Layout change

This commit is contained in:
Dariusz L
2025-07-28 15:57:28 +02:00
parent bb687a768b
commit f57b9f6b58
8 changed files with 805 additions and 338 deletions

View File

@@ -65,20 +65,14 @@ async function createCanvasWidget(node, widget, app) {
},
}, [
$el("div.painter-button-group", {}, [
$el("button.painter-button", {
$el("button.painter-button.icon-button", {
id: `open-editor-btn-${node.id}`,
textContent: "⛶",
title: "Open in Editor",
style: { minWidth: "40px", maxWidth: "40px", fontWeight: "bold" },
}),
$el("button.painter-button", {
$el("button.painter-button.icon-button", {
textContent: "?",
title: "Show shortcuts",
style: {
minWidth: "30px",
maxWidth: "30px",
fontWeight: "bold",
},
onmouseenter: (e) => {
const content = canvas.maskTool.isActive ? maskShortcuts : standardShortcuts;
showTooltip(e.target, content);
@@ -131,38 +125,63 @@ async function createCanvasWidget(node, widget, app) {
canvas.canvasLayers.handlePaste(addMode);
}
}),
$el("button.painter-button", {
id: `clipboard-toggle-${node.id}`,
textContent: "📋 System",
title: "Toggle clipboard source: System Clipboard",
style: {
minWidth: "100px",
fontSize: "11px",
backgroundColor: "#4a4a4a"
},
onclick: (e) => {
const button = e.target;
if (canvas.canvasLayers.clipboardPreference === 'system') {
canvas.canvasLayers.clipboardPreference = 'clipspace';
button.textContent = "📋 Clipspace";
button.title = "Toggle clipboard source: ComfyUI Clipspace";
button.style.backgroundColor = "#4a6cd4";
(() => {
// Modern clipboard switch
// Initial state: checked = clipspace, unchecked = system
const isClipspace = canvas.canvasLayers.clipboardPreference === 'clipspace';
const switchId = `clipboard-switch-${node.id}`;
const switchEl = $el("label.clipboard-switch", { id: switchId }, [
$el("input", {
type: "checkbox",
checked: isClipspace,
onchange: (e) => {
const checked = e.target.checked;
canvas.canvasLayers.clipboardPreference = checked ? 'clipspace' : 'system';
// For accessibility, update ARIA label
switchEl.setAttribute('aria-label', checked ? "Clipboard: Clipspace" : "Clipboard: System");
log.info(`Clipboard preference toggled to: ${canvas.canvasLayers.clipboardPreference}`);
}
}),
$el("span.switch-track"),
$el("span.switch-labels", {}, [
$el("span.text-clipspace", {}, ["Clipspace"]),
$el("span.text-system", {}, ["System"])
]),
$el("span.switch-knob", {}, [
$el("span.switch-icon")
])
]);
// Tooltip logic
switchEl.addEventListener("mouseenter", (e) => {
const checked = switchEl.querySelector('input[type="checkbox"]').checked;
const tooltipContent = checked ? clipspaceClipboardTooltip : systemClipboardTooltip;
showTooltip(switchEl, tooltipContent);
});
switchEl.addEventListener("mouseleave", hideTooltip);
// Dynamic icon and text update on toggle
const input = switchEl.querySelector('input[type="checkbox"]');
const knobIcon = switchEl.querySelector('.switch-knob .switch-icon');
const updateSwitchView = (isClipspace) => {
const iconTool = isClipspace ? LAYERFORGE_TOOLS.CLIPSPACE : LAYERFORGE_TOOLS.SYSTEM_CLIPBOARD;
const icon = iconLoader.getIcon(iconTool);
if (icon instanceof HTMLImageElement) {
knobIcon.innerHTML = '';
const clonedIcon = icon.cloneNode();
clonedIcon.style.width = '20px';
clonedIcon.style.height = '20px';
knobIcon.appendChild(clonedIcon);
}
else {
canvas.canvasLayers.clipboardPreference = 'system';
button.textContent = "📋 System";
button.title = "Toggle clipboard source: System Clipboard";
button.style.backgroundColor = "#4a4a4a";
knobIcon.textContent = isClipspace ? "🗂️" : "📋";
}
log.info(`Clipboard preference toggled to: ${canvas.canvasLayers.clipboardPreference}`);
},
onmouseenter: (e) => {
const currentPreference = canvas.canvasLayers.clipboardPreference;
const tooltipContent = currentPreference === 'system' ? systemClipboardTooltip : clipspaceClipboardTooltip;
showTooltip(e.target, tooltipContent);
},
onmouseleave: hideTooltip
})
};
input.addEventListener('change', () => updateSwitchView(input.checked));
// Initial state
iconLoader.preloadToolIcons().then(() => {
updateSwitchView(isClipspace);
});
return switchEl;
})()
]),
]),
$el("div.painter-separator"),
@@ -440,8 +459,15 @@ async function createCanvasWidget(node, widget, app) {
min: "1",
max: "200",
value: "20",
oninput: (e) => canvas.maskTool.setBrushSize(parseInt(e.target.value))
})
oninput: (e) => {
const value = e.target.value;
canvas.maskTool.setBrushSize(parseInt(value));
const valueEl = document.getElementById('brush-size-value');
if (valueEl)
valueEl.textContent = `${value}px`;
}
}),
$el("div.slider-value", { id: "brush-size-value" }, ["20px"])
]),
$el("div.painter-slider-container.mask-control", { style: { display: 'none' } }, [
$el("label", { for: "brush-strength-slider", textContent: "Strength:" }),
@@ -452,8 +478,15 @@ async function createCanvasWidget(node, widget, app) {
max: "1",
step: "0.05",
value: "0.5",
oninput: (e) => canvas.maskTool.setBrushStrength(parseFloat(e.target.value))
})
oninput: (e) => {
const value = e.target.value;
canvas.maskTool.setBrushStrength(parseFloat(value));
const valueEl = document.getElementById('brush-strength-value');
if (valueEl)
valueEl.textContent = `${Math.round(parseFloat(value) * 100)}%`;
}
}),
$el("div.slider-value", { id: "brush-strength-value" }, ["50%"])
]),
$el("div.painter-slider-container.mask-control", { style: { display: 'none' } }, [
$el("label", { for: "brush-hardness-slider", textContent: "Hardness:" }),
@@ -464,8 +497,15 @@ async function createCanvasWidget(node, widget, app) {
max: "1",
step: "0.05",
value: "0.5",
oninput: (e) => canvas.maskTool.setBrushHardness(parseFloat(e.target.value))
})
oninput: (e) => {
const value = e.target.value;
canvas.maskTool.setBrushHardness(parseFloat(value));
const valueEl = document.getElementById('brush-hardness-value');
if (valueEl)
valueEl.textContent = `${Math.round(parseFloat(value) * 100)}%`;
}
}),
$el("div.slider-value", { id: "brush-hardness-value" }, ["50%"])
]),
$el("button.painter-button.mask-control", {
textContent: "Clear Mask",
@@ -481,10 +521,9 @@ async function createCanvasWidget(node, widget, app) {
]),
$el("div.painter-separator"),
$el("div.painter-button-group", {}, [
$el("button.painter-button", {
$el("button.painter-button.success", {
textContent: "Run GC",
title: "Run Garbage Collection to clean unused images",
style: { backgroundColor: "#4a7c59", borderColor: "#3a6c49" },
onclick: async () => {
try {
const stats = canvas.imageReferenceManager.getStats();
@@ -500,10 +539,9 @@ async function createCanvasWidget(node, widget, app) {
}
}
}),
$el("button.painter-button", {
$el("button.painter-button.danger", {
textContent: "Clear Cache",
title: "Clear all saved canvas states from browser storage",
style: { backgroundColor: "#c54747", borderColor: "#a53737" },
onclick: async () => {
if (confirm("Are you sure you want to clear all saved canvas states? This action cannot be undone.")) {
try {
@@ -736,36 +774,33 @@ async function createCanvasWidget(node, widget, app) {
let backdrop = null;
let originalParent = null;
let isEditorOpen = false;
let viewportAdjustment = { x: 0, y: 0 };
/**
* Adjusts the viewport to keep the content centered when the container size changes.
* @param rectA The original rectangle.
* @param rectB The new rectangle.
* @param direction Determines whether to apply the adjustment for opening (-1) or closing (1).
* Adjusts the viewport when entering fullscreen mode.
*/
const adjustViewportForCentering = (rectA, rectB, direction) => {
if (!rectA || !rectB)
return;
const widthDiff = rectB.width - rectA.width;
const heightDiff = rectB.height - rectA.height;
const adjustViewportOnOpen = (originalRect) => {
const fullscreenRect = canvasContainer.getBoundingClientRect();
const widthDiff = fullscreenRect.width - originalRect.width;
const heightDiff = fullscreenRect.height - originalRect.height;
const adjustX = (widthDiff / 2) / canvas.viewport.zoom;
const adjustY = (heightDiff / 2) / canvas.viewport.zoom;
canvas.viewport.x -= adjustX * direction;
canvas.viewport.y -= adjustY * direction;
const action = direction === 1 ? 'OPENING' : 'CLOSING';
log.info(`FULLSCREEN ${action} - Viewport adjusted for centering:`, {
widthDiff, heightDiff, adjustX, adjustY,
viewport_after: { x: canvas.viewport.x, y: canvas.viewport.y, zoom: canvas.viewport.zoom }
});
// Store the adjustment
viewportAdjustment = { x: adjustX, y: adjustY };
// Apply the adjustment
canvas.viewport.x -= viewportAdjustment.x;
canvas.viewport.y -= viewportAdjustment.y;
};
/**
* Restores the viewport when exiting fullscreen mode.
*/
const adjustViewportOnClose = () => {
// Apply the stored adjustment in reverse
canvas.viewport.x += viewportAdjustment.x;
canvas.viewport.y += viewportAdjustment.y;
// Reset adjustment
viewportAdjustment = { x: 0, y: 0 };
};
const closeEditor = () => {
// Get fullscreen rect BEFORE removing from DOM
const fullscreenRect = backdrop?.querySelector('.painter-modal-content')?.getBoundingClientRect();
const currentRect = originalParent?.getBoundingClientRect();
log.info(`FULLSCREEN CLOSING - Window sizes:`, {
current: { width: currentRect?.width, height: currentRect?.height },
fullscreen: { width: fullscreenRect?.width, height: fullscreenRect?.height },
viewport_before: { x: canvas.viewport.x, y: canvas.viewport.y, zoom: canvas.viewport.zoom }
});
if (originalParent && backdrop) {
originalParent.appendChild(mainContainer);
document.body.removeChild(backdrop);
@@ -776,12 +811,7 @@ async function createCanvasWidget(node, widget, app) {
// Remove ESC key listener when editor closes
document.removeEventListener('keydown', handleEscKey);
setTimeout(() => {
// Use the actual canvas container for centering calculation
const currentCanvasContainer = originalParent.querySelector('.painterCanvasContainer.painter-container');
const fullscreenCanvasContainer = backdrop.querySelector('.painterCanvasContainer.painter-container');
const currentRect = currentCanvasContainer.getBoundingClientRect();
const fullscreenRect = fullscreenCanvasContainer.getBoundingClientRect();
adjustViewportForCentering(currentRect, fullscreenRect, -1);
adjustViewportOnClose();
canvas.render();
if (node.onResize) {
node.onResize();
@@ -794,7 +824,6 @@ async function createCanvasWidget(node, widget, app) {
e.preventDefault();
e.stopPropagation();
closeEditor();
log.info("Fullscreen editor closed via ESC key");
}
};
openEditorBtn.onclick = () => {
@@ -802,6 +831,7 @@ async function createCanvasWidget(node, widget, app) {
closeEditor();
return;
}
const originalRect = canvasContainer.getBoundingClientRect();
originalParent = mainContainer.parentElement;
if (!originalParent) {
log.error("Could not find original parent of the canvas container!");
@@ -818,12 +848,7 @@ async function createCanvasWidget(node, widget, app) {
// Add ESC key listener when editor opens
document.addEventListener('keydown', handleEscKey);
setTimeout(() => {
// Use the actual canvas container for centering calculation
const originalCanvasContainer = originalParent.querySelector('.painterCanvasContainer.painter-container');
const fullscreenCanvasContainer = modalContent.querySelector('.painterCanvasContainer.painter-container');
const originalRect = originalCanvasContainer.getBoundingClientRect();
const fullscreenRect = fullscreenCanvasContainer.getBoundingClientRect();
adjustViewportForCentering(originalRect, fullscreenRect, 1);
adjustViewportOnOpen(originalRect);
canvas.render();
if (node.onResize) {
node.onResize();