[483] | 1 | define(["dojo", "../util/oo", "../defaults"], |
---|
| 2 | function(dojo, oo, defaults){ |
---|
| 3 | |
---|
| 4 | //dojox.drawing.manager.Mouse = |
---|
| 5 | return oo.declare( |
---|
| 6 | function(/* Object */options){ |
---|
| 7 | this.util = options.util; |
---|
| 8 | this.keys = options.keys; |
---|
| 9 | this.id = options.id || this.util.uid("mouse"); |
---|
| 10 | this.currentNodeId = ""; |
---|
| 11 | this.registered = {}; |
---|
| 12 | }, |
---|
| 13 | |
---|
| 14 | { |
---|
| 15 | // summary: |
---|
| 16 | // Master object (instance) that tracks mouse |
---|
| 17 | // events. A new instance is created for each |
---|
| 18 | // Drawing object. |
---|
| 19 | // description: |
---|
| 20 | // You could connect to any method or event in this |
---|
| 21 | // class, but it is designed to have the object |
---|
| 22 | // 'registered'. All objects with the current event |
---|
| 23 | // will be called directly. |
---|
| 24 | // |
---|
| 25 | // Custom events are used often. In addition to |
---|
| 26 | // standard events onDown, onUp, onDrag, etc, if |
---|
| 27 | // a certain object is clicked upon (or dragged, etc), |
---|
| 28 | // that object's drawingType will create the custom event, |
---|
| 29 | // such as onAnchorDown, or onStencilDown. |
---|
| 30 | |
---|
| 31 | |
---|
| 32 | // doublClickSpeed: Number |
---|
| 33 | // Milliseconds between clicks to |
---|
| 34 | // register as for onDoubleClick |
---|
| 35 | doublClickSpeed:400, |
---|
| 36 | |
---|
| 37 | // private properties |
---|
| 38 | |
---|
| 39 | _lastx:0, |
---|
| 40 | _lasty:0, |
---|
| 41 | __reg:0, |
---|
| 42 | _downOnCanvas:false, |
---|
| 43 | |
---|
| 44 | /*===== |
---|
| 45 | CustomEventMethod: { |
---|
| 46 | // summary: |
---|
| 47 | // The custom event methods that an Object that has |
---|
| 48 | // registered with manager.Mouse can receive. |
---|
| 49 | // Can contain any or all of the following methods |
---|
| 50 | // and they will be called on mouse events. All events |
---|
| 51 | // will be sent a EventObject event object. |
---|
| 52 | // |
---|
| 53 | // NOTE: |
---|
| 54 | // Events happen anywhere in the document unless |
---|
| 55 | // otherwise noted. |
---|
| 56 | |
---|
| 57 | // onMove: Function |
---|
| 58 | // Fires on mousemove when mouse is up |
---|
| 59 | // onDown: Function |
---|
| 60 | // Fires on mousedown *on the canvas* |
---|
| 61 | // onDrag: Function |
---|
| 62 | // Fires on mousemove when mouse is down |
---|
| 63 | // onUp: Function |
---|
| 64 | // Fires on mouseup, anywhere in the document |
---|
| 65 | // onStencilDown: Function |
---|
| 66 | // Fired on mousedown on a Stencil |
---|
| 67 | // onStencilDrag: Function |
---|
| 68 | // Fired when mouse moves and mose is down on a Stencil |
---|
| 69 | // onStencilUp: Function |
---|
| 70 | // Fired on mouseup off of a Stencil |
---|
| 71 | // on[Custom]Up|Down|Move: Function |
---|
| 72 | // Custom events can bet set and fired by setting a |
---|
| 73 | // different drawingType on a Stencil, or by calling |
---|
| 74 | // setEventMode(customEventName) |
---|
| 75 | }, |
---|
| 76 | EventObject: function(){ |
---|
| 77 | // summary: |
---|
| 78 | // The custom event object that is sent to registered objects |
---|
| 79 | // and their respective methods. |
---|
| 80 | // |
---|
| 81 | // NOTE: Most event objects are the same with the exception |
---|
| 82 | // of the onDown events, which have fewer. |
---|
| 83 | |
---|
| 84 | // id: String |
---|
| 85 | // Id of the focused object (included in onDown) |
---|
| 86 | // pageX: Number |
---|
| 87 | // The X coordinate of the mouse from the left side of |
---|
| 88 | // the document. (included in onDown) |
---|
| 89 | // pageY: Number |
---|
| 90 | // The Y coordinate of the mouse from the top of |
---|
| 91 | // the document. (included in onDown) |
---|
| 92 | // x: Number |
---|
| 93 | // The X coordinate of the mouse from the left side |
---|
| 94 | // of the canvas (included in onDown) |
---|
| 95 | // y: Number |
---|
| 96 | // The Y coordinate of the mouse from the top |
---|
| 97 | // of the canvas (included in onDown) |
---|
| 98 | |
---|
| 99 | // last: Object |
---|
| 100 | // The x and y coordinates of the last mousemove |
---|
| 101 | // relative to the canvas (not included in onDown) |
---|
| 102 | // move: Object |
---|
| 103 | // The x and y amounts the mouse moved since the last event |
---|
| 104 | // (not included in onDown) |
---|
| 105 | // orgX: Number |
---|
| 106 | // The left side of the canvas from the side of the document (not included in onDown) |
---|
| 107 | // orgY: Number |
---|
| 108 | // The top of the canvas from the top of the document (not included in onDown) |
---|
| 109 | // scroll: Object |
---|
| 110 | // The 'top' and 'left' scroll amounts of the canvas. (not included in onDown) |
---|
| 111 | // start: Object |
---|
| 112 | // The x and y coordinates of the mousedown event (not included in onDown) |
---|
| 113 | // withinCanvas: Boolean |
---|
| 114 | // Whether the event happened within the Canvas or not (not included in onDown) |
---|
| 115 | }, |
---|
| 116 | =====*/ |
---|
| 117 | |
---|
| 118 | init: function(/* HTMLNode*/node){ |
---|
| 119 | // summary: |
---|
| 120 | // Internal. Initializes mouse. |
---|
| 121 | |
---|
| 122 | this.container = node; |
---|
| 123 | this.setCanvas(); |
---|
| 124 | var c; |
---|
| 125 | var _isDown = false; |
---|
| 126 | dojo.connect(this.container, "rightclick", this, function(evt){ |
---|
| 127 | console.warn("RIGHTCLICK") |
---|
| 128 | }); |
---|
| 129 | |
---|
| 130 | dojo.connect(document.body, "mousedown", this, function(evt){ |
---|
| 131 | //evt.preventDefault(); |
---|
| 132 | //dojo.stopEvent(evt); |
---|
| 133 | }); |
---|
| 134 | |
---|
| 135 | dojo.connect(this.container, "mousedown", this, function(evt){ |
---|
| 136 | this.down(evt); |
---|
| 137 | // Right click shouldn't trigger drag |
---|
| 138 | if(evt.button != dojo.mouseButtons.RIGHT){ |
---|
| 139 | _isDown = true; |
---|
| 140 | c = dojo.connect(document, "mousemove", this, "drag"); |
---|
| 141 | } |
---|
| 142 | }); |
---|
| 143 | dojo.connect(document, "mouseup", this, function(evt){ |
---|
| 144 | dojo.disconnect(c); |
---|
| 145 | _isDown = false; |
---|
| 146 | this.up(evt); |
---|
| 147 | }); |
---|
| 148 | dojo.connect(document, "mousemove", this, function(evt){ |
---|
| 149 | if(!_isDown){ |
---|
| 150 | this.move(evt); |
---|
| 151 | } |
---|
| 152 | }); |
---|
| 153 | dojo.connect(this.keys, "onEsc", this, function(evt){ |
---|
| 154 | this._dragged = false; |
---|
| 155 | }); |
---|
| 156 | }, |
---|
| 157 | |
---|
| 158 | setCanvas: function(){ |
---|
| 159 | // summary: |
---|
| 160 | // Internal. Sets canvas position |
---|
| 161 | var pos = dojo.position(this.container.parentNode); |
---|
| 162 | this.origin = dojo.clone(pos); |
---|
| 163 | }, |
---|
| 164 | |
---|
| 165 | scrollOffset: function(){ |
---|
| 166 | // summary: |
---|
| 167 | // Gets scroll offset of canvas |
---|
| 168 | return { |
---|
| 169 | top:this.container.parentNode.scrollTop, |
---|
| 170 | left:this.container.parentNode.scrollLeft |
---|
| 171 | }; // Object |
---|
| 172 | }, |
---|
| 173 | |
---|
| 174 | resize: function(width,height){ |
---|
| 175 | if(this.origin){ |
---|
| 176 | this.origin.w=width; |
---|
| 177 | this.origin.h=height; |
---|
| 178 | } |
---|
| 179 | }, |
---|
| 180 | |
---|
| 181 | register: function(/* CustomEventMethod*/scope){ |
---|
| 182 | // summary: |
---|
| 183 | // All objects (Stencils) should register here if they |
---|
| 184 | // use mouse events. When registering, the object will |
---|
| 185 | // be called if it has that method. |
---|
| 186 | // See: CustomEventMethod and EventObject |
---|
| 187 | // scope: |
---|
| 188 | // The object to be called |
---|
| 189 | // returns: handle |
---|
| 190 | // Keep the handle to be used for disconnection. |
---|
| 191 | |
---|
| 192 | var handle = scope.id || "reg_"+(this.__reg++); |
---|
| 193 | if(!this.registered[handle]){ this.registered[handle] = scope; } |
---|
| 194 | return handle; // String |
---|
| 195 | }, |
---|
| 196 | unregister: function(handle){ |
---|
| 197 | // summary: |
---|
| 198 | // Disconnects object. Mouse events are no longer |
---|
| 199 | // called for it. |
---|
| 200 | if(!this.registered[handle]){ return; } |
---|
| 201 | delete this.registered[handle]; |
---|
| 202 | }, |
---|
| 203 | |
---|
| 204 | _broadcastEvent:function(strEvt, obj){ |
---|
| 205 | // summary: |
---|
| 206 | // Fire events to all registered objects. |
---|
| 207 | |
---|
| 208 | //console.log("mouse.broadcast:", strEvt, obj) |
---|
| 209 | for(var nm in this.registered){ |
---|
| 210 | if(this.registered[nm][strEvt]) this.registered[nm][strEvt](obj); |
---|
| 211 | } |
---|
| 212 | }, |
---|
| 213 | |
---|
| 214 | onDown: function(obj){ |
---|
| 215 | // summary: |
---|
| 216 | // Create on[xx]Down event and send to broadcaster. |
---|
| 217 | // Could be connected to. |
---|
| 218 | |
---|
| 219 | //console.info("onDown:", this.eventName("down")) |
---|
| 220 | this._broadcastEvent(this.eventName("down"), obj); |
---|
| 221 | }, |
---|
| 222 | |
---|
| 223 | onDrag: function(obj){ |
---|
| 224 | // summary: |
---|
| 225 | // Create on[xx]Drag event and send to broadcaster. |
---|
| 226 | // Could be connected to. |
---|
| 227 | |
---|
| 228 | var nm = this.eventName("drag"); |
---|
| 229 | if(this._selected && nm == "onDrag"){ |
---|
| 230 | nm = "onStencilDrag" |
---|
| 231 | } |
---|
| 232 | this._broadcastEvent(nm, obj); |
---|
| 233 | }, |
---|
| 234 | |
---|
| 235 | onMove: function(obj){ |
---|
| 236 | // summary: |
---|
| 237 | // Create onMove event and send to broadcaster. |
---|
| 238 | // Could be connected to. |
---|
| 239 | // Note: onMove never uses a custom event |
---|
| 240 | // Note: onMove is currently not enabled in the app. |
---|
| 241 | |
---|
| 242 | this._broadcastEvent("onMove", obj); |
---|
| 243 | }, |
---|
| 244 | |
---|
| 245 | overName: function(obj,evt){ |
---|
| 246 | var nm = obj.id.split("."); |
---|
| 247 | evt = evt.charAt(0).toUpperCase() + evt.substring(1); |
---|
| 248 | if(nm[0] == "dojox" && (defaults.clickable || !defaults.clickMode)){ |
---|
| 249 | return "onStencil"+evt; |
---|
| 250 | }else{ |
---|
| 251 | return "on"+evt; |
---|
| 252 | } |
---|
| 253 | |
---|
| 254 | }, |
---|
| 255 | |
---|
| 256 | onOver: function(obj){ |
---|
| 257 | this._broadcastEvent(this.overName(obj,"over"), obj); |
---|
| 258 | }, |
---|
| 259 | |
---|
| 260 | onOut: function(obj){ |
---|
| 261 | this._broadcastEvent(this.overName(obj,"out"), obj); |
---|
| 262 | }, |
---|
| 263 | |
---|
| 264 | onUp: function(obj){ |
---|
| 265 | // summary: |
---|
| 266 | // Create on[xx]Up event and send to broadcaster. |
---|
| 267 | // Could be connected to. |
---|
| 268 | |
---|
| 269 | // blocking first click-off (deselect), largely for TextBlock |
---|
| 270 | // TODO: should have param to make this optional? |
---|
| 271 | var nm = this.eventName("up"); |
---|
| 272 | |
---|
| 273 | if(nm == "onStencilUp"){ |
---|
| 274 | this._selected = true; |
---|
| 275 | }else if(this._selected && nm == "onUp"){ ////////////////////////////////////////// |
---|
| 276 | nm = "onStencilUp"; |
---|
| 277 | this._selected = false; |
---|
| 278 | } |
---|
| 279 | |
---|
| 280 | console.info("Up Event:", this.id, nm, "id:", obj.id); |
---|
| 281 | this._broadcastEvent(nm, obj); |
---|
| 282 | |
---|
| 283 | // Silverlight double-click handled in Silverlight class |
---|
| 284 | if(dojox.gfx.renderer == "silverlight"){ return; } |
---|
| 285 | |
---|
| 286 | // Check Double Click |
---|
| 287 | // If a double click is detected, the onDoubleClick event fires, |
---|
| 288 | // but does not replace the normal event. They both fire. |
---|
| 289 | this._clickTime = new Date().getTime(); |
---|
| 290 | if(this._lastClickTime){ |
---|
| 291 | if(this._clickTime-this._lastClickTime<this.doublClickSpeed){ |
---|
| 292 | var dnm = this.eventName("doubleClick"); |
---|
| 293 | console.warn("DOUBLE CLICK", dnm, obj); |
---|
| 294 | this._broadcastEvent(dnm, obj); |
---|
| 295 | }else{ |
---|
| 296 | //console.log(" slow:", this._clickTime-this._lastClickTime) |
---|
| 297 | } |
---|
| 298 | } |
---|
| 299 | this._lastClickTime = this._clickTime; |
---|
| 300 | |
---|
| 301 | }, |
---|
| 302 | |
---|
| 303 | zoom: 1, |
---|
| 304 | setZoom: function(zoom){ |
---|
| 305 | // summary: |
---|
| 306 | // Internal. Sets the mouse zoom percentage to |
---|
| 307 | // that of the canvas |
---|
| 308 | this.zoom = 1/zoom; |
---|
| 309 | }, |
---|
| 310 | |
---|
| 311 | setEventMode: function(mode){ |
---|
| 312 | // summary: |
---|
| 313 | // Sets the mouse mode s that custom events can be called. |
---|
| 314 | // Also can 'disable' events by using a bogus mode: |
---|
| 315 | // | mouse.setEventMode("DISABLED") |
---|
| 316 | // (unless any object subscribes to this event, |
---|
| 317 | // it is effectively disabled) |
---|
| 318 | |
---|
| 319 | this.mode = mode ? "on" + mode.charAt(0).toUpperCase() + mode.substring(1) : ""; |
---|
| 320 | }, |
---|
| 321 | |
---|
| 322 | eventName: function(name){ |
---|
| 323 | // summary: |
---|
| 324 | // Internal. Determine the event name |
---|
| 325 | |
---|
| 326 | name = name.charAt(0).toUpperCase() + name.substring(1); |
---|
| 327 | if(this.mode){ |
---|
| 328 | if(this.mode == "onPathEdit"){ |
---|
| 329 | return "on"+name; |
---|
| 330 | } |
---|
| 331 | if(this.mode == "onUI"){ |
---|
| 332 | //return "on"+name; |
---|
| 333 | } |
---|
| 334 | return this.mode + name; |
---|
| 335 | }else{ |
---|
| 336 | //Allow a mode where stencils aren't clickable |
---|
| 337 | if(!defaults.clickable && defaults.clickMode){return "on"+name;} |
---|
| 338 | var dt = !this.drawingType || this.drawingType=="surface" || this.drawingType=="canvas" ? "" : this.drawingType; |
---|
| 339 | var t = !dt ? "" : dt.charAt(0).toUpperCase() + dt.substring(1); |
---|
| 340 | return "on"+t+name; |
---|
| 341 | } |
---|
| 342 | }, |
---|
| 343 | |
---|
| 344 | up: function(evt){ |
---|
| 345 | // summary: |
---|
| 346 | // Internal. Create onUp event |
---|
| 347 | |
---|
| 348 | this.onUp(this.create(evt)); |
---|
| 349 | }, |
---|
| 350 | |
---|
| 351 | down: function(evt){ |
---|
| 352 | // summary: |
---|
| 353 | // Internal. Create onDown event |
---|
| 354 | |
---|
| 355 | this._downOnCanvas = true; |
---|
| 356 | var sc = this.scrollOffset(); |
---|
| 357 | var dim = this._getXY(evt); |
---|
| 358 | this._lastpagex = dim.x; |
---|
| 359 | this._lastpagey = dim.y; |
---|
| 360 | var o = this.origin; |
---|
| 361 | var x = dim.x - o.x + sc.left; |
---|
| 362 | var y = dim.y - o.y + sc.top; |
---|
| 363 | |
---|
| 364 | var withinCanvas = x>=0 && y>=0 && x<=o.w && y<=o.h; |
---|
| 365 | x*= this.zoom; |
---|
| 366 | y*= this.zoom; |
---|
| 367 | |
---|
| 368 | o.startx = x; |
---|
| 369 | o.starty = y; |
---|
| 370 | this._lastx = x; |
---|
| 371 | this._lasty = y; |
---|
| 372 | |
---|
| 373 | this.drawingType = this.util.attr(evt, "drawingType") || ""; |
---|
| 374 | var id = this._getId(evt); |
---|
| 375 | //console.log("DOWN:", this.id, id, withinCanvas); |
---|
| 376 | //console.log("this.drawingType:", this.drawingType); |
---|
| 377 | |
---|
| 378 | if(evt.button == dojo.mouseButtons.RIGHT && this.id == "mse"){ |
---|
| 379 | //Allow right click events to bubble for context menus |
---|
| 380 | }else{ |
---|
| 381 | evt.preventDefault(); |
---|
| 382 | dojo.stopEvent(evt); |
---|
| 383 | } |
---|
| 384 | this.onDown({ |
---|
| 385 | mid:this.id, |
---|
| 386 | x:x, |
---|
| 387 | y:y, |
---|
| 388 | pageX:dim.x, |
---|
| 389 | pageY:dim.y, |
---|
| 390 | withinCanvas:withinCanvas, |
---|
| 391 | id:id |
---|
| 392 | }); |
---|
| 393 | |
---|
| 394 | }, |
---|
| 395 | over: function(obj){ |
---|
| 396 | // summary: |
---|
| 397 | // Internal. |
---|
| 398 | |
---|
| 399 | this.onOver(obj); |
---|
| 400 | }, |
---|
| 401 | out: function(obj){ |
---|
| 402 | // summary: |
---|
| 403 | // Internal. |
---|
| 404 | |
---|
| 405 | this.onOut(obj); |
---|
| 406 | }, |
---|
| 407 | move: function(evt){ |
---|
| 408 | // summary: |
---|
| 409 | // Internal. |
---|
| 410 | |
---|
| 411 | var obj = this.create(evt); |
---|
| 412 | if(this.id=="MUI"){ |
---|
| 413 | //console.log("obj.id:", obj.id, "was:", this.currentNodeId) |
---|
| 414 | } |
---|
| 415 | if(obj.id != this.currentNodeId){ |
---|
| 416 | // TODO: I wonder if an ID is good enough |
---|
| 417 | // that would avoid the mixin |
---|
| 418 | var outObj = {}; |
---|
| 419 | for(var nm in obj){ |
---|
| 420 | outObj[nm] = obj[nm]; |
---|
| 421 | } |
---|
| 422 | outObj.id = this.currentNodeId; |
---|
| 423 | this.currentNodeId && this.out(outObj); |
---|
| 424 | obj.id && this.over(obj); |
---|
| 425 | this.currentNodeId = obj.id; |
---|
| 426 | } |
---|
| 427 | this.onMove(obj); |
---|
| 428 | }, |
---|
| 429 | drag: function(evt){ |
---|
| 430 | // summary: |
---|
| 431 | // Internal. Create onDrag event |
---|
| 432 | this.onDrag(this.create(evt, true)); |
---|
| 433 | }, |
---|
| 434 | create: function(evt, squelchErrors){ |
---|
| 435 | // summary: |
---|
| 436 | // Internal. Create EventObject |
---|
| 437 | |
---|
| 438 | var sc = this.scrollOffset(); |
---|
| 439 | var dim = this._getXY(evt); |
---|
| 440 | |
---|
| 441 | var pagex = dim.x; |
---|
| 442 | var pagey = dim.y; |
---|
| 443 | |
---|
| 444 | var o = this.origin; |
---|
| 445 | var x = dim.x - o.x + sc.left; |
---|
| 446 | var y = dim.y - o.y + sc.top; |
---|
| 447 | |
---|
| 448 | var withinCanvas = x>=0 && y>=0 && x<=o.w && y<=o.h; |
---|
| 449 | x*= this.zoom; |
---|
| 450 | y*= this.zoom; |
---|
| 451 | |
---|
| 452 | var id = withinCanvas ? this._getId(evt, squelchErrors) : ""; |
---|
| 453 | var ret = { |
---|
| 454 | mid:this.id, |
---|
| 455 | x:x, |
---|
| 456 | y:y, |
---|
| 457 | pageX:dim.x, |
---|
| 458 | pageY:dim.y, |
---|
| 459 | page:{ |
---|
| 460 | x:dim.x, |
---|
| 461 | y:dim.y |
---|
| 462 | }, |
---|
| 463 | orgX:o.x, |
---|
| 464 | orgY:o.y, |
---|
| 465 | last:{ |
---|
| 466 | x: this._lastx, |
---|
| 467 | y: this._lasty |
---|
| 468 | }, |
---|
| 469 | start:{ |
---|
| 470 | x: this.origin.startx, //+ sc.left, |
---|
| 471 | y: this.origin.starty //+ sc.top |
---|
| 472 | }, |
---|
| 473 | move:{ |
---|
| 474 | x:pagex - this._lastpagex, |
---|
| 475 | y:pagey - this._lastpagey |
---|
| 476 | }, |
---|
| 477 | scroll:sc, |
---|
| 478 | id:id, |
---|
| 479 | withinCanvas:withinCanvas |
---|
| 480 | }; |
---|
| 481 | |
---|
| 482 | //console.warn("MSE LAST:", x-this._lastx, y-this._lasty) |
---|
| 483 | this._lastx = x; |
---|
| 484 | this._lasty = y; |
---|
| 485 | this._lastpagex = pagex; |
---|
| 486 | this._lastpagey = pagey; |
---|
| 487 | dojo.stopEvent(evt); |
---|
| 488 | return ret; //Object |
---|
| 489 | }, |
---|
| 490 | _getId: function(evt, squelchErrors){ |
---|
| 491 | // summary: |
---|
| 492 | // Internal. Gets ID of focused node. |
---|
| 493 | return this.util.attr(evt, "id", null, squelchErrors); // String |
---|
| 494 | }, |
---|
| 495 | _getXY: function(evt){ |
---|
| 496 | // summary: |
---|
| 497 | // Internal. Gets mouse coords to page. |
---|
| 498 | return {x:evt.pageX, y:evt.pageY}; // Object |
---|
| 499 | }, |
---|
| 500 | |
---|
| 501 | setCursor: function(cursor,/* HTMLNode*/node){ |
---|
| 502 | // summary: |
---|
| 503 | // Sets the cursor for a given node. If no |
---|
| 504 | // node is specified the containing node is used. |
---|
| 505 | if(!node){ |
---|
| 506 | dojo.style(this.container, "cursor", cursor); |
---|
| 507 | }else{ |
---|
| 508 | dojo.style(node, "cursor", cursor); |
---|
| 509 | } |
---|
| 510 | } |
---|
| 511 | } |
---|
| 512 | ); |
---|
| 513 | }); |
---|