diff --git a/README.md b/README.md index 09ce2bd..a76f77e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ComfyUI canvas editor page ## Updates + - 2023-12-4 Added hotkeys for Brush Radius, Added Duplicate Layer button. Ctrl-Click duplicates the target layer. - 2023-12-2 Added Trigger Queue on change toggle. - 2023-11-30 Added "Replace Targeted Layer" as an input mode, right click on a layer to set it as target to be replaced diff --git a/web/page/bspaint.js b/web/page/bspaint.js index 4e12bab..3d6a429 100644 --- a/web/page/bspaint.js +++ b/web/page/bspaint.js @@ -393,6 +393,22 @@ function createDrawArea(canvas = blankCanvas()) { this.updateLayerList(newList); return newLayer; }, + addDuplicateLayer(layer) { + if (!layer) { + return this.addEmptyLayer(); + } else { + // Duplicate the provided layer + const newLayer = new Layer(this, layer.title, {width: layer.canvas.width, height: layer.canvas.height}, layer.mask); + newLayer.ctx.drawImage(layer.canvas, 0, 0); // Copy the content of the original layer + newLayer.visible = layer.visible; + newLayer.compositeOperation = layer.compositeOperation; + newLayer.opacity = layer.opacity; + const newList = [...this.layers, newLayer]; + this.updateLayerList(newList); + return newLayer; + } + + }, removeLayer(layer = this.activeLayer) { const newList = layers.filter(l => l !== layer); this.updateLayerList(newList); @@ -1035,8 +1051,9 @@ function poulateLayerControl() {
-
-
+
+
+
`) @@ -1066,6 +1083,13 @@ function poulateLayerControl() { updateLayerList(); }); + $(".duplicate_layer").on("click",e=>{ + const layer = e.ctrlKey?targetLayer:activePic.activeLayer; + activePic.activeLayer = activePic.addDuplicateLayer(layer); + activePic.updateVisualRepresentation(); + updateLayerList(); + }); + $(".remove_layer").on("click",_=>{ activePic?.removeLayer(activePic.activeLayer) activePic?.updateVisualRepresentation(true) diff --git a/web/page/style.css b/web/page/style.css index 1da06da..9edb043 100644 --- a/web/page/style.css +++ b/web/page/style.css @@ -529,6 +529,18 @@ input[type="color"] { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-12 -12 24 24'%3E%3Cpath d='M -1 7 H 1 V 1 H 7 V -1 H 1 V -7 H -1 V -1 H -7 V 1 H -1' fill='%2300000080'/%3E%3C/svg%3E") } + +.layer_actions .duplicate_layer { + position:absolute; + + width:24px; + height:24px; + left:32px; + bottom:0px; + box-sizing: border-box; + + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24'%3E%3Cpath d='m3 9c0-1 1-2 2-2h8c1 0 2 1 2 2v11c0 1-1 2-2 2h-8c-1 0-2-1-2-2v-11m3-1c-1.5 0-2 .5-2 2v9c0 1.5.5 2 2 2h6c1.5 0 2-.5 2-2v-9c0-1.5-.5-2-2-2zm1-1v-2c0-1 1-2 2-2h8c1 0 2 1 2 2v11c0 1-1 2-2 2h-2v-1h1c1.5 0 2-.5 2-2v-9c0-1.5-.5-2-2-2h-6c-1.5 0-2 .5-2 2v1z' fill='%2300000080'/%3E%3C/svg%3E") +} input.maskColor {