diff --git a/src/item/Item.js b/src/item/Item.js index 2bd9d048..c7891e3a 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -231,7 +231,7 @@ var Item = this.Item = Base.extend({ } } else if ((selected = !!selected) != this._selected) { this._selected = selected; - this._project._selectItem(this, selected); + this._project._updateSelection(this); } }, diff --git a/src/path/Path.js b/src/path/Path.js index 2bfdd0d5..819dce0b 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -46,7 +46,7 @@ var Path = this.Path = PathItem.extend({ initialize: function(segments) { this.base(); this._closed = false; - this._selectedSegmentCount = 0; + this._selectedSegmentState = 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 @@ -248,9 +248,9 @@ var Path = this.Path = PathItem.extend({ segment._path = this; segment._index = index + i; // If parts of this segment are selected, adjust the internal - // _selectedSegmentCount now + // _selectedSegmentState now if (segment._selectionState) - this._updateSelection(segment); + this._updateSelection(segment, 0, segment._selectionState); } if (append) { // Append them all at the end by using push @@ -280,13 +280,6 @@ var Path = this.Path = PathItem.extend({ return segs; }, - _updateSelection: function(segment) { - var count = this._selectedSegmentCount += - segment._selectionState ? 1 : -1; - if (count <= 1) - this._project._selectItem(this, count == 1); - }, - // PORT: Add support for adding multiple segments at once to Scriptographer // DOCS: find a way to document the variable segment parameters of Path#add /** @@ -537,10 +530,8 @@ var Path = this.Path = PathItem.extend({ // Update selection state accordingly for (var i = 0; i < amount; i++) { var segment = removed[i]; - if (segment._selectionState) { - segment._selectionState = 0; - this._updateSelection(segment); - } + if (segment._selectionState) + this._updateSelection(segment, segment._selectionState, 0); // Clear the indices and path references of the removed segments removed._index = removed._path = undefined; } @@ -599,23 +590,8 @@ var Path = this.Path = PathItem.extend({ * } * */ - isSelected: function() { - return this._selectedSegmentCount > 0; - }, - - setSelected: function(selected) { - var wasSelected = this.isSelected(), - length = this._segments.length; - if (!wasSelected != !selected && length) - this._project._selectItem(this, selected); - this._selectedSegmentCount = selected ? length : 0; - for (var i = 0; i < length; i++) - this._segments[i]._selectionState = selected - ? SelectionState.POINT : 0; - }, - /** - * Specifies whether all segments of the path are selected. + * Specifies whether the path and all its segments are selected. * * @type Boolean * @bean @@ -623,10 +599,10 @@ var Path = this.Path = PathItem.extend({ * @example {@paperscript} * // A path is fully selected, if all of its segments are selected: * var path = new Path.Circle(new Size(80, 50), 35); - * path.selected = true; + * path.fullySelected = true; * * var path2 = new Path.Circle(new Size(180, 50), 35); - * path2.selected = true; + * path2.fullySelected = true; * * // Deselect the second segment of the second path: * path2.segments[1].selected = false; @@ -645,13 +621,26 @@ var Path = this.Path = PathItem.extend({ * } */ isFullySelected: function() { - return this._selectedSegmentCount == this._segments.length; + return this._selected && this._selectedSegmentState + == this._segments.length * SelectionState.POINT; }, setFullySelected: function(selected) { + var length = this._segments.length; + this._selectedSegmentState = selected + ? length * SelectionState.POINT : 0; + for (var i = 0; i < length; i++) + this._segments[i]._selectionState = selected + ? SelectionState.POINT : 0; this.setSelected(selected); }, + _updateSelection: function(segment, oldState, newState) { + segment._selectionState = newState; + this.setSelected( + (this._selectedSegmentState += newState - oldState) > 0); + }, + /** * Converts the curves in the path to straight lines. * @@ -1166,13 +1155,12 @@ var Path = this.Path = PathItem.extend({ for (var i = 0, l = segments.length; i < l; i++) { var segment = segments[i], point = segment._point, - pointSelected = segment._selectionState == SelectionState.POINT; - // TODO: draw handles depending on selection state of - // segment.point and neighbouring segments. - if (pointSelected || segment._isSelected(segment._handleIn)) - drawHandle(ctx, point, segment._handleIn); - if (pointSelected || segment._isSelected(segment._handleOut)) - drawHandle(ctx, point, segment._handleOut); + state = segment._selectionState, + selected = state & SelectionState.POINT; + if (selected || (state & SelectionState.HANDLE_IN)) + drawHandle(ctx, point, segment._handleIn); + if (selected || (state & SelectionState.HANDLE_OUT)) + drawHandle(ctx, point, segment._handleOut); // Draw a rectangle at segment.point: ctx.save(); ctx.beginPath(); @@ -1180,7 +1168,7 @@ var Path = this.Path = PathItem.extend({ ctx.fill(); // If the point is not selected, draw a white square that is 1 px // smaller on all sides: - if (!pointSelected) { + if (!selected) { ctx.beginPath(); ctx.rect(point._x - 1, point._y - 1, 2, 2); ctx.fillStyle = '#ffffff'; diff --git a/src/path/Segment.js b/src/path/Segment.js index c904586b..a89a3dfc 100644 --- a/src/path/Segment.js +++ b/src/path/Segment.js @@ -182,7 +182,6 @@ var Segment = this.Segment = Base.extend({ var path = this._path, selected = !!selected, // convert to boolean state = this._selectionState, - wasSelected = !!state, // For performance reasons use array indices to access the various // selection states: 0 = point, 1 = handleIn, 2 = handleOut selection = [ @@ -220,10 +219,12 @@ var Segment = this.Segment = Base.extend({ // If the selection state of the segment has changed, we need to let // it's path know and possibly add or remove it from // project._selectedItems - if (path && wasSelected != !!this._selectionState) - path._updateSelection(this); + if (path && state != this._selectionState) + path._updateSelection(this, state, this._selectionState); }, + + /** * Specifies whether the {@link #point} of the segment is selected. * @type Boolean diff --git a/src/path/SelectionState.js b/src/path/SelectionState.js index f5c76857..026886db 100644 --- a/src/path/SelectionState.js +++ b/src/path/SelectionState.js @@ -14,9 +14,12 @@ * All rights reserved. */ +// These values are ordered so that SelectionState.POINT has the highest value. +// As Path#_selectedSegmentState is the addition of all segment's states, and is +// used to see if all segments are fully selected, meaning they are set to +// SelectionState.POINT. var SelectionState = { - POINT: 1, - HANDLE_IN: 2, - HANDLE_OUT: 4, - HANDLE_BOTH: 6 + HANDLE_IN: 1, + HANDLE_OUT: 2, + POINT: 4 }; diff --git a/src/project/Project.js b/src/project/Project.js index c2b1256a..c007fff2 100644 --- a/src/project/Project.js +++ b/src/project/Project.js @@ -142,8 +142,8 @@ var Project = this.Project = Base.extend({ // TODO: Implement setSelectedItems? - _selectItem: function(item, select) { - if (select) { + _updateSelection: function(item) { + if (item._selected) { this._selectedItemCount++; this._selectedItems[item.getId()] = item; } else {