Files
Comfyui-LayerForge/js/CanvasSelection.js
Dariusz L f36f91487f Replace alert with notification utilities and refactor canvas creation
Replaces all uses of alert() with showErrorNotification or showSuccessNotification for improved user experience and consistency. Refactors canvas creation to use the createCanvas utility function across multiple files, reducing code duplication and improving maintainability. Also updates layer ID generation to use generateUUID.
2025-07-27 19:12:25 +02:00

149 lines
6.2 KiB
JavaScript

import { createModuleLogger } from "./utils/LoggerUtils.js";
import { generateUUID } from "./utils/CommonUtils.js";
const log = createModuleLogger('CanvasSelection');
export class CanvasSelection {
constructor(canvas) {
this.canvas = canvas;
this.selectedLayers = [];
this.selectedLayer = null;
this.onSelectionChange = null;
}
/**
* Duplikuje zaznaczone warstwy (w pamięci, bez zapisu stanu)
*/
duplicateSelectedLayers() {
if (this.selectedLayers.length === 0)
return [];
const newLayers = [];
const sortedLayers = [...this.selectedLayers].sort((a, b) => a.zIndex - b.zIndex);
sortedLayers.forEach(layer => {
const newLayer = {
...layer,
id: generateUUID(),
zIndex: this.canvas.layers.length, // Nowa warstwa zawsze na wierzchu
};
this.canvas.layers.push(newLayer);
newLayers.push(newLayer);
});
// Aktualizuj zaznaczenie, co powiadomi panel (ale nie renderuje go całego)
this.updateSelection(newLayers);
// Powiadom panel o zmianie struktury, aby się przerysował
if (this.canvas.canvasLayersPanel) {
this.canvas.canvasLayersPanel.onLayersChanged();
}
log.info(`Duplicated ${newLayers.length} layers (in-memory).`);
return newLayers;
}
/**
* Aktualizuje zaznaczenie warstw i powiadamia wszystkie komponenty.
* To jest "jedyne źródło prawdy" o zmianie zaznaczenia.
* @param {Array} newSelection - Nowa lista zaznaczonych warstw
*/
updateSelection(newSelection) {
const previousSelection = this.selectedLayers.length;
// Filter out invisible layers from selection
this.selectedLayers = (newSelection || []).filter((layer) => layer.visible !== false);
this.selectedLayer = this.selectedLayers.length > 0 ? this.selectedLayers[this.selectedLayers.length - 1] : null;
// Sprawdź, czy zaznaczenie faktycznie się zmieniło, aby uniknąć pętli
const hasChanged = previousSelection !== this.selectedLayers.length ||
this.selectedLayers.some((layer, i) => this.selectedLayers[i] !== (newSelection || [])[i]);
if (!hasChanged && previousSelection > 0) {
// return; // Zablokowane na razie, może powodować problemy
}
log.debug('Selection updated', {
previousCount: previousSelection,
newCount: this.selectedLayers.length,
selectedLayerIds: this.selectedLayers.map((l) => l.id || 'unknown')
});
// 1. Zrenderuj ponownie canvas, aby pokazać nowe kontrolki transformacji
this.canvas.render();
// 2. Powiadom inne części aplikacji (jeśli są)
if (this.onSelectionChange) {
this.onSelectionChange();
}
// 3. Powiadom panel warstw, aby zaktualizował swój wygląd
if (this.canvas.canvasLayersPanel) {
this.canvas.canvasLayersPanel.onSelectionChanged();
}
}
/**
* Logika aktualizacji zaznaczenia, wywoływana przez panel warstw.
*/
updateSelectionLogic(layer, isCtrlPressed, isShiftPressed, index) {
let newSelection = [...this.selectedLayers];
let selectionChanged = false;
if (isShiftPressed && this.canvas.canvasLayersPanel.lastSelectedIndex !== -1) {
const sortedLayers = [...this.canvas.layers].sort((a, b) => b.zIndex - a.zIndex);
const startIndex = Math.min(this.canvas.canvasLayersPanel.lastSelectedIndex, index);
const endIndex = Math.max(this.canvas.canvasLayersPanel.lastSelectedIndex, index);
newSelection = [];
for (let i = startIndex; i <= endIndex; i++) {
if (sortedLayers[i]) {
newSelection.push(sortedLayers[i]);
}
}
selectionChanged = true;
}
else if (isCtrlPressed) {
const layerIndex = newSelection.indexOf(layer);
if (layerIndex === -1) {
newSelection.push(layer);
}
else {
newSelection.splice(layerIndex, 1);
}
this.canvas.canvasLayersPanel.lastSelectedIndex = index;
selectionChanged = true;
}
else {
// 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.canvas.canvasLayersPanel.lastSelectedIndex = index;
}
// Aktualizuj zaznaczenie tylko jeśli faktycznie się zmieniło
if (selectionChanged) {
this.updateSelection(newSelection);
}
}
removeSelectedLayers() {
if (this.selectedLayers.length > 0) {
log.info('Removing selected layers', {
layersToRemove: this.selectedLayers.length,
totalLayers: this.canvas.layers.length
});
this.canvas.saveState();
this.canvas.layers = this.canvas.layers.filter((l) => !this.selectedLayers.includes(l));
this.updateSelection([]);
this.canvas.render();
this.canvas.saveState();
if (this.canvas.canvasLayersPanel) {
this.canvas.canvasLayersPanel.onLayersChanged();
}
log.debug('Layers removed successfully, remaining layers:', this.canvas.layers.length);
}
else {
log.debug('No layers selected for removal');
}
}
/**
* Aktualizuje zaznaczenie po operacji historii
*/
updateSelectionAfterHistory() {
const newSelectedLayers = [];
if (this.selectedLayers) {
this.selectedLayers.forEach((sl) => {
const found = this.canvas.layers.find((l) => l.id === sl.id);
if (found)
newSelectedLayers.push(found);
});
}
this.updateSelection(newSelectedLayers);
}
}