Issue 73: A good deal of the plumbing is now down for layers. You can select the current layer in the layers panel and elements not on the current layer are not selectable.

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@669 eee81c28-f429-11dd-99c0-75d572ba1ddd
master
Jeff Schiller 2009-09-21 22:16:44 +00:00
parent 3a650df943
commit 18253b5e5d
3 changed files with 165 additions and 25 deletions

View File

@ -45,7 +45,9 @@
</fieldset>
<select id="layerlist" size="20" multiple="multiple">
<option value="Layer_1" selected="selected">Layer 1</option>
<option value="Layer 1" selected="selected">Layer 1</option>
<option value="Layer 2">Layer 2</option>
<option value="Layer 3">Layer 3</option>
</select>
</div>
</div>

View File

@ -742,6 +742,7 @@ function svg_edit_setup() {
}
svgCanvas.clearSelection();
hideSourceEditor();
populateLayers();
};
var saveDocProperties = function(){
@ -1068,6 +1069,22 @@ function svg_edit_setup() {
$(this).removeClass('tool_flyout_button_current');
});
var populateLayers = function(){
var layerlen = svgCanvas.getNumLayers();
$('#layerlist').empty();
for (var layer = 0; layer < layerlen; ++layer) {
var name = svgCanvas.getLayer(layer);
$('#layerlist').append("<option value=\"" + name + "\">" + name + "</option>");
}
$('#layerlist option').mouseup(function(evt){
$('#layerlist option').removeAttr("selected");
var option = $(this);
option.attr("selected", "selected");
svgCanvas.setCurrentLayer(option.attr("value"));
});
};
populateLayers();
function changeResolution(x,y) {
var new_res = x+'x'+y;
var found = false;
@ -1134,7 +1151,7 @@ function svg_edit_setup() {
svgCanvas.bind("saved", opts.save);
}
}
return svgCanvas;
};

View File

