From 8345aa43d147ee66efe1113e2b182b270151de72 Mon Sep 17 00:00:00 2001 From: Alexis Deveria Date: Thu, 19 Aug 2010 18:30:19 +0000 Subject: [PATCH] Fixed issue 226 and issue 393, allowing the cloning and merging of layers git-svn-id: http://svg-edit.googlecode.com/svn/trunk@1672 eee81c28-f429-11dd-99c0-75d572ba1ddd --- editor/contextmenu/jquery.contextMenu.js | 6 +- editor/images/svg_edit_icons.svg | 12 +++ editor/svg-editor.css | 8 +- editor/svg-editor.html | 9 ++ editor/svg-editor.js | 125 +++++++++++++++-------- editor/svgcanvas.js | 90 +++++++++++++++- 6 files changed, 200 insertions(+), 50 deletions(-) diff --git a/editor/contextmenu/jquery.contextMenu.js b/editor/contextmenu/jquery.contextMenu.js index b6187aa0..75b79491 100755 --- a/editor/contextmenu/jquery.contextMenu.js +++ b/editor/contextmenu/jquery.contextMenu.js @@ -36,7 +36,7 @@ if(jQuery)( function() { $(this).mouseup( function(e) { var srcElement = $(this); $(this).unbind('mouseup'); - if( evt.button == 2 ) { + if( evt.button == 2 || o.allowLeft) { e.stopPropagation(); // Hide context menus that may be showing $(".contextMenu").hide(); @@ -51,8 +51,8 @@ if(jQuery)( function() { var x_off = $(window).width() - menu.width(), y_off = $(window).height() - menu.height(); - if(x > x_off) x = x_off-5; - if(y > y_off) y = y_off-5; + if(x > x_off) x = x_off-15; + if(y > y_off) y = y_off-15; // Show the menu $(document).unbind('click'); diff --git a/editor/images/svg_edit_icons.svg b/editor/images/svg_edit_icons.svg index 26959c20..78e72f24 100644 --- a/editor/images/svg_edit_icons.svg +++ b/editor/images/svg_edit_icons.svg @@ -540,6 +540,18 @@ + + + + + + + + + + + + diff --git a/editor/svg-editor.css b/editor/svg-editor.css index 237cc270..81c650b0 100644 --- a/editor/svg-editor.css +++ b/editor/svg-editor.css @@ -190,7 +190,7 @@ padding: 0px; padding-left: 2px; padding-right: 2px; - width: 106px; + width: 123px; height: 20px; border-right: 1px solid #FFFFFF; border-bottom: 1px solid #FFFFFF; @@ -212,6 +212,10 @@ margin-right: 3px; } +#svg_editor .layer_button:last-child { + margin-right: 0; +} + #svg_editor .layer_buttonpressed { width: 14px; height: 14px; @@ -226,7 +230,7 @@ #svg_editor #layerlist { margin: 1px; padding: 0px; - width: 110px; + width: 127px; border-collapse: collapse; border: 1px solid #808080; background-color: #FFFFFF; diff --git a/editor/svg-editor.html b/editor/svg-editor.html index 54f0e660..0aabe07a 100644 --- a/editor/svg-editor.html +++ b/editor/svg-editor.html @@ -62,6 +62,7 @@ script type="text/javascript" src="locale/locale.min.js">
+
@@ -674,5 +675,13 @@ script type="text/javascript" src="locale/locale.min.js">
  • Delete
  • + + + diff --git a/editor/svg-editor.js b/editor/svg-editor.js index efa9ddef..a5c4f873 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -355,6 +355,7 @@ '#layer_up':'go_up', '#layer_down':'go_down', + '#layer_moreopts':'context_menu', '#layerlist td.layervis':'eye', '#tool_source_save,#tool_docprops_save':'ok', @@ -443,6 +444,7 @@ default_img_url = curConfig.imgPath + "logo.png", workarea = $("#workarea"), canv_menu = $("#cmenu_canvas"), + layer_menu = $("#cmenu_layers"), show_save_warning = false, exportWindow = null, tool_scale = 1; @@ -3174,30 +3176,24 @@ }); $('#layer_new').click(function() { - var curNames = new Array(svgCanvas.getNumLayers()); - for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getLayer(i); } + var i = svgCanvas.getNumLayers(); + do { + var uniqName = uiStrings.layer + " " + ++i; + } while(svgCanvas.hasLayer(uniqName)); - var j = (curNames.length+1); - var uniqName = uiStrings.layer + " " + j; - while ($.inArray(uniqName, curNames) != -1) { - j++; - uniqName = uiStrings.layer + " " + j; - } $.prompt(uiStrings.enterUniqueLayerName,uniqName, function(newName) { if (!newName) return; - if ($.inArray(newName, curNames) != -1) { + if (svgCanvas.hasLayer(newName)) { $.alert(uiStrings.dupeLayerName); return; } svgCanvas.createLayer(newName); updateContextPanel(); populateLayers(); - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:first').addClass("layersel"); }); }); - $('#layer_delete').click(function() { + function deleteLayer() { if (svgCanvas.deleteCurrentLayer()) { updateContextPanel(); populateLayers(); @@ -3207,55 +3203,62 @@ $('#layerlist tr.layer').removeClass("layersel"); $('#layerlist tr.layer:first').addClass("layersel"); } - }); + } - $('#layer_up').click(function() { - // find index position of selected option - var curIndex = $('#layerlist tr.layersel').prevAll().length; - if (curIndex > 0) { - var total = $('#layerlist tr.layer').length; - curIndex--; + function cloneLayer() { + var name = svgCanvas.getCurrentLayer() + ' copy'; + + $.prompt(uiStrings.enterUniqueLayerName, name, function(newName) { + if (!newName) return; + if (svgCanvas.hasLayer(newName)) { + $.alert(uiStrings.dupeLayerName); + return; + } + svgCanvas.cloneLayer(newName); + updateContextPanel(); + populateLayers(); + }); + } + + function mergeLayer() { + if($('#layerlist tr.layersel').index() == svgCanvas.getNumLayers()-1) return; + svgCanvas.mergeLayer(); + updateContextPanel(); + populateLayers(); + } + + function moveLayer(pos) { + var curIndex = $('#layerlist tr.layersel').index(); + var total = svgCanvas.getNumLayers(); + if(curIndex > 0 || curIndex < total-1) { + curIndex += pos; svgCanvas.setCurrentLayerPosition(total-curIndex-1); populateLayers(); - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:eq('+curIndex+')').addClass("layersel"); } + } + + $('#layer_delete').click(deleteLayer); + + $('#layer_up').click(function() { + moveLayer(-1); }); $('#layer_down').click(function() { - // find index position of selected option - var curIndex = $('#layerlist tr.layersel').prevAll().length; - var total = $('#layerlist tr.layer').length; - if (curIndex < total-1) { - curIndex++; - svgCanvas.setCurrentLayerPosition(total-curIndex-1); - populateLayers(); - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:eq('+curIndex+')').addClass("layersel"); - } + moveLayer(1); }); - + $('#layer_rename').click(function() { var curIndex = $('#layerlist tr.layersel').prevAll().length; var oldName = $('#layerlist tr.layersel td.layername').text(); $.prompt(uiStrings.enterNewLayerName,"", function(newName) { if (!newName) return; - if (oldName == newName) { - $.alert(uiStrings.layerHasThatName); - return; - } - - var curNames = new Array(svgCanvas.getNumLayers()); - for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getLayer(i); } - if ($.inArray(newName, curNames) != -1) { + if (oldName == newName || svgCanvas.hasLayer(newName)) { $.alert(uiStrings.layerHasThatName); return; } svgCanvas.renameCurrentLayer(newName); populateLayers(); - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:eq('+curIndex+')').addClass("layersel"); }); }); @@ -3377,7 +3380,7 @@ } // handle selection of layer $('#layerlist td.layername') - .click(function(evt){ + .mouseup(function(evt){ $('#layerlist tr.layer').removeClass("layersel"); var row = $(this.parentNode); row.addClass("layersel"); @@ -3750,7 +3753,41 @@ if(svgCanvas.clipBoard.length) { canv_menu.enableContextMenuItems('#paste,#paste_in_place'); } - }); + }); + + var lmenu_func = function(action, el, pos) { + switch ( action ) { + case 'dupe': + cloneLayer(); + break; + case 'delete': + deleteLayer(); + break; + case 'merge_down': + mergeLayer(); + break; + case 'merge_all': + svgCanvas.mergeAllLayers(); + updateContextPanel(); + populateLayers(); + break; + } + } + + $("#layerlist").contextMenu({ + menu: 'cmenu_layers', + inSpeed: 0 + }, + lmenu_func + ); + + $("#layer_moreopts").contextMenu({ + menu: 'cmenu_layers', + inSpeed: 0, + allowLeft: true + }, + lmenu_func + ); $('.contextMenu li').mousedown(function(ev) { ev.preventDefault(); diff --git a/editor/svgcanvas.js b/editor/svgcanvas.js index de72146b..fb0c0fdd 100644 --- a/editor/svgcanvas.js +++ b/editor/svgcanvas.js @@ -826,7 +826,7 @@ var RemoveElementCommand = this.undoCmd.removeElement = function(elem, parent, t delete svgTransformLists[this.elem.id]; } - this.elem = this.parent.insertBefore(this.elem, this.elem.nextSibling); + this.elem = this.parent.insertBefore(this.elem, this.elem.nextSibling); if (this.parent == svgcontent) { identifyLayers(); } @@ -8344,6 +8344,36 @@ this.createLayer = function(name) { call("changed", [new_layer]); }; +// Function: cloneLayer +// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents +// to it, and then clears the selection This function then calls the 'changed' handler. +// This is an undoable action. +// +// Parameters: +// name - The given name +this.cloneLayer = function(name) { + var batchCmd = new BatchCommand("Duplicate Layer"); + var new_layer = svgdoc.createElementNS(svgns, "g"); + var layer_title = svgdoc.createElementNS(svgns, "title"); + layer_title.textContent = name; + new_layer.appendChild(layer_title); + $(current_layer).after(new_layer); + var childs = current_layer.childNodes; + for(var i = 0; i < childs.length; i++) { + var ch = childs[i]; + if(ch.localName == 'title') continue; + new_layer.appendChild(copyElem(ch)); + } + + clearSelection(); + identifyLayers(); + + batchCmd.addSubCommand(new InsertElementCommand(new_layer)); + addCommandToHistory(batchCmd); + canvas.setCurrentLayer(name); + call("changed", [new_layer]); +}; + // Function: deleteCurrentLayer // Deletes the current layer from the drawing and then clears the selection. This function // then calls the 'changed' handler. This is an undoable action. @@ -8364,6 +8394,15 @@ this.deleteCurrentLayer = function() { return false; }; +// Function: hasLayer +// Check if layer with given name already exists +this.hasLayer = function(name) { + for(var i = 0; i < all_layers.length; i++) { + if(all_layers[i][0] == name) return true; + } + return false; +}; + // Function: getNumLayers // Returns the number of layers in the current drawing. // @@ -8615,6 +8654,55 @@ this.moveSelectedToLayer = function(layername) { return true; }; +this.mergeLayer = function(skipHistory) { + var batchCmd = new BatchCommand("Merge Layer"); + var prev = $(current_layer).prev()[0]; + if(!prev) return; + var childs = current_layer.childNodes; + var len = childs.length; + batchCmd.addSubCommand(new RemoveElementCommand(current_layer, svgcontent)); + + while(current_layer.firstChild) { + var ch = current_layer.firstChild; + if(ch.localName == 'title') { + batchCmd.addSubCommand(new RemoveElementCommand(ch, current_layer)); + current_layer.removeChild(ch); + continue; + } + var oldNextSibling = ch.nextSibling; + prev.appendChild(ch); + batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, current_layer)); + } + + // Remove current layer + svgcontent.removeChild(current_layer); + + if(!skipHistory) { + clearSelection(); + identifyLayers(); + + call("changed", [svgcontent]); + + addCommandToHistory(batchCmd); + } + + current_layer = prev; + return batchCmd; +} + +this.mergeAllLayers = function() { + var batchCmd = new BatchCommand("Merge all Layers"); + current_layer = all_layers[all_layers.length-1][1]; + while($(svgcontent).children('g').length > 1) { + batchCmd.addSubCommand(canvas.mergeLayer(true)); + } + + clearSelection(); + identifyLayers(); + call("changed", [svgcontent]); + addCommandToHistory(batchCmd); +} + // Function: getLayerOpacity // Returns the opacity of the given layer. If the input name is not a layer, null is returned. //