Merge remote branch 'origin/master'

This commit is contained in:
Jonathan Puckey 2011-05-08 16:47:32 +01:00
commit b0e91c0173
10 changed files with 159 additions and 124 deletions

View file

@ -287,7 +287,7 @@
var layer = document.activeLayer;
function onKeyDown(event) {
if (event.keyCode == 'space')
if (event.key == 'space')
layer.selected = !layer.selected;
}
</script>

View file

@ -937,7 +937,7 @@ var Item = this.Item = Base.extend({
if (!func || !func._installed) {
var hash = {};
hash[handler] = function(event) {
// Always clear the drag set on mouse-up
// Always clear the drag set on mouseup
if (name === 'up')
sets.drag = {};
removeAll(sets[name]);

View file

@ -59,11 +59,7 @@ Base.inject({
var start = start || 0,
length = length || list.length - start;
var obj = list[start];
// As a convention, do not return objects that are owned, e.g.
// LinkedPoint or SegmentPoint, although they are instances of Point,
// since they override properties with beans. Convert these to pure
// Points instead, further down.
if (obj && !obj._owner && obj instanceof this
if (obj instanceof this
// If the class defines _readNull, return null when nothing
// was provided
|| this.prototype._readNull && obj == null && length <= 1)
@ -122,8 +118,28 @@ Base.inject({
});
},
camelize: function(str) {
return str.replace(/-(\w)/g, function(all, chr) {
return chr.toUpperCase();
});
},
/**
* Utility function for rendering numbers to strings at a precision of up
* to 5 fractional digits.
*/
formatNumber: function(num) {
return (Math.round(num * 100000) / 100000).toString();
},
/**
* Utility function for rendering objects to strings, in object literal
* notation.
*/
formatObject: function(obj) {
return '{ ' + Base.each(obj, function(value, key) {
this.push(key + ': ' + value);
}, []).join(', ') + ' }';
}
});

View file

@ -31,7 +31,7 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
this.events = {
mousedown: function(event) {
curPoint = viewToArtwork(event, that._document);
that.onHandleEvent('mouse-down', curPoint, event);
that.onHandleEvent('mousedown', curPoint, event);
if (that.onMouseDown)
that._document.redraw();
if (that.eventInterval != null) {
@ -54,9 +54,9 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
if (dragging && !onlyMove) {
curPoint = point || curPoint;
if (curPoint)
that.onHandleEvent('mouse-drag', curPoint, event);
that.onHandleEvent('mousedrag', curPoint, event);
} else if (!dragging || onlyMove) {
that.onHandleEvent('mouse-move', point, event);
that.onHandleEvent('mousemove', point, event);
}
if (that.onMouseMove || that.onMouseDrag)
that._document.redraw();
@ -67,7 +67,7 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
curPoint = null;
if (that.eventInterval != null)
clearInterval(this.timer);
that.onHandleEvent('mouse-up',
that.onHandleEvent('mouseup',
viewToArtwork(event, that._document), event);
if (that.onMouseUp)
that._document.redraw();

View file

@ -39,25 +39,13 @@ var ToolEvent = this.ToolEvent = Base.extend({
this.type = type;
this.event = event;
},
toString: function() {
return '{ type: ' + this.type
+ ', point: ' + this.point
+ ', count: ' + this.count
+ ', modifiers: ' + this.modifiers
+ ' }';
},
/**
* Convenience method to allow local overrides of point values.
* See application below.
*/
choosePoint: function(point, toolPoint) {
if (point)
return point;
if (toolPoint)
return new Point(toolPoint);
return null;
_choosePoint: function(point, toolPoint) {
return point ? point : toolPoint ? toolPoint.clone() : null;
},
/**
@ -78,7 +66,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
* </code>
*/
getPoint: function() {
return this.choosePoint(this._point, this.tool.point);
return this._choosePoint(this._point, this.tool.point);
},
setPoint: function(point) {
@ -90,7 +78,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
* event was fired.
*/
getLastPoint: function() {
return this.choosePoint(this._lastPoint, this.tool.lastPoint);
return this._choosePoint(this._lastPoint, this.tool.lastPoint);
},
setLastPoint: function(lastPoint) {
@ -102,7 +90,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
* was last clicked.
*/
getDownPoint: function() {
return this.choosePoint(this._downPoint, this.tool.downPoint);
return this._choosePoint(this._downPoint, this.tool.downPoint);
},
setDownPoint: function(downPoint) {
@ -117,7 +105,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
*/
getMiddlePoint: function() {
// For explanations, see getDelta()
if (this._middlePoint == null && this.tool.lastPoint != null) {
if (!this._middlePoint && this.tool.lastPoint) {
// (point + lastPoint) / 2
return this.tool.point.add(this.tool.lastPoint).divide(2);
}
@ -130,8 +118,8 @@ var ToolEvent = this.ToolEvent = Base.extend({
/**
* The difference between the current position and the last position of the
* mouse when the event was fired. In case of the mouse-up event, the
* difference to the mouse-down position is returned.
* mouse when the event was fired. In case of the mouseup event, the
* difference to the mousedown position is returned.
*/
getDelta: function() {
// Do not put the calculated delta into delta, since this only reserved
@ -139,10 +127,9 @@ var ToolEvent = this.ToolEvent = Base.extend({
// Instead, keep calculating the delta each time, so the result can be
// directly modified by the script without changing the internal values.
// We could cache this and use clone, but this is almost as fast...
if (this._delta == null && this.tool.lastPoint != null) {
return this.tool.point.subtract(this.tool.lastPoint);
}
return this._delta;
return this._delta && this.tool.lastPoint
? this.tool.point.subtract(this.tool.lastPoint)
: this._delta;
},
setDelta: function(delta) {
@ -168,32 +155,21 @@ var ToolEvent = this.ToolEvent = Base.extend({
* </code>
*/
getCount: function() {
switch (this.type) {
case 'mouse-down':
case 'mouse-up':
// Return downCount for both mouse down and up, since
// the count is the same.
return this.tool.downCount;
default:
return this.tool.count;
}
// Return downCount for both mouse down and up, since
// the count is the same.
return /^mouse(down|up)$/.test(this.type)
? this.tool.downCount
: this.tool.count;
},
setCount: function(count) {
switch (this.type) {
case 'mouse-down':
case 'mouse-up':
this.tool.downCount = count;
break;
default:
this.tool.count = count;
break;
}
this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count']
= count;
},
getModifiers: function() {
return Key.modifiers;
}
},
// TODO: implement hitTest first
// getItem: function() {
@ -215,4 +191,12 @@ var ToolEvent = this.ToolEvent = Base.extend({
// setItem: function(Item item) {
// this.item = item;
// }
toString: function() {
return '{ type: ' + this.type
+ ', point: ' + this.getPoint()
+ ', count: ' + this.getCount()
+ ', modifiers: ' + this.getModifiers()
+ ' }';
}
});

View file

@ -35,8 +35,8 @@ var ToolHandler = this.ToolHandler = Base.extend({
*
* Sample code:
* <code>
* // Fire the onMouseDrag event after the user has dragged
* // more then 5 points from the last onMouseDrag event:
* // Fire the onMouseDrag event after the user has dragged more then 5
* // points from the last onMouseDrag event:
* tool.minDistance = 5;
* </code>
*/
@ -98,42 +98,38 @@ var ToolHandler = this.ToolHandler = Base.extend({
this.lastPoint = this.point;
this.point = pt;
switch (type) {
case 'mouse-down':
case 'mousedown':
this.lastPoint = this.downPoint;
this.downPoint = this.point;
this.downCount++;
break;
case 'mouse-up':
// Mouse up events return the down point for last point,
// so delta is spanning over the whole drag.
case 'mouseup':
// Mouse up events return the down point for last point, so delta is
// spanning over the whole drag.
this.lastPoint = this.downPoint;
break;
}
if (start) {
this.count = 0;
} else {
this.count++;
}
this.count = start ? 0 : this.count + 1;
return true;
},
onHandleEvent: function(type, pt, event) {
switch (type) {
case 'mouse-down':
case 'mousedown':
this.updateEvent(type, pt, null, null, true, false, false);
if (this.onMouseDown)
this.onMouseDown(new ToolEvent(this, type, event));
break;
case 'mouse-drag':
// In order for idleInterval drag events to work, we need to
// not check the first call for a change of position.
// Subsequent calls required by min/maxDistance functionality
// will require it, otherwise this might loop endlessly.
case 'mousedrag':
// In order for idleInterval drag events to work, we need to not
// check the first call for a change of position. Subsequent calls
// required by min/maxDistance functionality will require it,
// otherwise this might loop endlessly.
var needsChange = false,
// If the mouse is moving faster than maxDistance, do not
// produce events for what is left after the first event is
// generated in case it is shorter than maxDistance, as this
// would produce weird results. matchMaxDistance controls this.
// If the mouse is moving faster than maxDistance, do not produce
// events for what is left after the first event is generated in
// case it is shorter than maxDistance, as this would produce weird
// results. matchMaxDistance controls this.
matchMaxDistance = false;
while (this.updateEvent(type, pt, this.minDistance,
this.maxDistance, false, needsChange, matchMaxDistance)) {
@ -143,11 +139,11 @@ var ToolHandler = this.ToolHandler = Base.extend({
matchMaxDistance = true;
}
break;
case 'mouse-up':
// If the last mouse drag happened in a different place, call
// mouse drag first, then mouse up.
case 'mouseup':
// If the last mouse drag happened in a different place, call mouse
// drag first, then mouse up.
if ((this.point.x != pt.x || this.point.y != pt.y)
&& this.updateEvent('mouse-drag', pt, this.minDistance,
&& this.updateEvent('mousedrag', pt, this.minDistance,
this.maxDistance, false, false, false)) {
if (this.onMouseDrag)
this.onMouseDrag(new ToolEvent(this, type, event));
@ -156,11 +152,11 @@ var ToolHandler = this.ToolHandler = Base.extend({
false, false);
if (this.onMouseUp)
this.onMouseUp(new ToolEvent(this, type, event));
// Start with new values for 'mouse-move'
// Start with new values for 'mousemove'
this.updateEvent(type, pt, null, null, true, false, false);
this.firstMove = true;
break;
case 'mouse-move':
case 'mousemove':
while (this.updateEvent(type, pt, this.minDistance,
this.maxDistance, this.firstMove, true, false)) {
if (this.onMouseMove)

View file

@ -15,6 +15,8 @@
*/
var Event = this.Event = Base.extend({
beans: true,
initialize: function(event) {
this.event = event;
},

View file

@ -16,18 +16,21 @@
var Key = this.Key = new function() {
// TODO: make sure the keys are called the same as in Scriptographer
// Missing: tab, cancel, clear, pause, page-down, page-up, end, home, comma,
// minus, period, slash, etc etc etc.
// Missing: tab, cancel, clear, page-down, page-up, comma, minus, period,
// slash, etc etc etc.
var keys = {
8: 'backspace',
13: 'enter',
16: 'shift',
17: 'control',
19: 'option', // was alt
20: 'capsLock',
18: 'option',
19: 'pause',
20: 'caps-lock',
27: 'escape',
32: 'space',
35: 'end',
36: 'home',
37: 'left',
38: 'up',
39: 'right',
@ -41,57 +44,84 @@ var Key = this.Key = new function() {
control: false,
option: false,
command: false,
capsLock: false
capsLock: false,
toString: function() {
return Base.formatObject(this);
}
},
keyCodes = {},
downCode,
downTimer;
// Since only keypress gets proper keyCodes that are actually representing
// characters, we need to perform a little trickery here to use these codes
// in onKeyDown/Up: keydown is used to store the downCode and handle
// modifiers and special keys such as arrows, space, etc, keypress fires the
// actual onKeyDown event and maps the keydown keyCode to the keypress
// charCode so keyup can do the right thing too.
charCodeMap = {}, // keyCode -> charCode mappings for pressed keys
keyMap = {}, // Map for currently pressed keys
downCode; // The last keyCode from keydown
function handleKey(down, code, event) {
var character = String.fromCharCode(code),
keyCode = keys[code] || character.toLowerCase(),
function handleKey(down, keyCode, charCode, event) {
var character = String.fromCharCode(charCode),
key = keys[keyCode] || character.toLowerCase(),
handler = down ? 'onKeyDown' : 'onKeyUp';
console.log(handler, keyCode, character);
if (modifiers[keyCode] !== undefined) {
modifiers[keyCode] = down;
} else if (paper.tool && paper.tool[handler]) {
keyMap[key] = down;
if (paper.tool && paper.tool[handler]) {
// Call the onKeyDown or onKeyUp handler if present
// When the handler function returns false, prevent the
// default behaviour of the key event:
// PORT: Add to Sg
var keyEvent = new KeyEvent(down, keyCode, character, event);
var keyEvent = new KeyEvent(down, key, character, event);
if (paper.tool[handler](keyEvent) === false) {
keyEvent.preventDefault();
}
}
}
// Since only keypress gest proper keyCodes that are actually representing
// characters, we need to add a little timeout to keydown events to see if
// they are follow immediately by a keypress, and if so, map the keyCode
// from the keydown to the one from keypress, so keyup still knows what
// code has now been released.
DomEvent.add(document, {
keydown: function(event) {
var code = downCode = event.which || event.keyCode;
downTimer = setTimeout(function() {
keyCodes[code] = code;
handleKey(true, code, event);
}, 1);
var code = event.which || event.keyCode;
// If the keyCode is in keys, it needs to be handled by keydown and
// not in keypress after (arrows for example wont be triggering
// a keypress, but space would).
var key = keys[code], name;
if (key) {
// Do not fire handleKey for modifiers, but for other keys such
// ass arrows, delete, backspace, etc.
if (modifiers[name = Base.camelize(key)] !== undefined) {
modifiers[name] = true;
} else {
// No char code for special keys, but mark as pressed
charCodeMap[code] = 0;
handleKey(true, code, null, event);
}
// Do not set downCode as we handled it already. Space would
// be handled twice otherwise, once here, once in keypress.
} else {
downCode = code;
}
},
keypress: function(event) {
clearTimeout(downTimer);
var code = event.which || event.keyCode;
keyCodes[downCode] = code;
handleKey(true, code, event);
if (downCode != null) {
var code = event.which || event.keyCode;
// Link the downCode from keydown with the code form keypress, so
// keyup can retrieve that code again.
charCodeMap[downCode] = code;
handleKey(true, downCode, code, event);
downCode = null;
}
},
keyup: function(event) {
var code = event.which || event.keyCode;
handleKey(false, keyCodes[code], event);
delete keyCodes[code];
var code = event.which || event.keyCode,
key = keys[code], name;
if (key && modifiers[name = Base.camelize(key)] !== undefined) {
modifiers[name] = false
} else if (charCodeMap[code] != null) {
handleKey(false, code, charCodeMap[code], event);
delete charCodeMap[code];
}
}
});
@ -99,7 +129,7 @@ var Key = this.Key = new function() {
modifiers: modifiers,
isDown: function(key) {
return !!activeKeys[key];
return !!keyMap[key];
}
};
};

View file

@ -16,11 +16,19 @@
var KeyEvent = this.KeyEvent = Event.extend(new function() {
return {
initialize: function(down, keyCode, character, event) {
initialize: function(down, key, character, event) {
this.base(event);
this.type = down ? 'key-down' : 'key-up';
this.keyCode = keyCode;
this.type = down ? 'keydown' : 'keyup';
this.key = key;
this.character = character;
},
toString: function() {
return '{ type: ' + this.type
+ ', key: ' + this.key
+ ', character: ' + this.character
+ ', modifiers: ' + this.getModifiers()
+ ' }';
}
};
});

View file

@ -134,14 +134,13 @@ var PaperScript = this.PaperScript = new function() {
var doc = paper.document,
tool = paper.tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)
&& new Tool(null, doc),
onEditOptions, onOptions, onSelect, onDeselect, onReselect,
onMouseDown, onMouseUp, onMouseDrag, onMouseMove, onKeyDown,
onKeyUp,
onEditOptions, onSelect, onDeselect, onReselect, onMouseDown,
onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onKeyUp,
res = eval(compile(code));
if (tool) {
Base.each(['onEditOptions', 'onOptions', 'onSelect',
'onDeselect', 'onReselect', 'onMouseDown', 'onMouseUp',
'onMouseDrag', 'onMouseMove', 'onKeyDown', 'onKeyUp'],
Base.each(['onEditOptions', 'onSelect', 'onDeselect',
'onReselect', 'onMouseDown', 'onMouseUp', 'onMouseDrag',
'onMouseMove', 'onKeyDown', 'onKeyUp'],
function(key) {
tool[key] = eval(key);
}