@ -1,17 +1,14 @@
/*
Issue 73 (Layers) TODO:
- when a layer option is selected, deselect all other layers
- when a layer option is double-clicked, pop up a 'rename' dialog? or provide a button?
- upon turning SVG text into a DOM, analyze all top-level <g> elements that have a <title>
and create layer options
- create a global variable for the currently selected layer, hold a reference to the <g>
- create API for SvgCanvas that allows the client to:
- change layer order
- create a layer
- delete a layer
- when New/Delete are clicked, fire off a function
- when creating a new layer, create a <g> with a <title>, set the current layer to the new one
- when deleting a layer, delete all children of the <g> and then delete the <g>
- ensure New/Delete are undo-able
- upon changing current layers, set pointer-events='none' on all elements in the old current layer
then pointer-events='all' on all elements in the newly selected layer
- create a mouseover region on the sidepanels that is resizable and affects all children within
- default the side panel to closed
- add a button that opens the side panel?
@ -594,8 +591,8 @@ function BatchCommand(text) {
svgroot.appendChild(svgzoom);
var comment = svgdoc.createComment(" created with SVG-edit - http://svg-edit.googlecode.com/ ");
svgzoom.appendChild(comment);
// associative array of layer names to <g> elements
var all_layers = {};
// z-ordered array of tuples containing layer names and <g> elements
var all_layers = [];
// pointer to the current layer <g>
var current_layer = null;
@ -1466,7 +1463,8 @@ function BatchCommand(text) {
"stroke-opacity": cur_shape.stroke_opacity,
"stroke-linecap": "round",
"stroke-linejoin": "round",
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
freehand_min_x = x;
@ -1486,7 +1484,8 @@ function BatchCommand(text) {
"width": 0,
"height": 0,
"id": getNextId(),
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
newImage.setAttributeNS(xlinkns, "href", "images/logo.png");
@ -1512,7 +1511,8 @@ function BatchCommand(text) {
"stroke-dasharray": cur_shape.stroke_style,
"stroke-opacity": cur_shape.stroke_opacity,
"fill-opacity": cur_shape.fill_opacity,
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
break;
@ -1532,7 +1532,8 @@ function BatchCommand(text) {
"stroke-dasharray": cur_shape.stroke_style,
"stroke-opacity": cur_shape.stroke_opacity,
"fill": "none",
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
break;
@ -1551,7 +1552,8 @@ function BatchCommand(text) {
"stroke-dasharray": cur_shape.stroke_style,
"stroke-opacity": cur_shape.stroke_opacity,
"fill-opacity": cur_shape.fill_opacity,
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
break;
@ -1571,7 +1573,8 @@ function BatchCommand(text) {
"stroke-dasharray": cur_shape.stroke_style,
"stroke-opacity": cur_shape.stroke_opacity,
"fill-opacity": cur_shape.fill_opacity,
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
break;
@ -1593,7 +1596,8 @@ function BatchCommand(text) {
"opacity": cur_shape.opacity,
"font-size": cur_text.font_size,
"font-family": cur_text.font_family,
"text-anchor": "middle"
"text-anchor": "middle",
"style": "pointer-events:all"
}
});
newText.textContent = "text";
@ -2034,7 +2038,7 @@ function BatchCommand(text) {
'stroke': "#00F",
'stroke-width': 2,
'cursor': 'move',
"pointer-events": "all"
'style': 'pointer-events:all'
});
pointGrip = pointGripContainer.appendChild(pointGrip);
@ -2214,7 +2218,8 @@ function BatchCommand(text) {
"stroke-dasharray": cur_shape.stroke_style,
"opacity": cur_shape.opacity,
"stroke-opacity": cur_shape.stroke_opacity,
"fill-opacity": cur_shape.fill_opacity
"fill-opacity": cur_shape.fill_opacity,
"style": "pointer-events:all"
}
});
call("changed",[element]);
@ -2238,7 +2243,8 @@ function BatchCommand(text) {
"stroke-dasharray": cur_shape.stroke_style,
"opacity": cur_shape.opacity,
"stroke-opacity": cur_shape.stroke_opacity,
"fill-opacity": cur_shape.fill_opacity
"fill-opacity": cur_shape.fill_opacity,
"style": "pointer-events:all"
}
});
call("changed",[element]);
@ -2282,7 +2288,8 @@ function BatchCommand(text) {
"stroke-width": cur_shape.stroke_width,
"stroke-dasharray": cur_shape.stroke_style,
"stroke-opacity": cur_shape.stroke_opacity,
"opacity": cur_shape.opacity / 2
"opacity": cur_shape.opacity / 2,
"style": "pointer-events:all"
}
});
// set stretchy line to first point
@ -2515,6 +2522,16 @@ function BatchCommand(text) {
call("saved", str);
};
var walkTree = function(elem, cbFn){
if (elem && elem.nodeType == 1) {
cbFn(elem);
var i = elem.childNodes.length;
while (i--) {
walkTree(elem.childNodes.item(i), cbFn);
}
}
};
this.getSvgString = function() {
return svgCanvasToString();
};
@ -2568,7 +2585,25 @@ function BatchCommand(text) {
current_zoom = 1;
// identify layers
all_layers = [];
var numchildren = svgzoom.childNodes.length;
// loop through all children of svgzoom
for (var i = 0; i < numchildren; ++i) {
var child = svgzoom.childNodes.item(i);
// for each g, find its layer name
if (child && child.tagName == "g") {
var name = getLayerName(child);
// store layer and name in global variable
if (name) {
all_layers.push( [name,child] );
current_layer = child;
walkTree(child, function(e){e.setAttribute("style", "pointer-events:none");});
}
}
}
console.dir(all_layers);
walkTree(current_layer, function(e){e.setAttribute("style","pointer-events:all");});
selectorManager.update();
addCommandToHistory(batchCmd);
@ -2581,6 +2616,92 @@ function BatchCommand(text) {
return true;
};
// Layer API Functions
// TODO: change layer order
// TODO: create a layer
// TODO: delete a layer
this.getNumLayers = function() {
return all_layers.length;
};
this.getLayer = function(i) {
if (i >= 0 && i < canvas.getNumLayers()) {
return all_layers[i][0];
}
return "";
};
this.getCurrentLayer = function() {
for (var i = 0; i < all_layers.length; ++i) {
if (all_layers[i][1] == current_layer) {
return all_layers[i][0];
}
}
return "";
};
this.setCurrentLayer = function(name) {
for (var i = 0; i < all_layers.length; ++i) {
if (name == all_layers[i][0]) {
if (current_layer != all_layers[i][1]) {
walkTree(current_layer,function(e){e.setAttribute("style","pointer-events:none");});
current_layer = all_layers[i][1];
walkTree(current_layer,function(e){e.setAttribute("style","pointer-events:all");});
}
return true;
}
}
return false;
};
this.renameLayer = function(oldname, newname) {
var rememberCurrentLayer = current_layer;
if (canvas.setCurrentLayer(oldname)) {
var oldLayer = current_layer;
// setCurrentLayer will return false if the name doesn't already exists
if (!canvas.setCurrentLayer(newname)) {
// find the index of the layer
for (var i = 0; i < all_layers.length; ++i) {
if (all_layers[i][1] == oldLayer) break;
}
all_layers[i][0] = newname;
// now change the underlying title element contents
var len = oldLayer.childNodes.length;
for (var i = 0; i < len; ++i) {
var child = oldLayer.childNodes.item(i);
// found the <title> element, now append all the
if (child && child.tagName == "title") {
// wipe out old name
// TODO: make this undo-able
while (child.firstChild) { child.removeChild(child.firstChild); }
child.appendChild( svgdoc.createTextNode(newname) );
return true;
}
}
}
}
return false;
};
// used internally
var getLayerName = function(g) {
var name = "";
if (g && g.tagName == "g") {
var len = g.childNodes.length;
for (var i = 0; i < len; ++i) {
var child = g.childNodes.item(i);
// found the <title> element, now append all the
if (child && child.tagName == "title") {
var tlen = child.childNodes.length;
for (var j = 0; j < tlen; ++j) {
var textNode = child.childNodes.item(j);
if (textNode.nodeType == 3) {
name += textNode.nodeValue;
}
}
break;
}
}
}
return name;
};
this.clear = function() {
current_poly_pts = [];
@ -2602,8 +2723,8 @@ function BatchCommand(text) {
layer_title.appendChild(svgdoc.createTextNode("Layer 1"));
current_layer.appendChild(layer_title);
current_layer = svgzoom.appendChild(current_layer);
all_layers = {};
all_layers["Layer 1"] = current_layer;
all_layers = [];
all_layers[0] = ["Layer 1",current_layer];
// clear the undo stack
resetUndoStack();