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; var layer = document.activeLayer;
function onKeyDown(event) { function onKeyDown(event) {
if (event.keyCode == 'space') if (event.key == 'space')
layer.selected = !layer.selected; layer.selected = !layer.selected;
} }
</script> </script>

View file

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

View file

@ -59,11 +59,7 @@ Base.inject({
var start = start || 0, var start = start || 0,
length = length || list.length - start; length = length || list.length - start;
var obj = list[start]; var obj = list[start];
// As a convention, do not return objects that are owned, e.g. if (obj instanceof this
// 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 the class defines _readNull, return null when nothing // If the class defines _readNull, return null when nothing
// was provided // was provided
|| this.prototype._readNull && obj == null && length <= 1) || 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) { formatNumber: function(num) {
return (Math.round(num * 100000) / 100000).toString(); 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 = { this.events = {
mousedown: function(event) { mousedown: function(event) {
curPoint = viewToArtwork(event, that._document); curPoint = viewToArtwork(event, that._document);
that.onHandleEvent('mouse-down', curPoint, event); that.onHandleEvent('mousedown', curPoint, event);
if (that.onMouseDown) if (that.onMouseDown)
that._document.redraw(); that._document.redraw();
if (that.eventInterval != null) { if (that.eventInterval != null) {
@ -54,9 +54,9 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
if (dragging && !onlyMove) { if (dragging && !onlyMove) {
curPoint = point || curPoint; curPoint = point || curPoint;
if (curPoint) if (curPoint)
that.onHandleEvent('mouse-drag', curPoint, event); that.onHandleEvent('mousedrag', curPoint, event);
} else if (!dragging || onlyMove) { } else if (!dragging || onlyMove) {
that.onHandleEvent('mouse-move', point, event); that.onHandleEvent('mousemove', point, event);
} }
if (that.onMouseMove || that.onMouseDrag) if (that.onMouseMove || that.onMouseDrag)
that._document.redraw(); that._document.redraw();
@ -67,7 +67,7 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
curPoint = null; curPoint = null;
if (that.eventInterval != null) if (that.eventInterval != null)
clearInterval(this.timer); clearInterval(this.timer);
that.onHandleEvent('mouse-up', that.onHandleEvent('mouseup',
viewToArtwork(event, that._document), event); viewToArtwork(event, that._document), event);
if (that.onMouseUp) if (that.onMouseUp)
that._document.redraw(); that._document.redraw();

View file

@ -39,25 +39,13 @@ var ToolEvent = this.ToolEvent = Base.extend({
this.type = type; this.type = type;
this.event = event; 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. * Convenience method to allow local overrides of point values.
* See application below. * See application below.
*/ */
choosePoint: function(point, toolPoint) { _choosePoint: function(point, toolPoint) {
if (point) return point ? point : toolPoint ? toolPoint.clone() : null;
return point;
if (toolPoint)
return new Point(toolPoint);
return null;
}, },
/** /**
@ -78,7 +66,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
* </code> * </code>
*/ */
getPoint: function() { getPoint: function() {
return this.choosePoint(this._point, this.tool.point); return this._choosePoint(this._point, this.tool.point);
}, },
setPoint: function(point) { setPoint: function(point) {
@ -90,7 +78,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
* event was fired. * event was fired.
*/ */
getLastPoint: function() { getLastPoint: function() {
return this.choosePoint(this._lastPoint, this.tool.lastPoint); return this._choosePoint(this._lastPoint, this.tool.lastPoint);
}, },
setLastPoint: function(lastPoint) { setLastPoint: function(lastPoint) {
@ -102,7 +90,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
* was last clicked. * was last clicked.
*/ */
getDownPoint: function() { getDownPoint: function() {
return this.choosePoint(this._downPoint, this.tool.downPoint); return this._choosePoint(this._downPoint, this.tool.downPoint);
}, },
setDownPoint: function(downPoint) { setDownPoint: function(downPoint) {
@ -117,7 +105,7 @@ var ToolEvent = this.ToolEvent = Base.extend({
*/ */
getMiddlePoint: function() { getMiddlePoint: function() {
// For explanations, see getDelta() // For explanations, see getDelta()
if (this._middlePoint == null && this.tool.lastPoint != null) { if (!this._middlePoint && this.tool.lastPoint) {
// (point + lastPoint) / 2 // (point + lastPoint) / 2
return this.tool.point.add(this.tool.lastPoint).divide(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 * 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 * mouse when the event was fired. In case of the mouseup event, the
* difference to the mouse-down position is returned. * difference to the mousedown position is returned.
*/ */
getDelta: function() { getDelta: function() {
// Do not put the calculated delta into delta, since this only reserved // 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 // Instead, keep calculating the delta each time, so the result can be
// directly modified by the script without changing the internal values. // directly modified by the script without changing the internal values.
// We could cache this and use clone, but this is almost as fast... // We could cache this and use clone, but this is almost as fast...
if (this._delta == null && this.tool.lastPoint != null) { return this._delta && this.tool.lastPoint
return this.tool.point.subtract(this.tool.lastPoint); ? this.tool.point.subtract(this.tool.lastPoint)
} : this._delta;
return this._delta;
}, },
setDelta: function(delta) { setDelta: function(delta) {
@ -168,32 +155,21 @@ var ToolEvent = this.ToolEvent = Base.extend({
* </code> * </code>
*/ */
getCount: function() { getCount: function() {
switch (this.type) { // Return downCount for both mouse down and up, since
case 'mouse-down': // the count is the same.
case 'mouse-up': return /^mouse(down|up)$/.test(this.type)
// Return downCount for both mouse down and up, since ? this.tool.downCount
// the count is the same. : this.tool.count;
return this.tool.downCount;
default:
return this.tool.count;
}
}, },
setCount: function(count) { setCount: function(count) {
switch (this.type) { this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count']
case 'mouse-down': = count;
case 'mouse-up':
this.tool.downCount = count;
break;
default:
this.tool.count = count;
break;
}
}, },
getModifiers: function() { getModifiers: function() {
return Key.modifiers; return Key.modifiers;
} },
// TODO: implement hitTest first // TODO: implement hitTest first
// getItem: function() { // getItem: function() {
@ -215,4 +191,12 @@ var ToolEvent = this.ToolEvent = Base.extend({
// setItem: function(Item item) { // setItem: function(Item item) {
// this.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: * Sample code:
* <code> * <code>
* // Fire the onMouseDrag event after the user has dragged * // Fire the onMouseDrag event after the user has dragged more then 5
* // more then 5 points from the last onMouseDrag event: * // points from the last onMouseDrag event:
* tool.minDistance = 5; * tool.minDistance = 5;
* </code> * </code>
*/ */
@ -98,42 +98,38 @@ var ToolHandler = this.ToolHandler = Base.extend({
this.lastPoint = this.point; this.lastPoint = this.point;
this.point = pt; this.point = pt;
switch (type) { switch (type) {
case 'mouse-down': case 'mousedown':
this.lastPoint = this.downPoint; this.lastPoint = this.downPoint;
this.downPoint = this.point; this.downPoint = this.point;
this.downCount++; this.downCount++;
break; break;
case 'mouse-up': case 'mouseup':
// Mouse up events return the down point for last point, // Mouse up events return the down point for last point, so delta is
// so delta is spanning over the whole drag. // spanning over the whole drag.
this.lastPoint = this.downPoint; this.lastPoint = this.downPoint;
break; break;
} }
if (start) { this.count = start ? 0 : this.count + 1;
this.count = 0;
} else {
this.count++;
}
return true; return true;
}, },
onHandleEvent: function(type, pt, event) { onHandleEvent: function(type, pt, event) {
switch (type) { switch (type) {
case 'mouse-down': case 'mousedown':
this.updateEvent(type, pt, null, null, true, false, false); this.updateEvent(type, pt, null, null, true, false, false);
if (this.onMouseDown) if (this.onMouseDown)
this.onMouseDown(new ToolEvent(this, type, event)); this.onMouseDown(new ToolEvent(this, type, event));
break; break;
case 'mouse-drag': case 'mousedrag':
// In order for idleInterval drag events to work, we need to // In order for idleInterval drag events to work, we need to not
// not check the first call for a change of position. // check the first call for a change of position. Subsequent calls
// Subsequent calls required by min/maxDistance functionality // required by min/maxDistance functionality will require it,
// will require it, otherwise this might loop endlessly. // otherwise this might loop endlessly.
var needsChange = false, var needsChange = false,
// If the mouse is moving faster than maxDistance, do not // If the mouse is moving faster than maxDistance, do not produce
// produce events for what is left after the first event is // events for what is left after the first event is generated in
// generated in case it is shorter than maxDistance, as this // case it is shorter than maxDistance, as this would produce weird
// would produce weird results. matchMaxDistance controls this. // results. matchMaxDistance controls this.
matchMaxDistance = false; matchMaxDistance = false;
while (this.updateEvent(type, pt, this.minDistance, while (this.updateEvent(type, pt, this.minDistance,
this.maxDistance, false, needsChange, matchMaxDistance)) { this.maxDistance, false, needsChange, matchMaxDistance)) {
@ -143,11 +139,11 @@ var ToolHandler = this.ToolHandler = Base.extend({
matchMaxDistance = true; matchMaxDistance = true;
} }
break; break;
case 'mouse-up': case 'mouseup':
// If the last mouse drag happened in a different place, call // If the last mouse drag happened in a different place, call mouse
// mouse drag first, then mouse up. // drag first, then mouse up.
if ((this.point.x != pt.x || this.point.y != pt.y) 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)) { this.maxDistance, false, false, false)) {
if (this.onMouseDrag) if (this.onMouseDrag)
this.onMouseDrag(new ToolEvent(this, type, event)); this.onMouseDrag(new ToolEvent(this, type, event));
@ -156,11 +152,11 @@ var ToolHandler = this.ToolHandler = Base.extend({
false, false); false, false);
if (this.onMouseUp) if (this.onMouseUp)
this.onMouseUp(new ToolEvent(this, type, event)); 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.updateEvent(type, pt, null, null, true, false, false);
this.firstMove = true; this.firstMove = true;
break; break;
case 'mouse-move': case 'mousemove':
while (this.updateEvent(type, pt, this.minDistance, while (this.updateEvent(type, pt, this.minDistance,
this.maxDistance, this.firstMove, true, false)) { this.maxDistance, this.firstMove, true, false)) {
if (this.onMouseMove) if (this.onMouseMove)

View file

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

View file

@ -16,18 +16,21 @@
var Key = this.Key = new function() { var Key = this.Key = new function() {
// TODO: make sure the keys are called the same as in Scriptographer // TODO: make sure the keys are called the same as in Scriptographer
// Missing: tab, cancel, clear, pause, page-down, page-up, end, home, comma, // Missing: tab, cancel, clear, page-down, page-up, comma, minus, period,
// minus, period, slash, etc etc etc. // slash, etc etc etc.
var keys = { var keys = {
8: 'backspace', 8: 'backspace',
13: 'enter', 13: 'enter',
16: 'shift', 16: 'shift',
17: 'control', 17: 'control',
19: 'option', // was alt 18: 'option',
20: 'capsLock', 19: 'pause',
20: 'caps-lock',
27: 'escape', 27: 'escape',
32: 'space', 32: 'space',
35: 'end',
36: 'home',
37: 'left', 37: 'left',
38: 'up', 38: 'up',
39: 'right', 39: 'right',
@ -41,57 +44,84 @@ var Key = this.Key = new function() {
control: false, control: false,
option: false, option: false,
command: false, command: false,
capsLock: false capsLock: false,
toString: function() {
return Base.formatObject(this);
}
}, },
keyCodes = {}, // Since only keypress gets proper keyCodes that are actually representing
downCode, // characters, we need to perform a little trickery here to use these codes
downTimer; // 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) { function handleKey(down, keyCode, charCode, event) {
var character = String.fromCharCode(code), var character = String.fromCharCode(charCode),
keyCode = keys[code] || character.toLowerCase(), key = keys[keyCode] || character.toLowerCase(),
handler = down ? 'onKeyDown' : 'onKeyUp'; handler = down ? 'onKeyDown' : 'onKeyUp';
console.log(handler, keyCode, character); keyMap[key] = down;
if (modifiers[keyCode] !== undefined) { if (paper.tool && paper.tool[handler]) {
modifiers[keyCode] = down;
} else if (paper.tool && paper.tool[handler]) {
// Call the onKeyDown or onKeyUp handler if present // Call the onKeyDown or onKeyUp handler if present
// When the handler function returns false, prevent the // When the handler function returns false, prevent the
// default behaviour of the key event: // default behaviour of the key event:
// PORT: Add to Sg // 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) { if (paper.tool[handler](keyEvent) === false) {
keyEvent.preventDefault(); 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, { DomEvent.add(document, {
keydown: function(event) { keydown: function(event) {
var code = downCode = event.which || event.keyCode; var code = event.which || event.keyCode;
downTimer = setTimeout(function() { // If the keyCode is in keys, it needs to be handled by keydown and
keyCodes[code] = code; // not in keypress after (arrows for example wont be triggering
handleKey(true, code, event); // a keypress, but space would).
}, 1); 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) { keypress: function(event) {
clearTimeout(downTimer); if (downCode != null) {
var code = event.which || event.keyCode; var code = event.which || event.keyCode;
keyCodes[downCode] = code; // Link the downCode from keydown with the code form keypress, so
handleKey(true, code, event); // keyup can retrieve that code again.
charCodeMap[downCode] = code;
handleKey(true, downCode, code, event);
downCode = null;
}
}, },
keyup: function(event) { keyup: function(event) {
var code = event.which || event.keyCode; var code = event.which || event.keyCode,
handleKey(false, keyCodes[code], event); key = keys[code], name;
delete keyCodes[code]; 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, modifiers: modifiers,
isDown: function(key) { isDown: function(key) {
return !!activeKeys[key]; return !!keyMap[key];
} }
}; };
}; };

View file

@ -16,11 +16,19 @@
var KeyEvent = this.KeyEvent = Event.extend(new function() { var KeyEvent = this.KeyEvent = Event.extend(new function() {
return { return {
initialize: function(down, keyCode, character, event) { initialize: function(down, key, character, event) {
this.base(event); this.base(event);
this.type = down ? 'key-down' : 'key-up'; this.type = down ? 'keydown' : 'keyup';
this.keyCode = keyCode; this.key = key;
this.character = character; 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, var doc = paper.document,
tool = paper.tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code) tool = paper.tool = /on(?:Key|Mouse)(?:Up|Down|Move|Drag)/.test(code)
&& new Tool(null, doc), && new Tool(null, doc),
onEditOptions, onOptions, onSelect, onDeselect, onReselect, onEditOptions, onSelect, onDeselect, onReselect, onMouseDown,
onMouseDown, onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onMouseUp, onMouseDrag, onMouseMove, onKeyDown, onKeyUp,
onKeyUp,
res = eval(compile(code)); res = eval(compile(code));
if (tool) { if (tool) {
Base.each(['onEditOptions', 'onOptions', 'onSelect', Base.each(['onEditOptions', 'onSelect', 'onDeselect',
'onDeselect', 'onReselect', 'onMouseDown', 'onMouseUp', 'onReselect', 'onMouseDown', 'onMouseUp', 'onMouseDrag',
'onMouseDrag', 'onMouseMove', 'onKeyDown', 'onKeyUp'], 'onMouseMove', 'onKeyDown', 'onKeyUp'],
function(key) { function(key) {
tool[key] = eval(key); tool[key] = eval(key);
} }