diff --git a/ui_server.py b/ui_server.py
index c861468..ea4f561 100644
--- a/ui_server.py
+++ b/ui_server.py
@@ -1287,6 +1287,8 @@ HTML = """
.config-scale-control input { width: 74px; height: 16px; margin: 0; accent-color: var(--ui-accent); cursor: pointer; }
.config-scale-control input:disabled { opacity: .45; cursor: default; }
.config-scale-control output { min-width: 34px; color: var(--ui-text); font-variant-numeric: tabular-nums; text-align: right; }
+ .config-scale-mode { min-height: 26px !important; padding: 0 8px !important; white-space: nowrap; }
+ .config-scale-mode[aria-pressed="true"] { color: #fff !important; background: var(--ui-accent-bg) !important; border-color: var(--ui-accent) !important; box-shadow: 0 0 0 2px color-mix(in srgb, var(--ui-accent) 16%, transparent); }
.config-layout-state { min-width: 0; color: var(--ui-muted); font-size: 10px; }
.config-workspace { display: grid; grid-template-columns: minmax(0, 1fr); min-width: 0; min-height: 0; }
.config-workspace.has-structure { grid-template-columns: minmax(190px, 260px) minmax(0, 1fr); align-items: start; }
@@ -1603,6 +1605,7 @@ HTML = """
+
Ctrl/Cmd + клик — выбрать несколько · перетаскивайте группу
@@ -1829,6 +1832,7 @@ HTML = """
+
Ctrl/Cmd + клик — выбрать несколько · перетаскивайте группу
@@ -2093,6 +2097,7 @@ HTML = """
let deletedPanelOpen = false;
let configZIndex = 1;
let configContentScale = 1;
+ let configScaleWheelEnabled = false;
let configBlockObserver = null;
let selectedConfigBlock = null;
let selectedConfigBlocks = new Set();
@@ -2138,6 +2143,14 @@ HTML = """
updateConfigBlockScale(block);
saveConfigLayout();
}
+ function setConfigScaleMode(enabled) {
+ configScaleWheelEnabled = !!enabled && !!selectedConfigBlock;
+ const button = $('configScaleMode');
+ if (!button) return;
+ button.disabled = !selectedConfigBlock;
+ button.setAttribute('aria-pressed', String(configScaleWheelEnabled));
+ button.textContent = configScaleWheelEnabled ? 'масштаб колесом: вкл' : 'масштаб колесом: выкл';
+ }
function selectConfigBlock(block) {
selectedConfigBlocks = new Set(block && !configBlockState(block) ? [block] : []);
updateConfigSelection(block);
@@ -2152,6 +2165,7 @@ HTML = """
if (!selectedConfigBlock) {
if (control) control.disabled = true;
if (remove) remove.disabled = true;
+ setConfigScaleMode(false);
return;
}
const entry = configLayout[selectedConfigBlock.dataset.section] || {};
@@ -2161,6 +2175,7 @@ HTML = """
setText('configContentScaleValue', `${value}%`);
if (control) control.disabled = selectedConfigBlocks.size !== 1;
if (remove) remove.disabled = !selectedConfigBlocks.size;
+ setConfigScaleMode(configScaleWheelEnabled);
updateConfigBlockScale(selectedConfigBlock);
if (selectedConfigBlocks.size > 1) setText('configLayoutState', `выбрано ${selectedConfigBlocks.size} блока · перетаскивайте группу`);
}
@@ -2637,6 +2652,14 @@ HTML = """
block.style.cursor = edge ? `${edge}-resize` : '';
}
});
+ block.addEventListener('wheel', event => {
+ if (!configScaleWheelEnabled || configBlockState(block) || !event.deltaY) return;
+ event.preventDefault();
+ event.stopPropagation();
+ if (selectedConfigBlock !== block) selectConfigBlock(block);
+ const current = Number(configLayout[block.dataset.section]?.scale) || 100;
+ applyConfigContentScale(current + (event.deltaY < 0 ? 5 : -5));
+ }, {passive: false});
block.addEventListener('pointerleave', () => { if (!block.classList.contains('is-resizing')) block.style.cursor = ''; });
block.addEventListener('pointerdown', event => {
if (event.defaultPrevented || block.classList.contains('is-resizing')) return;
@@ -2756,6 +2779,7 @@ HTML = """
selectConfigBlock(configBlocks.find(block => !configBlockState(block)) || null);
$('configResetLayout')?.addEventListener('click', resetConfigLayout);
$('configDeleteSelected')?.addEventListener('click', deleteSelectedConfigBlocks);
+ $('configScaleMode')?.addEventListener('click', () => setConfigScaleMode(!configScaleWheelEnabled));
$('configRestoreToggle')?.addEventListener('click', () => {
restorePanelOpen = !restorePanelOpen;
renderConfigRestorePanel();
@@ -2811,6 +2835,7 @@ HTML = """
let selectedNetworkBlocks = new Set();
let networkStructureOpen = false;
let networkContentScale = 1;
+ let networkScaleWheelEnabled = false;
function readNetworkLayout() {
try {
const saved = JSON.parse(localStorage.getItem('fpv-network-layout-v1') || '{}');
@@ -2857,6 +2882,7 @@ HTML = """
if (!networkSelectedBlock) {
if (control) control.disabled = true;
if (remove) remove.disabled = true;
+ setNetworkScaleMode(false);
return;
}
const value = Math.max(50, Math.min(200, Math.round(Number(networkLayout[networkSelectedBlock.dataset.section]?.scale) || 100)));
@@ -2865,6 +2891,7 @@ HTML = """
setText('networkContentScaleValue', `${value}%`);
if (control) control.disabled = selectedNetworkBlocks.size !== 1;
if (remove) remove.disabled = !selectedNetworkBlocks.size;
+ setNetworkScaleMode(networkScaleWheelEnabled);
updateNetworkBlockScale(networkSelectedBlock);
if (selectedNetworkBlocks.size > 1) setText('networkLayoutState', `выбрано ${selectedNetworkBlocks.size} блока · перетаскивайте группу`);
}
@@ -2887,6 +2914,14 @@ HTML = """
updateNetworkBlockScale(block);
saveNetworkLayout();
}
+ function setNetworkScaleMode(enabled) {
+ networkScaleWheelEnabled = !!enabled && !!networkSelectedBlock;
+ const button = $('networkScaleMode');
+ if (!button) return;
+ button.disabled = !networkSelectedBlock;
+ button.setAttribute('aria-pressed', String(networkScaleWheelEnabled));
+ button.textContent = networkScaleWheelEnabled ? 'масштаб колесом: вкл' : 'масштаб колесом: выкл';
+ }
function captureNetworkLayout(block) {
const key = block?.dataset.section;
if (!key) return;
@@ -3261,6 +3296,14 @@ HTML = """
block.style.cursor = edge ? `${edge}-resize` : '';
}
});
+ block.addEventListener('wheel', event => {
+ if (!networkScaleWheelEnabled || networkState(block) || !event.deltaY) return;
+ event.preventDefault();
+ event.stopPropagation();
+ if (networkSelectedBlock !== block) selectNetworkBlock(block);
+ const current = Number(networkLayout[block.dataset.section]?.scale) || 100;
+ applyNetworkContentScale(current + (event.deltaY < 0 ? 5 : -5));
+ }, {passive: false});
block.addEventListener('pointerdown', event => {
if (event.defaultPrevented || block.classList.contains('is-resizing')) return;
startNetworkDrag(block, event);
@@ -3314,6 +3357,7 @@ HTML = """
selectNetworkBlock(networkBlocks.find(block => !networkState(block)) || null);
$('networkResetLayout')?.addEventListener('click', resetNetworkLayout);
$('networkDeleteSelected')?.addEventListener('click', deleteSelectedNetworkBlocks);
+ $('networkScaleMode')?.addEventListener('click', () => setNetworkScaleMode(!networkScaleWheelEnabled));
$('networkStructureToggle')?.addEventListener('click', () => {
networkStructureOpen = !networkStructureOpen;
renderNetworkStructure();