Implement segment point selection.

This commit is contained in:
Jonathan Puckey 2011-04-21 18:06:06 +02:00
parent 63c3480ef4
commit 73b97dbfba
4 changed files with 168 additions and 19 deletions

View file

@ -279,7 +279,7 @@ var Item = this.Item = Base.extend({
* Removes the item.
*/
remove: function() {
if(this._selected)
if(this.getSelected())
this.setSelected(false);
return this.removeFromParent();
},

View file

@ -20,6 +20,7 @@ var Path = this.Path = PathItem.extend({
initialize: function(segments) {
this.base();
this.closed = false;
this._selectedSegmentCount = 0;
// Support both passing of segments as array or arguments
// If it is an array, it can also be a description of a point, so
// check its first entry for object as well
@ -128,6 +129,37 @@ var Path = this.Path = PathItem.extend({
}
},
getSelected: function() {
return this._selectedSegmentCount > 0;
},
setSelected: function(selected) {
var wasSelected = this.getSelected();
var length = this._segments.length;
if (wasSelected != selected && length) {
var selectedItems = this._document._selectedItems;
if (selected) {
selectedItems.push(this);
} else {
// TODO: is there a faster way?
var index = selectedItems.indexOf(this);
if (index != -1)
selectedItems.splice(index, 1);
}
}
this._selectedSegmentCount = selected ? length : 0;
for (var i = 0; i < length; i++)
this._segments[i]._selectionState = selected ? 'point' : null;
},
isFullySelected: function() {
return this._selectedSegmentCount == this._segments.length;
},
setFullySelected: function(selected) {
this.setSelected(selected);
},
// TODO: pointsToCurves([tolerance[, threshold[, cornerRadius[, scale]]]])
// TODO: curvesToPoints([maxPointDistance[, flatness]])
// TODO: reduceSegments([flatness])
@ -254,23 +286,28 @@ var Path = this.Path = PathItem.extend({
function drawHandles(ctx, segments) {
for (var i = 0, l = segments.length; i < l; i++) {
var segment = segments[i],
point = segment._point;
point = segment._point,
pointSelected = segment._selectionState == 'point';
// TODO: draw handles depending on selection state of
// segment.point and neighbouring segments.
drawHandle(ctx, point, segment._handleIn);
drawHandle(ctx, point, segment._handleOut);
if (pointSelected || segment.getSelected(segment._handleIn))
drawHandle(ctx, point, segment._handleIn);
if (pointSelected || segment.getSelected(segment._handleOut))
drawHandle(ctx, point, segment._handleOut);
// Draw a rectangle at segment.point:
ctx.save();
ctx.beginPath();
ctx.rect(point._x - 2, point._y - 2, 4, 4);
ctx.fill();
// TODO: Only draw white rectangle if point.isSelected()
// TODO: Only draw white rectangle if point.getSelected()
// is false:
ctx.beginPath();
ctx.rect(point._x - 1, point._y - 1, 2, 2);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.restore();
if (!pointSelected) {
ctx.beginPath();
ctx.rect(point._x - 1, point._y - 1, 2, 2);
ctx.fillStyle = '#ffffff';
ctx.fill();
ctx.restore();
}
}
}

View file

@ -125,12 +125,112 @@ var Segment = this.Segment = Base.extend({
return this._path && this._path._segments[this.getIndex() - 1] || null;
},
// TODO:
// isSelected: function() {
//
// }
//
// setSelected: function(pt, selected)
getSelected: function(/* point */) {
var point = arguments.length ? arguments[0] : this.point;
var state = this._selectionState;
if (point == this.point) {
return state == 'point';
} else if (point == this.handleIn) {
return state == 'handle-in' || state == 'handle-both';
} else if (point == this.handleOut) {
return state == 'handle-out' || state == 'handle-both';
}
return false;
},
setSelected: function(/* pt, selected */) {
var pt, selected;
if (arguments.length == 2) {
// setSelected(pt, selected)
pt = arguments[0];
selected = arguments[1];
} else {
// setSelected(selected)
pt = this._point;
selected = arguments[0];
}
if (!this._path)
return;
var wasSelected = !!this._selectionState;
var state = this._selectionState,
pointSelected = state == 'point',
handleInSelected = state == 'handle-in'
|| state == 'handle-both',
handleOutSelected = state == 'handle-out'
|| state == 'handle-both',
previous = this.getPrevious(),
next = this.getNext(),
closed = this._path.closed,
segments = this._path._segments,
length = segments.length;
if (length > 1 && closed) {
if (previous == null)
previous = segments[length - 1];
if (next == null)
next = segments[0];
}
if (pt == this._point) {
if (pointSelected != selected) {
if (selected) {
handleInSelected = handleOutSelected = false;
} else {
// When deselecting a point, the handles get selected
// instead depending on the selection state of their
// neighbors.
handleInSelected = previous != null
&& (previous._point.getSelected()
|| previous._handleOut.getSelected());
handleOutSelected = next != null
&& (next._point.getSelected()
|| next._handleOut.getSelected());
}
pointSelected = selected;
}
} else if (pt == this._handleIn) {
if (handleInSelected != selected) {
// When selecting handles, the point get deselected.
if (selected)
pointSelected = false;
handleInSelected = selected;
}
} else if (pt == this._handleOut) {
if (handleOutSelected != selected) {
// When selecting handles, the point get deselected.
if (selected)
pointSelected = false;
handleOutSelected = selected;
}
}
this._selectionState = pointSelected
? 'point'
: handleInSelected
? handleOutSelected
? 'handle-both'
: 'handle-in'
: handleOutSelected
? 'handle-out'
: null;
// If the selection state of the segment has changed, we need to let
// it's path know and possibly add or remove it from
// document._selectedItems
if (wasSelected == !this._selectionState) {
var path = this._path,
selectedItems = path._document._selectedItems;
if (!this._selectionState) {
path._selectedSegmentCount--;
if (path._selectedSegmentCount == 0) {
var index = selectedItems.indexOf(this);
selectedItems.slice(index, 1);
}
} else {
path._selectedSegmentCount++;
if (path._selectedSegmentCount == 1) {
selectedItems.push(path);
}
}
}
},
reverse: function() {
return new Segment(this._point, this._handleOut, this._handleIn);
@ -141,8 +241,12 @@ var Segment = this.Segment = Base.extend({
},
remove: function() {
if (this._path && this._path._segments)
return !!this._path._segments.splice(this.getIndex(), 1).length;
if (this._path) {
this._path._segments.splice(this.getIndex(), 1);
if (this.getSelected())
this._path._selectedSegmentCount--;
return true;
}
return false;
},

View file

@ -29,7 +29,15 @@ var SegmentPoint = Point.extend({
this._y = y;
// this._segment._markDirty(DirtyFlags.BOUNDS);
},
setSelected: function(selected) {
this._segment.setSelected(this, selected);
},
getSelected: function() {
return this._segment.getSelected(this);
},
statics: {
create: function(segment, arg1, arg2) {
var point;