diff --git a/js/Canvas.js b/js/Canvas.js index c14af8b..a6f6890 100644 --- a/js/Canvas.js +++ b/js/Canvas.js @@ -373,6 +373,7 @@ export class Canvas { */ updateSelectionLogic(layer, isCtrlPressed, isShiftPressed, index) { let newSelection = [...this.selectedLayers]; + let selectionChanged = false; if (isShiftPressed && this.canvasLayersPanel.lastSelectedIndex !== -1) { const sortedLayers = [...this.layers].sort((a, b) => b.zIndex - a.zIndex); @@ -385,6 +386,7 @@ export class Canvas { newSelection.push(sortedLayers[i]); } } + selectionChanged = true; } else if (isCtrlPressed) { const layerIndex = newSelection.indexOf(layer); if (layerIndex === -1) { @@ -392,12 +394,24 @@ export class Canvas { } else { newSelection.splice(layerIndex, 1); } + this.canvasLayersPanel.lastSelectedIndex = index; + selectionChanged = true; } else { - newSelection = [layer]; + // Jeśli kliknięta warstwa nie jest częścią obecnego zaznaczenia, + // wyczyść zaznaczenie i zaznacz tylko ją. + if (!this.selectedLayers.includes(layer)) { + newSelection = [layer]; + selectionChanged = true; + } + // Jeśli kliknięta warstwa JEST już zaznaczona (potencjalnie z innymi), + // NIE rób nic, aby umożliwić przeciąganie całej grupy. this.canvasLayersPanel.lastSelectedIndex = index; } - this.updateSelection(newSelection); + // Aktualizuj zaznaczenie tylko jeśli faktycznie się zmieniło + if (selectionChanged) { + this.updateSelection(newSelection); + } } /** diff --git a/js/CanvasLayers.js b/js/CanvasLayers.js index bb55b61..c4a2332 100644 --- a/js/CanvasLayers.js +++ b/js/CanvasLayers.js @@ -200,40 +200,93 @@ export class CanvasLayers { return this.addLayerWithImage(image); } - moveLayerUp() { - if (this.canvas.selectedLayers.length === 0) return; - const selectedIndicesSet = new Set(this.canvas.selectedLayers.map(layer => this.canvas.layers.indexOf(layer))); + /** + * Centralna funkcja do przesuwania warstw. + * @param {Array} layersToMove - Tablica warstw do przesunięcia. + * @param {Object} options - Opcje przesunięcia, np. { direction: 'up' } lub { toIndex: 3 } + */ + moveLayers(layersToMove, options = {}) { + if (!layersToMove || layersToMove.length === 0) return; - const sortedIndices = Array.from(selectedIndicesSet).sort((a, b) => b - a); + let finalLayers; - sortedIndices.forEach(index => { - const targetIndex = index + 1; - - if (targetIndex < this.canvas.layers.length && !selectedIndicesSet.has(targetIndex)) { - [this.canvas.layers[index], this.canvas.layers[targetIndex]] = [this.canvas.layers[targetIndex], this.canvas.layers[index]]; + if (options.direction) { + // Logika dla 'up' i 'down' + const allLayers = [...this.canvas.layers]; + const selectedIndices = new Set(layersToMove.map(l => allLayers.indexOf(l))); + + if (options.direction === 'up') { + const sorted = Array.from(selectedIndices).sort((a, b) => b - a); + sorted.forEach(index => { + const targetIndex = index + 1; + if (targetIndex < allLayers.length && !selectedIndices.has(targetIndex)) { + [allLayers[index], allLayers[targetIndex]] = [allLayers[targetIndex], allLayers[index]]; + } + }); + } else if (options.direction === 'down') { + const sorted = Array.from(selectedIndices).sort((a, b) => a - b); + sorted.forEach(index => { + const targetIndex = index - 1; + if (targetIndex >= 0 && !selectedIndices.has(targetIndex)) { + [allLayers[index], allLayers[targetIndex]] = [allLayers[targetIndex], allLayers[index]]; + } + }); } + finalLayers = allLayers; + + } else if (options.toIndex !== undefined) { + // Logika dla przeciągania i upuszczania (z panelu) + const displayedLayers = [...this.canvas.layers].sort((a, b) => b.zIndex - a.zIndex); + const reorderedFinal = []; + let inserted = false; + + for (let i = 0; i < displayedLayers.length; i++) { + if (i === options.toIndex) { + reorderedFinal.push(...layersToMove); + inserted = true; + } + const currentLayer = displayedLayers[i]; + if (!layersToMove.includes(currentLayer)) { + reorderedFinal.push(currentLayer); + } + } + if (!inserted) { + reorderedFinal.push(...layersToMove); + } + finalLayers = reorderedFinal; + } else { + log.warn("Invalid options for moveLayers", options); + return; + } + + // Zunifikowana końcówka: aktualizacja zIndex i stanu aplikacji + const totalLayers = finalLayers.length; + finalLayers.forEach((layer, index) => { + // Jeśli przyszły z panelu, zIndex jest odwrócony + const zIndex = (options.toIndex !== undefined) ? (totalLayers - 1 - index) : index; + layer.zIndex = zIndex; }); - this.canvas.layers.forEach((layer, i) => layer.zIndex = i); + + this.canvas.layers = finalLayers; + this.canvas.layers.sort((a, b) => a.zIndex - b.zIndex); + + if (this.canvas.canvasLayersPanel) { + this.canvas.canvasLayersPanel.onLayersChanged(); + } + this.canvas.render(); this.canvas.saveState(); + log.info(`Moved ${layersToMove.length} layer(s).`); + } + + moveLayerUp() { + if (this.canvas.selectedLayers.length === 0) return; + this.moveLayers(this.canvas.selectedLayers, { direction: 'up' }); } moveLayerDown() { if (this.canvas.selectedLayers.length === 0) return; - const selectedIndicesSet = new Set(this.canvas.selectedLayers.map(layer => this.canvas.layers.indexOf(layer))); - - const sortedIndices = Array.from(selectedIndicesSet).sort((a, b) => a - b); - - sortedIndices.forEach(index => { - const targetIndex = index - 1; - - if (targetIndex >= 0 && !selectedIndicesSet.has(targetIndex)) { - [this.canvas.layers[index], this.canvas.layers[targetIndex]] = [this.canvas.layers[targetIndex], this.canvas.layers[index]]; - } - }); - this.canvas.layers.forEach((layer, i) => layer.zIndex = i); - this.canvas.render(); - this.canvas.saveState(); + this.moveLayers(this.canvas.selectedLayers, { direction: 'down' }); } /** diff --git a/js/CanvasLayersPanel.js b/js/CanvasLayersPanel.js index 41fe843..77b0ca8 100644 --- a/js/CanvasLayersPanel.js +++ b/js/CanvasLayersPanel.js @@ -365,12 +365,11 @@ export class CanvasLayersPanel { * Konfiguruje event listenery dla elementu warstwy */ setupLayerEventListeners(layerRow, layer, index) { - // Click handler - natychmiastowe zaznaczanie - layerRow.addEventListener('click', (e) => { + // Mousedown handler - zaznaczanie w momencie wciśnięcia przycisku + layerRow.addEventListener('mousedown', (e) => { + // Ignoruj, jeśli edytujemy nazwę const nameElement = layerRow.querySelector('.layer-name'); if (nameElement && nameElement.classList.contains('editing')) { - e.preventDefault(); - e.stopPropagation(); return; } this.handleLayerClick(e, layer, index); @@ -395,9 +394,6 @@ export class CanvasLayersPanel { * Obsługuje kliknięcie na warstwę, aktualizując stan bez pełnego renderowania. */ handleLayerClick(e, layer, index) { - // Zatrzymujemy, bo dblclick też wywołałby click - e.preventDefault(); - const isCtrlPressed = e.ctrlKey || e.metaKey; const isShiftPressed = e.shiftKey; @@ -599,7 +595,8 @@ export class CanvasLayersPanel { insertIndex = targetIndex + 1; } - this.moveLayersToPosition(this.draggedElements, insertIndex); + // Użyj nowej, centralnej funkcji do przesuwania warstw + this.canvas.canvasLayers.moveLayers(this.draggedElements, { toIndex: insertIndex }); log.info(`Dropped ${this.draggedElements.length} layers at position ${insertIndex}`); } @@ -618,29 +615,6 @@ export class CanvasLayersPanel { this.draggedElements = []; } - /** - * Przenosi warstwy na nową pozycję - */ - moveLayersToPosition(layers, insertIndex) { - const sortedLayers = [...this.canvas.layers].sort((a, b) => a.zIndex - b.zIndex); - - // Usuń przeciągane warstwy z listy - const filteredLayers = sortedLayers.filter(layer => !layers.includes(layer)); - - // Wstaw warstwy w nowej pozycji (odwróć kolejność bo renderujemy od góry) - const reverseInsertIndex = filteredLayers.length - insertIndex; - filteredLayers.splice(reverseInsertIndex, 0, ...layers); - - // Zaktualizuj zIndex dla wszystkich warstw - filteredLayers.forEach((layer, index) => { - layer.zIndex = index; - }); - - this.canvas.layers = filteredLayers; - this.canvas.render(); - this.renderLayers(); - this.canvas.saveState(); - } /** * Aktualizuje panel gdy zmienią się warstwy