mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-25 22:35:43 -03:00
Refactor canvas interactions and update keyboard shortcuts
Reorganizes mouse and keyboard event handling in CanvasInteractions for clearer priority and improved usability. Adds global keyboard shortcuts for undo, redo, copy, and paste. Updates context-sensitive shortcuts to support both Delete and Backspace for layer removal. Refactors CanvasLayers to use delayed state saving via requestSaveState. Updates CanvasView shortcut documentation to reflect these changes and clarify mouse/keyboard actions.
This commit is contained in:
@@ -70,20 +70,33 @@ export class CanvasInteractions {
|
|||||||
const worldCoords = this.canvas.getMouseWorldCoordinates(e);
|
const worldCoords = this.canvas.getMouseWorldCoordinates(e);
|
||||||
const viewCoords = this.canvas.getMouseViewCoordinates(e);
|
const viewCoords = this.canvas.getMouseViewCoordinates(e);
|
||||||
|
|
||||||
if (e.button === 2) { // Obsługa prawego przycisku myszy
|
// --- Ostateczna, poprawna kolejność sprawdzania ---
|
||||||
|
|
||||||
|
// 1. Akcje globalne z modyfikatorami (mają najwyższy priorytet)
|
||||||
|
if (e.shiftKey && e.ctrlKey) {
|
||||||
|
this.startCanvasMove(worldCoords);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.shiftKey) {
|
||||||
|
this.startCanvasResize(worldCoords);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Inne przyciski myszy
|
||||||
|
if (e.button === 2) { // Prawy przycisk myszy
|
||||||
const clickedLayerResult = this.canvas.canvasLayers.getLayerAtPosition(worldCoords.x, worldCoords.y);
|
const clickedLayerResult = this.canvas.canvasLayers.getLayerAtPosition(worldCoords.x, worldCoords.y);
|
||||||
if (clickedLayerResult && this.canvas.selectedLayers.includes(clickedLayerResult.layer)) {
|
if (clickedLayerResult && this.canvas.selectedLayers.includes(clickedLayerResult.layer)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.canvas.canvasLayers.showBlendModeMenu(viewCoords.x, viewCoords.y);
|
this.canvas.canvasLayers.showBlendModeMenu(viewCoords.x, viewCoords.y);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (e.button !== 0) { // Środkowy przycisk
|
||||||
if (e.button !== 0) { // Ignoruj inne przyciski niż lewy i prawy
|
|
||||||
this.startPanning(e);
|
this.startPanning(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Interakcje z elementami na płótnie (lewy przycisk)
|
||||||
const transformTarget = this.canvas.canvasLayers.getHandleAtPosition(worldCoords.x, worldCoords.y);
|
const transformTarget = this.canvas.canvasLayers.getHandleAtPosition(worldCoords.x, worldCoords.y);
|
||||||
if (transformTarget) {
|
if (transformTarget) {
|
||||||
this.startLayerTransform(transformTarget.layer, transformTarget.handle, worldCoords);
|
this.startLayerTransform(transformTarget.layer, transformTarget.handle, worldCoords);
|
||||||
@@ -92,17 +105,17 @@ export class CanvasInteractions {
|
|||||||
|
|
||||||
const clickedLayerResult = this.canvas.canvasLayers.getLayerAtPosition(worldCoords.x, worldCoords.y);
|
const clickedLayerResult = this.canvas.canvasLayers.getLayerAtPosition(worldCoords.x, worldCoords.y);
|
||||||
if (clickedLayerResult) {
|
if (clickedLayerResult) {
|
||||||
// Zaznacz warstwę i przygotuj się do potencjalnego przeciągania
|
|
||||||
this.prepareForDrag(clickedLayerResult.layer, worldCoords);
|
this.prepareForDrag(clickedLayerResult.layer, worldCoords);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jeśli nie kliknięto na nic, rozpocznij panoramowanie lub wyczyść zaznaczenie
|
// 4. Domyślna akcja na tle (lewy przycisk bez modyfikatorów)
|
||||||
this.startPanningOrClearSelection(e);
|
this.startPanningOrClearSelection(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseMove(e) {
|
handleMouseMove(e) {
|
||||||
const worldCoords = this.canvas.getMouseWorldCoordinates(e);
|
const worldCoords = this.canvas.getMouseWorldCoordinates(e);
|
||||||
|
this.canvas.lastMousePosition = worldCoords; // Zawsze aktualizuj ostatnią pozycję myszy
|
||||||
|
|
||||||
// Sprawdź, czy rozpocząć przeciąganie
|
// Sprawdź, czy rozpocząć przeciąganie
|
||||||
if (this.interaction.mode === 'potential-drag') {
|
if (this.interaction.mode === 'potential-drag') {
|
||||||
@@ -284,10 +297,45 @@ export class CanvasInteractions {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.canvas.selectedLayer) {
|
// Globalne skróty (Undo/Redo/Copy/Paste)
|
||||||
|
if (e.ctrlKey || e.metaKey) {
|
||||||
|
let handled = true;
|
||||||
|
switch (e.key.toLowerCase()) {
|
||||||
|
case 'z':
|
||||||
|
if (e.shiftKey) {
|
||||||
|
this.canvas.redo();
|
||||||
|
} else {
|
||||||
|
this.canvas.undo();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
this.canvas.redo();
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
if (this.canvas.selectedLayers.length > 0) {
|
||||||
|
this.canvas.canvasLayers.copySelectedLayers();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
this.canvas.canvasLayers.handlePaste('mouse');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
handled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (handled) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skróty kontekstowe (zależne od zaznaczenia)
|
||||||
|
if (this.canvas.selectedLayers.length > 0) {
|
||||||
const step = e.shiftKey ? 10 : 1;
|
const step = e.shiftKey ? 10 : 1;
|
||||||
let needsRender = false;
|
let needsRender = false;
|
||||||
|
|
||||||
|
// Używamy e.code dla spójności i niezależności od układu klawiatury
|
||||||
const movementKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'BracketLeft', 'BracketRight'];
|
const movementKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'BracketLeft', 'BracketRight'];
|
||||||
if (movementKeys.includes(e.code)) {
|
if (movementKeys.includes(e.code)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -304,7 +352,7 @@ export class CanvasInteractions {
|
|||||||
needsRender = true;
|
needsRender = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.key === 'Delete') {
|
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.canvas.removeSelectedLayers();
|
this.canvas.removeSelectedLayers();
|
||||||
@@ -312,7 +360,7 @@ export class CanvasInteractions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needsRender) {
|
if (needsRender) {
|
||||||
this.canvas.render(); // Tylko renderuj, nie zapisuj stanu
|
this.canvas.render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,19 +441,8 @@ export class CanvasInteractions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startPanningOrClearSelection(e) {
|
startPanningOrClearSelection(e) {
|
||||||
const worldCoords = this.canvas.getMouseWorldCoordinates(e);
|
// Ta funkcja jest teraz wywoływana tylko gdy kliknięto na tło bez modyfikatorów.
|
||||||
|
// Domyślna akcja: wyczyść zaznaczenie i rozpocznij panoramowanie.
|
||||||
// Sprawdź modyfikatory dla akcji na tle
|
|
||||||
if (e.shiftKey) {
|
|
||||||
this.startCanvasResize(worldCoords);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (e.altKey) {
|
|
||||||
this.startCanvasMove(worldCoords);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Domyślna akcja: wyczyść zaznaczenie i rozpocznij panoramowanie
|
|
||||||
if (!this.interaction.isCtrlPressed) {
|
if (!this.interaction.isCtrlPressed) {
|
||||||
this.canvas.updateSelection([]);
|
this.canvas.updateSelection([]);
|
||||||
}
|
}
|
||||||
@@ -469,6 +506,7 @@ export class CanvasInteractions {
|
|||||||
this.canvas.viewport.y -= finalY;
|
this.canvas.viewport.y -= finalY;
|
||||||
}
|
}
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
|
this.canvas.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
startPanning(e) {
|
startPanning(e) {
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ export class CanvasLayers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
this.canvas.saveState();
|
this.canvas.requestSaveState(); // Użyj opóźnionego zapisu
|
||||||
log.info(`Moved ${layersToMove.length} layer(s).`);
|
log.info(`Moved ${layersToMove.length} layer(s).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +301,7 @@ export class CanvasLayers {
|
|||||||
layer.height *= scale;
|
layer.height *= scale;
|
||||||
});
|
});
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
this.canvas.saveState();
|
this.canvas.requestSaveState(); // Użyj opóźnionego zapisu
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -315,7 +315,7 @@ export class CanvasLayers {
|
|||||||
layer.rotation += angle;
|
layer.rotation += angle;
|
||||||
});
|
});
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
this.canvas.saveState();
|
this.canvas.requestSaveState(); // Użyj opóźnionego zapisu
|
||||||
}
|
}
|
||||||
|
|
||||||
getLayerAtPosition(worldX, worldY) {
|
getLayerAtPosition(worldX, worldY) {
|
||||||
@@ -371,7 +371,7 @@ export class CanvasLayers {
|
|||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
this.canvas.saveState();
|
this.canvas.requestSaveState(); // Użyj opóźnionego zapisu
|
||||||
}
|
}
|
||||||
|
|
||||||
async mirrorVertical() {
|
async mirrorVertical() {
|
||||||
@@ -399,7 +399,7 @@ export class CanvasLayers {
|
|||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
this.canvas.render();
|
this.canvas.render();
|
||||||
this.canvas.saveState();
|
this.canvas.requestSaveState(); // Użyj opóźnionego zapisu
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLayerImageData(layer) {
|
async getLayerImageData(layer) {
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
<tr><td><kbd>Mouse Wheel</kbd></td><td>Zoom view in/out</td></tr>
|
<tr><td><kbd>Mouse Wheel</kbd></td><td>Zoom view in/out</td></tr>
|
||||||
<tr><td><kbd>Shift + Click (background)</kbd></td><td>Start resizing canvas area</td></tr>
|
<tr><td><kbd>Shift + Click (background)</kbd></td><td>Start resizing canvas area</td></tr>
|
||||||
<tr><td><kbd>Shift + Ctrl + Click</kbd></td><td>Start moving entire canvas</td></tr>
|
<tr><td><kbd>Shift + Ctrl + Click</kbd></td><td>Start moving entire canvas</td></tr>
|
||||||
<tr><td><kbd>Double Click (background)</kbd></td><td>Deselect all layers</td></tr>
|
<tr><td><kbd>Single Click (background)</kbd></td><td>Deselect all layers</td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h4>Clipboard & I/O</h4>
|
<h4>Clipboard & I/O</h4>
|
||||||
@@ -444,7 +444,7 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
<tr><td><kbd>Click + Drag</kbd></td><td>Move selected layer(s)</td></tr>
|
<tr><td><kbd>Click + Drag</kbd></td><td>Move selected layer(s)</td></tr>
|
||||||
<tr><td><kbd>Ctrl + Click</kbd></td><td>Add/Remove layer from selection</td></tr>
|
<tr><td><kbd>Ctrl + Click</kbd></td><td>Add/Remove layer from selection</td></tr>
|
||||||
<tr><td><kbd>Alt + Drag</kbd></td><td>Clone selected layer(s)</td></tr>
|
<tr><td><kbd>Alt + Drag</kbd></td><td>Clone selected layer(s)</td></tr>
|
||||||
<tr><td><kbd>Shift + Click</kbd></td><td>Show blend mode & opacity menu</td></tr>
|
<tr><td><kbd>Right Click</kbd></td><td>Show blend mode & opacity menu</td></tr>
|
||||||
<tr><td><kbd>Mouse Wheel</kbd></td><td>Scale layer (snaps to grid)</td></tr>
|
<tr><td><kbd>Mouse Wheel</kbd></td><td>Scale layer (snaps to grid)</td></tr>
|
||||||
<tr><td><kbd>Ctrl + Mouse Wheel</kbd></td><td>Fine-scale layer</td></tr>
|
<tr><td><kbd>Ctrl + Mouse Wheel</kbd></td><td>Fine-scale layer</td></tr>
|
||||||
<tr><td><kbd>Shift + Mouse Wheel</kbd></td><td>Rotate layer by 5°</td></tr>
|
<tr><td><kbd>Shift + Mouse Wheel</kbd></td><td>Rotate layer by 5°</td></tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user