mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-14 20:22:22 +02:00
97 lines
3.8 KiB
JavaScript
97 lines
3.8 KiB
JavaScript
/** Shared multi-layer selection semantics for panel and canvas tools. */
|
|
import { isLayerEffectivelyLocked } from './layer-groups.js';
|
|
|
|
function existingIds(editorState) {
|
|
return new Set((editorState.layers || []).map(layer => layer.id));
|
|
}
|
|
|
|
export function normalizeLayerSelection(editorState) {
|
|
const valid = existingIds(editorState);
|
|
const selected = [];
|
|
for (const id of editorState.selectedLayerIds || []) {
|
|
if (valid.has(id) && !selected.includes(id)) selected.push(id);
|
|
}
|
|
if (valid.has(editorState.activeLayerId) && !selected.includes(editorState.activeLayerId)) {
|
|
selected.length = 0;
|
|
selected.push(editorState.activeLayerId);
|
|
editorState.activeGroupId = null;
|
|
}
|
|
if (!selected.length && editorState.layers?.length) {
|
|
const fallback = editorState.layers[editorState.layers.length - 1];
|
|
editorState.activeLayerId = fallback.id;
|
|
selected.push(fallback.id);
|
|
editorState.activeGroupId = null;
|
|
}
|
|
editorState.selectedLayerIds = selected;
|
|
if (!valid.has(editorState.selectionAnchorId)) {
|
|
editorState.selectionAnchorId = editorState.activeLayerId || null;
|
|
}
|
|
return selected;
|
|
}
|
|
|
|
export function selectedLayers(editorState, { unlockedOnly = false } = {}) {
|
|
const ids = new Set(normalizeLayerSelection(editorState));
|
|
return (editorState.layers || []).filter(layer =>
|
|
ids.has(layer.id) && (!unlockedOnly || !isLayerEffectivelyLocked(editorState, layer))
|
|
);
|
|
}
|
|
|
|
export function selectOnlyLayer(editorState, layerId) {
|
|
if (!(editorState.layers || []).some(layer => layer.id === layerId)) return [];
|
|
editorState.activeLayerId = layerId;
|
|
editorState.selectionAnchorId = layerId;
|
|
editorState.selectedLayerIds = [layerId];
|
|
editorState.activeGroupId = null;
|
|
return editorState.selectedLayerIds;
|
|
}
|
|
|
|
export function toggleLayerSelection(editorState, layerId) {
|
|
const valid = (editorState.layers || []).some(layer => layer.id === layerId);
|
|
if (!valid) return normalizeLayerSelection(editorState);
|
|
const selected = normalizeLayerSelection(editorState);
|
|
const index = selected.indexOf(layerId);
|
|
if (index >= 0 && selected.length > 1) {
|
|
selected.splice(index, 1);
|
|
if (editorState.activeLayerId === layerId) {
|
|
editorState.activeLayerId = selected[selected.length - 1];
|
|
}
|
|
} else if (index < 0) {
|
|
selected.push(layerId);
|
|
editorState.activeLayerId = layerId;
|
|
}
|
|
editorState.selectionAnchorId = layerId;
|
|
editorState.selectedLayerIds = selected;
|
|
editorState.activeGroupId = null;
|
|
return selected;
|
|
}
|
|
|
|
export function selectLayerRange(editorState, layerId) {
|
|
const layers = editorState.layers || [];
|
|
const target = layers.findIndex(layer => layer.id === layerId);
|
|
if (target < 0) return normalizeLayerSelection(editorState);
|
|
const anchorId = editorState.selectionAnchorId || editorState.activeLayerId || layerId;
|
|
const anchor = layers.findIndex(layer => layer.id === anchorId);
|
|
if (anchor < 0) return selectOnlyLayer(editorState, layerId);
|
|
const start = Math.min(anchor, target);
|
|
const end = Math.max(anchor, target);
|
|
editorState.selectedLayerIds = layers.slice(start, end + 1).map(layer => layer.id);
|
|
editorState.activeLayerId = layerId;
|
|
editorState.activeGroupId = null;
|
|
return editorState.selectedLayerIds;
|
|
}
|
|
|
|
export function selectAllLayers(editorState) {
|
|
editorState.selectedLayerIds = (editorState.layers || []).map(layer => layer.id);
|
|
if (editorState.selectedLayerIds.length && !editorState.selectedLayerIds.includes(editorState.activeLayerId)) {
|
|
editorState.activeLayerId = editorState.selectedLayerIds[editorState.selectedLayerIds.length - 1];
|
|
}
|
|
editorState.selectionAnchorId = editorState.activeLayerId || null;
|
|
editorState.activeGroupId = null;
|
|
return editorState.selectedLayerIds;
|
|
}
|
|
|
|
export function selectionLabel(editorState, singular = 'layer') {
|
|
const count = normalizeLayerSelection(editorState).length;
|
|
return count === 1 ? singular : `${count} layers`;
|
|
}
|