mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Merge remote branch 'origin/master'
This commit is contained in:
commit
b0e91c0173
10 changed files with 159 additions and 124 deletions
|
@ -287,7 +287,7 @@
|
|||
|
||||
var layer = document.activeLayer;
|
||||
function onKeyDown(event) {
|
||||
if (event.keyCode == 'space')
|
||||
if (event.key == 'space')
|
||||
layer.selected = !layer.selected;
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -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]);
|
||||
|
|
26
src/paper.js
26
src/paper.js
|
@ -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(', ') + ' }';
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
+ ' }';
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
|
||||
var Event = this.Event = Base.extend({
|
||||
beans: true,
|
||||
|
||||
initialize: function(event) {
|
||||
this.event = event;
|
||||
},
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
};
|
|
@ -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()
|
||||
+ ' }';
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue