mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-21 12:52:10 -03:00
Add Master Visibility Toggle to Layers Panel
Introduce a three-state checkbox in CanvasLayersPanel header to control visibility of all layers at once. Supports automatic state updates and integrates with renderLayers() for seamless layer management.
This commit is contained in:
@@ -103,6 +103,7 @@ export class CanvasLayersPanel {
|
||||
this.container.tabIndex = 0; // Umożliwia fokus na panelu
|
||||
this.container.innerHTML = `
|
||||
<div class="layers-panel-header">
|
||||
<div class="master-visibility-toggle" title="Toggle all layers visibility"></div>
|
||||
<span class="layers-panel-title">Layers</span>
|
||||
<div class="layers-panel-controls">
|
||||
<button class="layers-btn" id="delete-layer-btn" title="Delete layer"></button>
|
||||
@@ -115,6 +116,7 @@ export class CanvasLayersPanel {
|
||||
this.layersContainer = this.container.querySelector('#layers-container');
|
||||
// Setup event listeners dla przycisków
|
||||
this.setupControlButtons();
|
||||
this.setupMasterVisibilityToggle();
|
||||
// Dodaj listener dla klawiatury, aby usuwanie działało z panelu
|
||||
this.container.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Delete' || e.key === 'Backspace') {
|
||||
@@ -142,6 +144,67 @@ export class CanvasLayersPanel {
|
||||
// Initial button state update
|
||||
this.updateButtonStates();
|
||||
}
|
||||
setupMasterVisibilityToggle() {
|
||||
if (!this.container)
|
||||
return;
|
||||
const toggleContainer = this.container.querySelector('.master-visibility-toggle');
|
||||
if (!toggleContainer)
|
||||
return;
|
||||
const updateToggleState = () => {
|
||||
const total = this.canvas.layers.length;
|
||||
const visibleCount = this.canvas.layers.filter(l => l.visible).length;
|
||||
toggleContainer.innerHTML = '';
|
||||
const checkboxContainer = document.createElement('div');
|
||||
checkboxContainer.className = 'checkbox-container';
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.id = 'master-visibility-checkbox';
|
||||
const customCheckbox = document.createElement('span');
|
||||
customCheckbox.className = 'custom-checkbox';
|
||||
checkboxContainer.appendChild(checkbox);
|
||||
checkboxContainer.appendChild(customCheckbox);
|
||||
if (visibleCount === 0) {
|
||||
checkbox.checked = false;
|
||||
checkbox.indeterminate = false;
|
||||
customCheckbox.classList.remove('checked', 'indeterminate');
|
||||
}
|
||||
else if (visibleCount === total) {
|
||||
checkbox.checked = true;
|
||||
checkbox.indeterminate = false;
|
||||
customCheckbox.classList.add('checked');
|
||||
customCheckbox.classList.remove('indeterminate');
|
||||
}
|
||||
else {
|
||||
checkbox.checked = false;
|
||||
checkbox.indeterminate = true;
|
||||
customCheckbox.classList.add('indeterminate');
|
||||
customCheckbox.classList.remove('checked');
|
||||
}
|
||||
checkboxContainer.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
let newVisible;
|
||||
if (checkbox.indeterminate) {
|
||||
newVisible = false; // hide all when mixed
|
||||
}
|
||||
else if (checkbox.checked) {
|
||||
newVisible = false; // toggle to hide all
|
||||
}
|
||||
else {
|
||||
newVisible = true; // toggle to show all
|
||||
}
|
||||
this.canvas.layers.forEach(layer => {
|
||||
layer.visible = newVisible;
|
||||
});
|
||||
this.canvas.render();
|
||||
this.canvas.requestSaveState();
|
||||
updateToggleState();
|
||||
this.renderLayers();
|
||||
});
|
||||
toggleContainer.appendChild(checkboxContainer);
|
||||
};
|
||||
updateToggleState();
|
||||
this._updateMasterVisibilityToggle = updateToggleState;
|
||||
}
|
||||
renderLayers() {
|
||||
if (!this.layersContainer) {
|
||||
log.warn('Layers container not initialized');
|
||||
@@ -158,6 +221,8 @@ export class CanvasLayersPanel {
|
||||
if (this.layersContainer)
|
||||
this.layersContainer.appendChild(layerElement);
|
||||
});
|
||||
if (this._updateMasterVisibilityToggle)
|
||||
this._updateMasterVisibilityToggle();
|
||||
log.debug(`Rendered ${sortedLayers.length} layers`);
|
||||
}
|
||||
createLayerElement(layer, index) {
|
||||
|
||||
@@ -23,6 +23,85 @@
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 5px 0;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.checkbox-container:hover {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
|
||||
.checkbox-container input[type="checkbox"] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.checkbox-container .custom-checkbox {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #666;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkbox-container input:checked ~ .custom-checkbox {
|
||||
background-color: #3a76d6;
|
||||
border-color: #3a76d6;
|
||||
}
|
||||
|
||||
.checkbox-container .custom-checkbox::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
left: 5px;
|
||||
top: 1px;
|
||||
width: 4px;
|
||||
height: 9px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.checkbox-container input:checked ~ .custom-checkbox::after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.checkbox-container input:indeterminate ~ .custom-checkbox {
|
||||
background-color: #3a76d6;
|
||||
border-color: #3a76d6;
|
||||
}
|
||||
|
||||
.checkbox-container input:indeterminate ~ .custom-checkbox::after {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 3px;
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
background-color: white;
|
||||
border: none;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.checkbox-container:hover {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
|
||||
.layers-panel-title {
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
|
||||
@@ -121,6 +121,7 @@ export class CanvasLayersPanel {
|
||||
this.container.tabIndex = 0; // Umożliwia fokus na panelu
|
||||
this.container.innerHTML = `
|
||||
<div class="layers-panel-header">
|
||||
<div class="master-visibility-toggle" title="Toggle all layers visibility"></div>
|
||||
<span class="layers-panel-title">Layers</span>
|
||||
<div class="layers-panel-controls">
|
||||
<button class="layers-btn" id="delete-layer-btn" title="Delete layer"></button>
|
||||
@@ -135,6 +136,7 @@ export class CanvasLayersPanel {
|
||||
|
||||
// Setup event listeners dla przycisków
|
||||
this.setupControlButtons();
|
||||
this.setupMasterVisibilityToggle();
|
||||
|
||||
// Dodaj listener dla klawiatury, aby usuwanie działało z panelu
|
||||
this.container.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
@@ -169,6 +171,74 @@ export class CanvasLayersPanel {
|
||||
this.updateButtonStates();
|
||||
}
|
||||
|
||||
setupMasterVisibilityToggle(): void {
|
||||
if (!this.container) return;
|
||||
const toggleContainer = this.container.querySelector('.master-visibility-toggle') as HTMLElement;
|
||||
if (!toggleContainer) return;
|
||||
|
||||
const updateToggleState = () => {
|
||||
const total = this.canvas.layers.length;
|
||||
const visibleCount = this.canvas.layers.filter(l => l.visible).length;
|
||||
toggleContainer.innerHTML = '';
|
||||
|
||||
const checkboxContainer = document.createElement('div');
|
||||
checkboxContainer.className = 'checkbox-container';
|
||||
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.id = 'master-visibility-checkbox';
|
||||
|
||||
const customCheckbox = document.createElement('span');
|
||||
customCheckbox.className = 'custom-checkbox';
|
||||
|
||||
checkboxContainer.appendChild(checkbox);
|
||||
checkboxContainer.appendChild(customCheckbox);
|
||||
|
||||
if (visibleCount === 0) {
|
||||
checkbox.checked = false;
|
||||
checkbox.indeterminate = false;
|
||||
customCheckbox.classList.remove('checked', 'indeterminate');
|
||||
} else if (visibleCount === total) {
|
||||
checkbox.checked = true;
|
||||
checkbox.indeterminate = false;
|
||||
customCheckbox.classList.add('checked');
|
||||
customCheckbox.classList.remove('indeterminate');
|
||||
} else {
|
||||
checkbox.checked = false;
|
||||
checkbox.indeterminate = true;
|
||||
customCheckbox.classList.add('indeterminate');
|
||||
customCheckbox.classList.remove('checked');
|
||||
}
|
||||
|
||||
checkboxContainer.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
let newVisible: boolean;
|
||||
if (checkbox.indeterminate) {
|
||||
newVisible = false; // hide all when mixed
|
||||
} else if (checkbox.checked) {
|
||||
newVisible = false; // toggle to hide all
|
||||
} else {
|
||||
newVisible = true; // toggle to show all
|
||||
}
|
||||
|
||||
this.canvas.layers.forEach(layer => {
|
||||
layer.visible = newVisible;
|
||||
});
|
||||
this.canvas.render();
|
||||
this.canvas.requestSaveState();
|
||||
updateToggleState();
|
||||
this.renderLayers();
|
||||
});
|
||||
|
||||
toggleContainer.appendChild(checkboxContainer);
|
||||
};
|
||||
|
||||
updateToggleState();
|
||||
this._updateMasterVisibilityToggle = updateToggleState;
|
||||
}
|
||||
|
||||
private _updateMasterVisibilityToggle?: () => void;
|
||||
|
||||
renderLayers(): void {
|
||||
if (!this.layersContainer) {
|
||||
log.warn('Layers container not initialized');
|
||||
@@ -186,10 +256,11 @@ export class CanvasLayersPanel {
|
||||
|
||||
sortedLayers.forEach((layer: Layer, index: number) => {
|
||||
const layerElement = this.createLayerElement(layer, index);
|
||||
if(this.layersContainer)
|
||||
if (this.layersContainer)
|
||||
this.layersContainer.appendChild(layerElement);
|
||||
});
|
||||
|
||||
if (this._updateMasterVisibilityToggle) this._updateMasterVisibilityToggle();
|
||||
log.debug(`Rendered ${sortedLayers.length} layers`);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,85 @@
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 5px 0;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.checkbox-container:hover {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
|
||||
.checkbox-container input[type="checkbox"] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.checkbox-container .custom-checkbox {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #666;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkbox-container input:checked ~ .custom-checkbox {
|
||||
background-color: #3a76d6;
|
||||
border-color: #3a76d6;
|
||||
}
|
||||
|
||||
.checkbox-container .custom-checkbox::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
left: 5px;
|
||||
top: 1px;
|
||||
width: 4px;
|
||||
height: 9px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.checkbox-container input:checked ~ .custom-checkbox::after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.checkbox-container input:indeterminate ~ .custom-checkbox {
|
||||
background-color: #3a76d6;
|
||||
border-color: #3a76d6;
|
||||
}
|
||||
|
||||
.checkbox-container input:indeterminate ~ .custom-checkbox::after {
|
||||
display: block;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 3px;
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
background-color: white;
|
||||
border: none;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.checkbox-container:hover {
|
||||
background-color: #4a4a4a;
|
||||
}
|
||||
|
||||
.layers-panel-title {
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
|
||||
Reference in New Issue
Block a user