520 lines
13 KiB
JavaScript
520 lines
13 KiB
JavaScript
//>>built
|
|
// wrapped by build app
|
|
define("dojox/drawing/manager/Mouse", ["dijit","dojo","dojox"], function(dijit,dojo,dojox){
|
|
dojo.provide("dojox.drawing.manager.Mouse");
|
|
|
|
dojox.drawing.manager.Mouse = dojox.drawing.util.oo.declare(
|
|
// summary:
|
|
// Master object (instance) that tracks mouse
|
|
// events. A new instance is created for each
|
|
// Drawing object.
|
|
// description:
|
|
// You could connect to any method or event in this
|
|
// class, but it is designed to have the object
|
|
// 'registered'. All objects with the current event
|
|
// will be called directly.
|
|
//
|
|
// Custom events are used often. In addition to
|
|
// standard events onDown, onUp, onDrag, etc, if
|
|
// a certain object is clicked upon (or dragged, etc),
|
|
// that object's drawingType will create the custom event,
|
|
// such as onAnchorDown, or onStencilDown.
|
|
//
|
|
function(/* Object */options){
|
|
this.util = options.util;
|
|
this.keys = options.keys;
|
|
this.id = options.id || this.util.uid("mouse");
|
|
this.currentNodeId = "";
|
|
this.registered = {};
|
|
},
|
|
|
|
{
|
|
// doublClickSpeed: Number
|
|
// Milliseconds between clicks to
|
|
// register as for onDoubleClick
|
|
doublClickSpeed:400,
|
|
|
|
// private properties
|
|
|
|
_lastx:0,
|
|
_lasty:0,
|
|
__reg:0,
|
|
_downOnCanvas:false,
|
|
|
|
/*=====
|
|
CustomEventMethod: function(){
|
|
// summary:
|
|
// The custom event method that an Object that has
|
|
// registered with manager.Mouse can receive.
|
|
// Can contain any or all of the following methods
|
|
// and they will be called as mouse events. All events
|
|
// will be sent a EventObject event object.
|
|
// NOTE:
|
|
// Events happen anywhere in the document unless
|
|
// otherwise noted.
|
|
//
|
|
// onMove
|
|
// Fires on mousemove when mouse is up
|
|
// onDown
|
|
// Fires on mousedown *on the canvas*
|
|
// onDrag
|
|
// Fires on mousemove when mouse is down
|
|
// onUp
|
|
// Fires on mouseup, anywhere in the document
|
|
// onStencilDown
|
|
// Fired on mousedown on a Stencil
|
|
// onStencilDrag
|
|
// Fired when mouse moves and mose is down on a Stencil
|
|
// onStencilUp
|
|
// Fired on mouseup off of a Stencil
|
|
// on[Custom]Up|Down|Move
|
|
// Custom events can bet set and fired by setting a
|
|
// different drawingType on a Stencil, or by calling
|
|
// setEventMode(customEventName)
|
|
},
|
|
EventObject: function(){
|
|
// summary:
|
|
// The custom event object that is sent to registered objects
|
|
// and their respective methods.
|
|
// NOTE: Most event objects are the same with the exception
|
|
// of the onDown events, which have fewer.
|
|
//
|
|
// All event properties included onDown:
|
|
//
|
|
// id: String
|
|
// Id of the focused object
|
|
// pageX: Number
|
|
// The X coordinate of the mouse from the left side of
|
|
// the document.
|
|
// pageY: Number
|
|
// The Y coordinate of the mouse from the top of
|
|
// the document.
|
|
// x: Number
|
|
// The X coordinate of the mouse from the left side
|
|
// of the canvas
|
|
// y: Number
|
|
// The Y coordinate of the mouse from the top
|
|
// of the canvas
|
|
//
|
|
// These event properties are *not* in onDown:
|
|
//
|
|
// last: Object
|
|
// The x and y coordinates of the last mousemove
|
|
// relative to the canvas
|
|
// move: Object
|
|
// The x and y amounts the mouse moved since the last event
|
|
// orgX: Number
|
|
// The left side of the canvas from the side of the document
|
|
// orgY: Number
|
|
// The top of the canvas from the top of the document
|
|
// scroll: Object
|
|
// The 'top' and 'left' scroll amounts of the canvas.
|
|
// start: Object
|
|
// The x and y coordinates of the mousedown event
|
|
// withinCanvas: Boolean
|
|
// Whether the event happened within the Canvas or not
|
|
|
|
},
|
|
=====*/
|
|
|
|
init: function(/* HTMLNode*/node){
|
|
// summary:
|
|
// Internal. Initializes mouse.
|
|
//
|
|
this.container = node;
|
|
this.setCanvas();
|
|
var c;
|
|
var _isDown = false;
|
|
dojo.connect(this.container, "rightclick", this, function(evt){
|
|
console.warn("RIGHTCLICK")
|
|
});
|
|
|
|
dojo.connect(document.body, "mousedown", this, function(evt){
|
|
//evt.preventDefault();
|
|
//dojo.stopEvent(evt);
|
|
});
|
|
|
|
dojo.connect(this.container, "mousedown", this, function(evt){
|
|
this.down(evt);
|
|
// Right click shouldn't trigger drag
|
|
if(evt.button != dojo.mouseButtons.RIGHT){
|
|
_isDown = true;
|
|
c = dojo.connect(document, "mousemove", this, "drag");
|
|
}
|
|
});
|
|
dojo.connect(document, "mouseup", this, function(evt){
|
|
dojo.disconnect(c);
|
|
_isDown = false;
|
|
this.up(evt);
|
|
});
|
|
dojo.connect(document, "mousemove", this, function(evt){
|
|
if(!_isDown){
|
|
this.move(evt);
|
|
}
|
|
});
|
|
dojo.connect(this.keys, "onEsc", this, function(evt){
|
|
this._dragged = false;
|
|
});
|
|
},
|
|
|
|
setCanvas: function(){
|
|
// summary:
|
|
// Internal. Sets canvas position
|
|
var pos = dojo.coords(this.container.parentNode);
|
|
this.origin = dojo.clone(pos);
|
|
},
|
|
|
|
scrollOffset: function(){
|
|
// summary:
|
|
// Gets scroll offset of canvas
|
|
return {
|
|
top:this.container.parentNode.scrollTop,
|
|
left:this.container.parentNode.scrollLeft
|
|
}; // Object
|
|
},
|
|
|
|
resize: function(width,height){
|
|
if(this.origin){
|
|
this.origin.w=width;
|
|
this.origin.h=height;
|
|
}
|
|
},
|
|
|
|
register: function(/* Object*/scope){
|
|
// summary:
|
|
// All objects (Stencils) should register here if they
|
|
// use mouse events. When registering, the object will
|
|
// be called if it has that method.
|
|
// argument:
|
|
// The object to be called
|
|
// Returns: handle
|
|
// Keep the handle to be used for disconnection.
|
|
// See: CustomEventMethod and EventObject
|
|
//
|
|
var handle = scope.id || "reg_"+(this.__reg++);
|
|
if(!this.registered[handle]){ this.registered[handle] = scope; }
|
|
return handle; // String
|
|
},
|
|
unregister: function(handle){
|
|
// summary:
|
|
// Disconnects object. Mouse events are no longer
|
|
// called for it.
|
|
if(!this.registered[handle]){ return; }
|
|
delete this.registered[handle];
|
|
},
|
|
|
|
_broadcastEvent:function(strEvt, obj){
|
|
// summary:
|
|
// Fire events to all registered objects.
|
|
//
|
|
//console.log("mouse.broadcast:", strEvt, obj)
|
|
for(var nm in this.registered){
|
|
if(this.registered[nm][strEvt]) this.registered[nm][strEvt](obj);
|
|
}
|
|
},
|
|
|
|
onDown: function(obj){
|
|
// summary:
|
|
// Create on[xx]Down event and send to broadcaster.
|
|
// Could be connected to.
|
|
//console.info("onDown:", this.eventName("down"))
|
|
this._broadcastEvent(this.eventName("down"), obj);
|
|
},
|
|
|
|
onDrag: function(obj){
|
|
// summary:
|
|
// Create on[xx]Drag event and send to broadcaster.
|
|
// Could be connected to.
|
|
//
|
|
var nm = this.eventName("drag");
|
|
if(this._selected && nm == "onDrag"){
|
|
nm = "onStencilDrag"
|
|
}
|
|
this._broadcastEvent(nm, obj);
|
|
},
|
|
|
|
onMove: function(obj){
|
|
// summary:
|
|
// Create onMove event and send to broadcaster.
|
|
// Could be connected to.
|
|
// Note: onMove never uses a custom event
|
|
// Note: onMove is currently not enabled in the app.
|
|
//
|
|
this._broadcastEvent("onMove", obj);
|
|
},
|
|
|
|
overName: function(obj,evt){
|
|
var nm = obj.id.split(".");
|
|
evt = evt.charAt(0).toUpperCase() + evt.substring(1);
|
|
if(nm[0] == "dojox" && (dojox.drawing.defaults.clickable || !dojox.drawing.defaults.clickMode)){
|
|
return "onStencil"+evt;
|
|
}else{
|
|
return "on"+evt;
|
|
}
|
|
|
|
},
|
|
|
|
onOver: function(obj){
|
|
// summary:
|
|
//
|
|
this._broadcastEvent(this.overName(obj,"over"), obj);
|
|
},
|
|
|
|
onOut: function(obj){
|
|
// summary:
|
|
//
|
|
this._broadcastEvent(this.overName(obj,"out"), obj);
|
|
},
|
|
|
|
onUp: function(obj){
|
|
// summary:
|
|
// Create on[xx]Up event and send to broadcaster.
|
|
// Could be connected to.
|
|
//
|
|
// blocking first click-off (deselect), largely for TextBlock
|
|
// TODO: should have param to make this optional?
|
|
var nm = this.eventName("up");
|
|
|
|
if(nm == "onStencilUp"){
|
|
this._selected = true;
|
|
}else if(this._selected && nm == "onUp"){ //////////////////////////////////////////
|
|
nm = "onStencilUp";
|
|
this._selected = false;
|
|
}
|
|
|
|
console.info("Up Event:", this.id, nm, "id:", obj.id);
|
|
this._broadcastEvent(nm, obj);
|
|
|
|
// Silverlight double-click handled in Silverlight class
|
|
if(dojox.gfx.renderer == "silverlight"){ return; }
|
|
|
|
// Check Double Click
|
|
// If a double click is detected, the onDoubleClick event fires,
|
|
// but does not replace the normal event. They both fire.
|
|
this._clickTime = new Date().getTime();
|
|
if(this._lastClickTime){
|
|
if(this._clickTime-this._lastClickTime<this.doublClickSpeed){
|
|
var dnm = this.eventName("doubleClick");
|
|
console.warn("DOUBLE CLICK", dnm, obj);
|
|
this._broadcastEvent(dnm, obj);
|
|
}else{
|
|
//console.log(" slow:", this._clickTime-this._lastClickTime)
|
|
}
|
|
}
|
|
this._lastClickTime = this._clickTime;
|
|
|
|
},
|
|
|
|
zoom: 1,
|
|
setZoom: function(zoom){
|
|
// summary:
|
|
// Internal. Sets the mouse zoom percentage to
|
|
// that of the canvas
|
|
this.zoom = 1/zoom;
|
|
},
|
|
|
|
setEventMode: function(mode){
|
|
// summary:
|
|
// Sets the mouse mode s that custom events can be called.
|
|
// Also can 'disable' events by using a bogus mode:
|
|
// | mouse.setEventMode("DISABLED")
|
|
// (unless any object subscribes to this event,
|
|
// it is effectively disabled)
|
|
//
|
|
this.mode = mode ? "on" + mode.charAt(0).toUpperCase() + mode.substring(1) : "";
|
|
},
|
|
|
|
eventName: function(name){
|
|
// summary:
|
|
// Internal. Determine the event name
|
|
//
|
|
name = name.charAt(0).toUpperCase() + name.substring(1);
|
|
if(this.mode){
|
|
if(this.mode == "onPathEdit"){
|
|
return "on"+name;
|
|
}
|
|
if(this.mode == "onUI"){
|
|
//return "on"+name;
|
|
}
|
|
return this.mode + name;
|
|
}else{
|
|
//Allow a mode where stencils aren't clickable
|
|
if(!dojox.drawing.defaults.clickable && dojox.drawing.defaults.clickMode){return "on"+name;}
|
|
var dt = !this.drawingType || this.drawingType=="surface" || this.drawingType=="canvas" ? "" : this.drawingType;
|
|
var t = !dt ? "" : dt.charAt(0).toUpperCase() + dt.substring(1);
|
|
return "on"+t+name;
|
|
}
|
|
},
|
|
|
|
up: function(evt){
|
|
// summary:
|
|
// Internal. Create onUp event
|
|
//
|
|
this.onUp(this.create(evt));
|
|
},
|
|
|
|
down: function(evt){
|
|
// summary:
|
|
// Internal. Create onDown event
|
|
//
|
|
this._downOnCanvas = true;
|
|
var sc = this.scrollOffset();
|
|
var dim = this._getXY(evt);
|
|
this._lastpagex = dim.x;
|
|
this._lastpagey = dim.y;
|
|
var o = this.origin;
|
|
var x = dim.x - o.x + sc.left;
|
|
var y = dim.y - o.y + sc.top;
|
|
|
|
var withinCanvas = x>=0 && y>=0 && x<=o.w && y<=o.h;
|
|
x*= this.zoom;
|
|
y*= this.zoom;
|
|
|
|
o.startx = x;
|
|
o.starty = y;
|
|
this._lastx = x;
|
|
this._lasty = y;
|
|
|
|
this.drawingType = this.util.attr(evt, "drawingType") || "";
|
|
var id = this._getId(evt);
|
|
//console.log("DOWN:", this.id, id, withinCanvas);
|
|
//console.log("this.drawingType:", this.drawingType);
|
|
|
|
if(evt.button == dojo.mouseButtons.RIGHT && this.id == "mse"){
|
|
//Allow right click events to bubble for context menus
|
|
}else{
|
|
evt.preventDefault();
|
|
dojo.stopEvent(evt);
|
|
}
|
|
this.onDown({
|
|
mid:this.id,
|
|
x:x,
|
|
y:y,
|
|
pageX:dim.x,
|
|
pageY:dim.y,
|
|
withinCanvas:withinCanvas,
|
|
id:id
|
|
});
|
|
|
|
},
|
|
over: function(obj){
|
|
// summary:
|
|
// Internal.
|
|
//
|
|
this.onOver(obj);
|
|
},
|
|
out: function(obj){
|
|
// summary:
|
|
// Internal.
|
|
//
|
|
this.onOut(obj);
|
|
},
|
|
move: function(evt){
|
|
// summary:
|
|
// Internal.
|
|
//
|
|
var obj = this.create(evt);
|
|
if(this.id=="MUI"){
|
|
//console.log("obj.id:", obj.id, "was:", this.currentNodeId)
|
|
}
|
|
if(obj.id != this.currentNodeId){
|
|
// TODO: I wonder if an ID is good enough
|
|
// that would avoid the mixin
|
|
var outObj = {};
|
|
for(var nm in obj){
|
|
outObj[nm] = obj[nm];
|
|
}
|
|
outObj.id = this.currentNodeId;
|
|
this.currentNodeId && this.out(outObj);
|
|
obj.id && this.over(obj);
|
|
this.currentNodeId = obj.id;
|
|
}
|
|
this.onMove(obj);
|
|
},
|
|
drag: function(evt){
|
|
// summary:
|
|
// Internal. Create onDrag event
|
|
this.onDrag(this.create(evt, true));
|
|
},
|
|
create: function(evt, squelchErrors){
|
|
// summary:
|
|
// Internal. Create EventObject
|
|
//
|
|
var sc = this.scrollOffset();
|
|
var dim = this._getXY(evt);
|
|
|
|
var pagex = dim.x;
|
|
var pagey = dim.y;
|
|
|
|
var o = this.origin;
|
|
var x = dim.x - o.x + sc.left;
|
|
var y = dim.y - o.y + sc.top;
|
|
|
|
var withinCanvas = x>=0 && y>=0 && x<=o.w && y<=o.h;
|
|
x*= this.zoom;
|
|
y*= this.zoom;
|
|
|
|
var id = withinCanvas ? this._getId(evt, squelchErrors) : "";
|
|
var ret = {
|
|
mid:this.id,
|
|
x:x,
|
|
y:y,
|
|
pageX:dim.x,
|
|
pageY:dim.y,
|
|
page:{
|
|
x:dim.x,
|
|
y:dim.y
|
|
},
|
|
orgX:o.x,
|
|
orgY:o.y,
|
|
last:{
|
|
x: this._lastx,
|
|
y: this._lasty
|
|
},
|
|
start:{
|
|
x: this.origin.startx, //+ sc.left,
|
|
y: this.origin.starty //+ sc.top
|
|
},
|
|
move:{
|
|
x:pagex - this._lastpagex,
|
|
y:pagey - this._lastpagey
|
|
},
|
|
scroll:sc,
|
|
id:id,
|
|
withinCanvas:withinCanvas
|
|
};
|
|
|
|
//console.warn("MSE LAST:", x-this._lastx, y-this._lasty)
|
|
this._lastx = x;
|
|
this._lasty = y;
|
|
this._lastpagex = pagex;
|
|
this._lastpagey = pagey;
|
|
dojo.stopEvent(evt);
|
|
return ret; //Object
|
|
},
|
|
_getId: function(evt, squelchErrors){
|
|
// summary:
|
|
// Internal. Gets ID of focused node.
|
|
return this.util.attr(evt, "id", null, squelchErrors); // String
|
|
},
|
|
_getXY: function(evt){
|
|
// summary:
|
|
// Internal. Gets mouse coords to page.
|
|
return {x:evt.pageX, y:evt.pageY}; // Object
|
|
},
|
|
|
|
setCursor: function(cursor,/* HTMLNode*/node){
|
|
// summary:
|
|
// Sets the cursor for a given node. If no
|
|
// node is specified the containing node is used.
|
|
if(!node){
|
|
dojo.style(this.container, "cursor", cursor);
|
|
}else{
|
|
dojo.style(node, "cursor", cursor);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
});
|