More refactoring for selection, still only single selection
git-svn-id: http://svg-edit.googlecode.com/svn/trunk@241 eee81c28-f429-11dd-99c0-75d572ba1ddd
This commit is contained in:
@@ -22,23 +22,23 @@
|
||||
<div id="tools_top" class="tools_panel">
|
||||
<!-- File-like buttons: New, Save -->
|
||||
<div>
|
||||
<img class="tool_button" id="tool_clear" src="images/clear.png" title="New Image [N]" alt="Clear" />
|
||||
<img class="tool_button" id="tool_save" src="images/save.png" title="Save Image [S]" alt="Save"/>
|
||||
<img class="tool_button" id="tool_clear" src="images/clear.png" title="New Image [N]" alt="Clear" />
|
||||
<img class="tool_button" id="tool_save" src="images/save.png" title="Save Image [S]" alt="Save"/>
|
||||
</div>
|
||||
|
||||
<!-- History buttons -->
|
||||
<div>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button tool_button_disabled" id="tool_undo" src="images/undo.png" title="Undo [Z]" alt="Undo" />
|
||||
<img class="tool_button tool_button_disabled" id="tool_redo" src="images/redo.png" title="Redo [Shift+Z/Y]" alt="Redo"/>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button tool_button_disabled" id="tool_undo" src="images/undo.png" title="Undo [Z]" alt="Undo" />
|
||||
<img class="tool_button tool_button_disabled" id="tool_redo" src="images/redo.png" title="Redo [Shift+Z/Y]" alt="Redo"/>
|
||||
</div>
|
||||
|
||||
<!-- Buttons when something is selected -->
|
||||
<div id="selected_panel">
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_delete" src="images/delete.png" title="Delete Element [Delete/Backspace]" alt="Delete"/>
|
||||
<img class="tool_button" id="tool_move_top" src="images/move_top.png" title="Move to Top [Shift+Up]" alt="Top"/>
|
||||
<img class="tool_button" id="tool_move_bottom" src="images/move_bottom.png" title="Move to Bottom [Shift+Down]" alt="Bottom"/>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_delete" src="images/delete.png" title="Delete Element [Delete/Backspace]" alt="Delete"/>
|
||||
<img class="tool_button" id="tool_move_top" src="images/move_top.png" title="Move to Top [Shift+Up]" alt="Top"/>
|
||||
<img class="tool_button" id="tool_move_bottom" src="images/move_bottom.png" title="Move to Bottom [Shift+Down]" alt="Bottom"/>
|
||||
</div>
|
||||
|
||||
<div id="rect_panel">
|
||||
@@ -248,8 +248,6 @@
|
||||
<div id="tool_fhellipse" class="tool_flyout_button" title="Free-Hand Ellipse"></div>
|
||||
</div>
|
||||
|
||||
</div> <!-- tools_container -->
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -238,8 +238,8 @@ function svg_edit_setup() {
|
||||
$('#styleoverrides').text('');
|
||||
$('.tool_button_current').removeClass('tool_button_current').addClass('tool_button');
|
||||
$(button).addClass('tool_button_current');
|
||||
// when a tool is selected, we should deselect the currently selected element
|
||||
svgCanvas.selectNone();
|
||||
// when a tool is selected, we should deselect any currently selected elements
|
||||
svgCanvas.clearSelection();
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
@@ -115,8 +115,10 @@ function SvgCanvas(c)
|
||||
|
||||
// this function is used to reset the id and element that the selector is attached to
|
||||
this.reset = function(e) {
|
||||
// console.log("Selector.reset() with e=" + e.id);
|
||||
this.locked = true;
|
||||
this.selectedElement = e;
|
||||
this.resize();
|
||||
this.selectorGroup.setAttribute("display", "inline");
|
||||
};
|
||||
|
||||
@@ -186,6 +188,7 @@ function SvgCanvas(c)
|
||||
};
|
||||
|
||||
this.resize = function(bbox) {
|
||||
// console.log("in Selector.resize()");
|
||||
var selectedBox = this.selectorRect;
|
||||
var selectedGrips = this.selectorGrips;
|
||||
var selected = this.selectedElement;
|
||||
@@ -197,6 +200,8 @@ function SvgCanvas(c)
|
||||
if (selected.tagName == "text") {
|
||||
offset += 2;
|
||||
}
|
||||
var bbox = bbox || this.selectedElement.getBBox();
|
||||
// console.log(" bbox=" + bbox.x + "," + bbox.y + "," + bbox.width + "," + bbox.height);
|
||||
var l=bbox.x-offset, t=bbox.y-offset, w=bbox.width+(offset<<1), h=bbox.height+(offset<<1);
|
||||
selectedBox.x.baseVal.value = l;
|
||||
selectedBox.y.baseVal.value = t;
|
||||
@@ -219,6 +224,9 @@ function SvgCanvas(c)
|
||||
selectedGrips.s.x.baseVal.value = l+w/2-3;
|
||||
selectedGrips.s.y.baseVal.value = t+h-3;
|
||||
};
|
||||
|
||||
// now initialize the selector
|
||||
this.reset(elem);
|
||||
};
|
||||
|
||||
// TODO: add accessor methods to determine number of currently selected elements
|
||||
@@ -249,22 +257,27 @@ function SvgCanvas(c)
|
||||
};
|
||||
|
||||
this.requestSelector = function(elem) {
|
||||
if (elem == null) return null;
|
||||
var N = this.selectors.length;
|
||||
|
||||
// console.log("requestSelector() with N=" + N);
|
||||
if (this.selectorParentGroup == null) {
|
||||
initGroup();
|
||||
}
|
||||
|
||||
// if we've already acquired one for this element, return it
|
||||
if (this.selectorMap[elem] ) {
|
||||
if (typeof(this.selectorMap[elem]) == "object") {
|
||||
// console.log("-found elem in selectorMap");
|
||||
this.selectorMap[elem].locked = true;
|
||||
return this.selectorMap[elem];
|
||||
}
|
||||
// console.log(this.selectors);
|
||||
|
||||
for (var i = 0; i < N; ++i) {
|
||||
if (this.selectors[i] && !this.selectors[i].locked) {
|
||||
this.selectors[i].locked = true;
|
||||
this.selectors[i].reset(elem);
|
||||
this.selectors[i].reset(elem);
|
||||
this.selectorMap[elem] = this.selectors[i];
|
||||
return this.selectors[i];
|
||||
}
|
||||
}
|
||||
@@ -274,14 +287,20 @@ function SvgCanvas(c)
|
||||
this.selectorMap[elem] = this.selectors[N];
|
||||
return this.selectors[N];
|
||||
};
|
||||
this.releaseSelector = function(sel) {
|
||||
this.releaseSelector = function(elem) {
|
||||
// console.log("releaseSelector() with N=" + N +", elem=" + elem.id);
|
||||
if (elem == null) return;
|
||||
var N = this.selectors.length;
|
||||
var sel = this.selectorMap[elem];
|
||||
// console.log("sel=" + sel);
|
||||
// console.log(this.selectors);
|
||||
for (var i = 0; i < N; ++i) {
|
||||
if (this.selectors[i] && this.selectors[i] == sel) {
|
||||
// console.log("found it");
|
||||
if (sel.locked == false) {
|
||||
console.log("WARNING! selector was released but was already unlocked");
|
||||
}
|
||||
delete this.selectorMap[sel.selectedElement];
|
||||
delete this.selectorMap[elem];
|
||||
sel.locked = false;
|
||||
sel.selectedElement = null;
|
||||
|
||||
@@ -297,6 +316,9 @@ function SvgCanvas(c)
|
||||
|
||||
// this keeps the selector groups as the last child in the document
|
||||
this.update = function() {
|
||||
if (this.selectorParentGroup == null) {
|
||||
initGroup();
|
||||
}
|
||||
this.selectorParentGroup = svgroot.appendChild(this.selectorParentGroup);
|
||||
}
|
||||
|
||||
@@ -371,6 +393,22 @@ function SvgCanvas(c)
|
||||
var undoStackPointer = 0;
|
||||
var undoStack = [];
|
||||
|
||||
// Since the only browser that supports getIntersectionList is Opera, we need to
|
||||
// provide an implementation here. We brute-force it for now.
|
||||
var getIntersectionList = function(rect) {
|
||||
var resultList = null;
|
||||
try {
|
||||
resultList = svgroot.getIntersectionList(rect, null);
|
||||
} catch(e) { }
|
||||
|
||||
if (resultList == null || typeof(resultList.item) != "function")
|
||||
{
|
||||
// TODO: provide brute-force algorithm, looking at every element's bbox for intersection
|
||||
console.log("brute force!");
|
||||
}
|
||||
return resultList;
|
||||
};
|
||||
|
||||
// FIXME: we MUST compress consecutive text changes to the same element
|
||||
// (right now each keystroke is saved as a separate command that includes the
|
||||
// entire text contents of the text element)
|
||||
@@ -587,13 +625,18 @@ function SvgCanvas(c)
|
||||
};
|
||||
|
||||
// public events
|
||||
|
||||
// TODO: grab code here and add to addSelection...
|
||||
// TODO: use addSelection instead of selectElement throughout
|
||||
|
||||
// call this function to set a single selected element
|
||||
// call this function with null to clear the selected element
|
||||
var selectElement = function(newSelected, multi)
|
||||
{
|
||||
var rubberBox = selectorManager.getRubberBandBox();
|
||||
// if the element to be selected is actually the rubber-band box
|
||||
// then simply return (do not select it)
|
||||
if (newSelected == selectorManager.getRubberBandBox()) {
|
||||
if (newSelected == rubberBox) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -612,6 +655,13 @@ function SvgCanvas(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Firefox does not implement getIntersectionList(), see
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=501421
|
||||
// Webkit does not implement getIntersectionList(), see
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=11274
|
||||
// TODO: for these browsers we will need to brute force getIntersectionList()
|
||||
// var nodes = svgroot.getIntersectionList(rubberBox.getBBox(), null);
|
||||
|
||||
// find next slot in selectedElements array
|
||||
var index = 0;
|
||||
/* index = selectedElements.length;
|
||||
@@ -649,6 +699,79 @@ function SvgCanvas(c)
|
||||
|
||||
call("selected", selected);
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
this.clearSelection = function() {
|
||||
if (selectedElements[0] == null) { return; }
|
||||
// console.log("clearSelection() with length=" + selectedElements.length);
|
||||
|
||||
for (var i = 0; i < selectedElements.length; ++i) {
|
||||
var elem = selectedElements[i];
|
||||
if (elem == null) break;
|
||||
selectorManager.releaseSelector(elem);
|
||||
selectedElements[i] = null;
|
||||
}
|
||||
call("selected", null);
|
||||
// console.log(selectedElements);
|
||||
};
|
||||
|
||||
this.addToSelection = function(elemsToAdd) {
|
||||
if (elemsToAdd.length == 0) { return; }
|
||||
|
||||
// find the first null in our selectedElements array
|
||||
var j = 0;
|
||||
while (j < selectedElements.length) {
|
||||
if (selectedElements[j] == null) {
|
||||
break;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
// console.log("addToSelection() with j=" + j + " and # to add is " + elemsToAdd.length);
|
||||
// console.log(selectedElements);
|
||||
|
||||
// now add each element consecutively
|
||||
for (var i = 0; i < elemsToAdd.length; ++i) {
|
||||
var elem = elemsToAdd[i];
|
||||
// if it's not already there, add it
|
||||
if (selectedElements.indexOf(elem) == -1) {
|
||||
selectedElements[j++] = elem;
|
||||
selectorManager.requestSelector(elem);
|
||||
selectedBBox = elem.getBBox();
|
||||
call("selected", elem);
|
||||
// console.log(selectorManager.selectors);
|
||||
// console.log(selectorManager.selectorMap);
|
||||
}
|
||||
}
|
||||
// console.log(selectedElements);
|
||||
// TODO: if there is only one element, then set the current fill/stroke properties to it
|
||||
};
|
||||
|
||||
//
|
||||
this.removeFromSelection = function(elemsToRemove) {
|
||||
if (selectedElements[0] == null) { return; }
|
||||
if (elemsToRemove.length == 0) { return; }
|
||||
|
||||
// find every element and remove it from our array copy
|
||||
var newSelectedItems = new Array(selectedElements.length);
|
||||
var j = 0;
|
||||
for (var i = 0; i < selectedElements.length; ++i) {
|
||||
var elem = selectedElements[i];
|
||||
if (elem) {
|
||||
// keep the item
|
||||
if (elemsToRemove.indexOf(elem) == -1) {
|
||||
newSelectedItems[j++] = elem;
|
||||
}
|
||||
else { // remove the item and its selector
|
||||
console.log(selectorManager.selectors);
|
||||
console.log(selectorManager.selectorMap);
|
||||
selectorManager.releaseSelector(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
// the copy becomes the master now
|
||||
selectedElements = newSelectedItems;
|
||||
};
|
||||
|
||||
// in mouseDown :
|
||||
// - when we are in a create mode, the element is added to the canvas
|
||||
@@ -668,7 +791,8 @@ function SvgCanvas(c)
|
||||
var t = evt.target;
|
||||
// WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg>
|
||||
if (t.nodeName.toLowerCase() != "div" && t.nodeName.toLowerCase() != "svg") {
|
||||
selectElement(t);
|
||||
canvas.clearSelection();
|
||||
canvas.addToSelection([t]);
|
||||
}
|
||||
else {
|
||||
current_mode = "multiselect";
|
||||
@@ -856,7 +980,7 @@ function SvgCanvas(c)
|
||||
// selector for it, etc
|
||||
var nodeName = evt.target.nodeName;
|
||||
if (nodeName != "div" && nodeName != "svg") {
|
||||
selectElement(evt.target);
|
||||
addToSelection([evt.target]);
|
||||
}
|
||||
break;
|
||||
case "resize":
|
||||
@@ -1082,7 +1206,7 @@ function SvgCanvas(c)
|
||||
|
||||
this.save = function() {
|
||||
// remove the selected outline before serializing
|
||||
this.selectNone();
|
||||
this.clearSelection();
|
||||
var str = "<?xml version=\"1.0\" standalone=\"no\"?>\n";
|
||||
// see http://jwatt.org/svg/authoring/#doctype-declaration
|
||||
// str += "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
|
||||
@@ -1094,7 +1218,7 @@ function SvgCanvas(c)
|
||||
var nodes = svgroot.childNodes;
|
||||
var len = svgroot.childNodes.length;
|
||||
var i = 0;
|
||||
this.selectNone();
|
||||
this.clearSelection();
|
||||
for(var rep = 0; rep < len; rep++){
|
||||
if (nodes[i].nodeType == 1) { // element node
|
||||
nodes[i].parentNode.removeChild(nodes[i]);
|
||||
@@ -1279,17 +1403,13 @@ function SvgCanvas(c)
|
||||
window.open("data:image/svg+xml;base64," + Utils.encode64(svg));
|
||||
};
|
||||
|
||||
this.selectNone = function() {
|
||||
selectElement(null);
|
||||
};
|
||||
|
||||
this.deleteSelectedElement = function() {
|
||||
var selected = selectedElements[0];
|
||||
if (selected != null) {
|
||||
var parent = selected.parentNode;
|
||||
var t = selected;
|
||||
// this will unselect the element (and remove the selectedOutline)
|
||||
selectElement(null);
|
||||
this.removeFromSelection([t]);
|
||||
var elem = parent.removeChild(t);
|
||||
addCommandToHistory(new RemoveElementCommand(elem, parent));
|
||||
}
|
||||
@@ -1336,23 +1456,19 @@ function SvgCanvas(c)
|
||||
|
||||
this.undo = function() {
|
||||
if (undoStackPointer > 0) {
|
||||
this.selectNone();
|
||||
this.clearSelection();
|
||||
var cmd = undoStack[--undoStackPointer];
|
||||
cmd.unapply();
|
||||
call("changed", cmd.elem);
|
||||
}
|
||||
// console.log("after undo, stackPointer=" + undoStackPointer);
|
||||
// console.log(undoStack);
|
||||
}
|
||||
this.redo = function() {
|
||||
if (undoStackPointer < undoStack.length && undoStack.length > 0) {
|
||||
this.selectNone();
|
||||
this.clearSelection();
|
||||
var cmd = undoStack[undoStackPointer++];
|
||||
cmd.apply();
|
||||
call("changed", cmd.elem);
|
||||
}
|
||||
// console.log("after redo, stackPointer=" + undoStackPointer);
|
||||
// console.log(undoStack);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user