From 279a529b92aa48c379a061d1fcf028b962eb4f5b Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 24 May 2026 15:07:09 -0400 Subject: [PATCH] Add layer panel range selection --- src/index.html | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/index.html b/src/index.html index 997338c..379f750 100644 --- a/src/index.html +++ b/src/index.html @@ -9661,7 +9661,7 @@ const groupTag = groupName ? `GRP` : ''; item.innerHTML = `${lockTag}${groupTag}${escapeHtml(displayName)}${escapeHtml(layer.type)}`; item.addEventListener('click', (event) => { - selectLayerWithEvent(layer.id, event); + selectLayerPanelEntry('layer', layer.id, event); render(); }); const eye = document.createElement('button'); @@ -9707,7 +9707,7 @@ const name = group.name || 'Layer group'; button.innerHTML = `📁 ${escapeHtml(name)}${layers.length} layer${layers.length === 1 ? '' : 's'}`; button.addEventListener('click', (event) => { - selectLayerGroupWithEvent(groupId, event); + selectLayerPanelEntry('group', groupId, event); render(); }); @@ -11180,6 +11180,80 @@ setLayerSelection([]); } + let _layerPanelSelectionAnchor = null; + + function layerPanelRowsFromOrderedLayers(orderedLayers) { + const rows = []; + const renderedGroups = new Set(); + for (const layer of orderedLayers) { + if (layer.groupId) { + if (renderedGroups.has(layer.groupId)) continue; + const groupLayers = orderedLayers.filter(l => l.groupId === layer.groupId); + renderedGroups.add(layer.groupId); + rows.push({ key: `group:${layer.groupId}`, type: 'group', id: layer.groupId, layerIds: groupLayers.map(l => l.id) }); + const group = ensureLayerGroups()[layer.groupId] || {}; + if (!group.collapsed) { + for (const child of groupLayers) rows.push({ key: `layer:${child.id}`, type: 'layer', id: child.id, layerIds: [child.id] }); + } + } else { + rows.push({ key: `layer:${layer.id}`, type: 'layer', id: layer.id, layerIds: [layer.id] }); + } + } + return rows; + } + + function visibleLayerPanelRows() { + if (state.appMode === 'designer') { + const listedLayers = (state.layers || []) + .filter(layer => layer.target === 'designer-disc' && !layer._generatedDiscLayer) + .sort((a, b) => (b.z || 0) - (a.z || 0)); + return layerPanelRowsFromOrderedLayers(listedLayers); + } + const rows = []; + const targetLayers = (state.layers || []).filter(layer => layer.target !== 'designer-disc' && !layer._generatedDiscLayer); + for (const targetDef of templateLayerTargetsForMode()) { + const matchKeys = targetDef.matchKeys || [targetDef.key]; + const ordered = targetLayers + .filter(layer => matchKeys.includes(layer.target)) + .sort((a, b) => (b.z || 0) - (a.z || 0)); + rows.push(...layerPanelRowsFromOrderedLayers(ordered)); + } + return rows; + } + + function selectLayerPanelEntry(kind, id, event) { + const key = `${kind}:${id}`; + const rows = visibleLayerPanelRows(); + const row = rows.find(item => item.key === key); + if (!row) return; + const additive = !!(event && (event.ctrlKey || event.metaKey)); + const range = !!(event && event.shiftKey); + if (range && _layerPanelSelectionAnchor) { + const a = rows.findIndex(item => item.key === _layerPanelSelectionAnchor.key); + const b = rows.findIndex(item => item.key === key); + if (a !== -1 && b !== -1) { + const [from, to] = a < b ? [a, b] : [b, a]; + const rangeIds = rows.slice(from, to + 1).flatMap(item => item.layerIds); + const nextIds = additive ? [...selectedLayerIds(), ...rangeIds] : rangeIds; + setLayerSelection(nextIds, row.layerIds[row.layerIds.length - 1] || ''); + return; + } + } + if (additive) { + const current = selectedLayerIds(); + const allSelected = row.layerIds.every(layerId => current.includes(layerId)); + if (allSelected) { + const remove = new Set(row.layerIds); + setLayerSelection(current.filter(layerId => !remove.has(layerId))); + } else { + setLayerSelection([...current, ...row.layerIds], row.layerIds[row.layerIds.length - 1] || ''); + } + } else { + setLayerSelection(row.layerIds, row.layerIds[row.layerIds.length - 1] || ''); + } + _layerPanelSelectionAnchor = { key }; + } + let _pendingLayerGroupIds = []; function openLayerGroupModal() { @@ -19309,7 +19383,7 @@ if (k === 'enter' && _penDraft && _penDraft.tool === 'pen') { e.preventDefault(); finishPenPath(false); return; } if (!_penDraft) { if (k === 'delete' || k === 'backspace') { - if (state.selectedLayerId) { e.preventDefault(); deleteSelectedLayer(); } + if (selectedLayerIds().length) { e.preventDefault(); deleteSelectedLayer(); } return; } const layer = selectedLayer();