Skip to content

Commit 3774516

Browse files
committed
layers: add Alt+Drag duplication support in Layers panel
1 parent 00718c5 commit 3774516

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

frontend/src/components/panels/Layers.svelte

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@
6666
let justFinishedDrag = false; // Used to prevent click events after a drag
6767
let dragInPanel = false;
6868
69+
// Alt+Drag duplication
70+
let altKeyPressedDuringDrag = false;
71+
let originalLayersBeforeDuplication: bigint[] | undefined = undefined;
72+
let duplicatedLayerIds: bigint[] | undefined = undefined;
73+
6974
// Interactive clipping
7075
let layerToClipUponClick: LayerListingInfo | undefined = undefined;
7176
let layerToClipAltKeyPressed = false;
@@ -107,6 +112,8 @@
107112
addEventListener("pointermove", draggingPointerMove);
108113
addEventListener("mousedown", draggingMouseDown);
109114
addEventListener("keydown", draggingKeyDown);
115+
addEventListener("keyup", draggingKeyUp);
116+
addEventListener("blur", () => internalDragState?.active && abortDrag());
110117
111118
addEventListener("pointermove", clippingHover);
112119
addEventListener("keydown", clippingKeyPress);
@@ -124,6 +131,7 @@
124131
removeEventListener("pointermove", draggingPointerMove);
125132
removeEventListener("mousedown", draggingMouseDown);
126133
removeEventListener("keydown", draggingKeyDown);
134+
removeEventListener("keyup", draggingKeyUp);
127135
128136
removeEventListener("pointermove", clippingHover);
129137
removeEventListener("keydown", clippingKeyPress);
@@ -469,11 +477,43 @@
469477
abortDrag();
470478
}
471479
480+
async function startDuplicates() {
481+
originalLayersBeforeDuplication = [...$nodeGraph.selected];
482+
editor.handle.duplicateSelectedLayers();
483+
484+
await tick();
485+
duplicatedLayerIds = [...$nodeGraph.selected];
486+
}
487+
488+
function stopDuplicates() {
489+
if (!originalLayersBeforeDuplication || !duplicatedLayerIds) return;
490+
491+
duplicatedLayerIds.forEach(layerId => {
492+
editor.handle.deleteNode(layerId);
493+
});
494+
495+
editor.handle.deselectAllLayers();
496+
originalLayersBeforeDuplication.forEach((layerId, index) => {
497+
const ctrl = index > 0;
498+
editor.handle.selectLayer(layerId, ctrl, false);
499+
});
500+
501+
originalLayersBeforeDuplication = undefined;
502+
duplicatedLayerIds = undefined;
503+
}
504+
472505
function abortDrag() {
506+
if (altKeyPressedDuringDrag && originalLayersBeforeDuplication) {
507+
stopDuplicates();
508+
}
509+
473510
internalDragState = undefined;
474511
draggingData = undefined;
475512
fakeHighlightOfNotYetSelectedLayerBeingDragged = undefined;
476513
dragInPanel = false;
514+
altKeyPressedDuringDrag = false;
515+
originalLayersBeforeDuplication = undefined;
516+
duplicatedLayerIds = undefined;
477517
}
478518
479519
function draggingMouseDown(e: MouseEvent) {
@@ -489,6 +529,18 @@
489529
justFinishedDrag = true;
490530
abortDrag();
491531
}
532+
533+
if (e.key === "Alt" && !altKeyPressedDuringDrag) {
534+
altKeyPressedDuringDrag = true;
535+
startDuplicates();
536+
}
537+
}
538+
539+
function draggingKeyUp(e: KeyboardEvent) {
540+
if (e.key === "Alt" && altKeyPressedDuringDrag) {
541+
altKeyPressedDuringDrag = false;
542+
stopDuplicates();
543+
}
492544
}
493545
494546
function fileDragOver(e: DragEvent) {

frontend/wasm/src/editor_api.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,13 @@ impl EditorHandle {
665665
self.dispatch(message);
666666
}
667667

668+
/// Duplicate the currently selected layers
669+
#[wasm_bindgen(js_name = duplicateSelectedLayers)]
670+
pub fn duplicate_selected_layers(&self) {
671+
let message = DocumentMessage::DuplicateSelectedLayers;
672+
self.dispatch(message);
673+
}
674+
668675
/// Move a layer to within a folder and placed down at the given index.
669676
/// If the folder is `None`, it is inserted into the document root.
670677
/// If the insert index is `None`, it is inserted at the start of the folder.

0 commit comments

Comments
 (0)