From acf73c73c71366a9afd1dadcd02f77167f353dae Mon Sep 17 00:00:00 2001 From: rouggy Date: Sat, 1 Aug 2026 19:55:42 +0200 Subject: [PATCH] fix(panels): the wheel moved whatever slider the pointer was over MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rig-panel sliders take a non-passive wheel listener and acted on hover, so scrolling the panel fed the gesture to whichever control sat under the cursor — RF power included, mid-QSO. An operator scrolling to read the bottom of the panel could change his transmit power without touching anything. They now require focus, i.e. a deliberate click on that slider first. Without it the event is left alone and the panel scrolls, which is what the operator meant. Same fix on the Flex and Yaesu panels, which share the pattern. This is a fault in its own right. It is NOT an explanation for the "transmit power moves since 0.22.8" report: that release changed nothing in the Icom path, and this behaviour is older than it. --- changelog.json | 6 ++++-- frontend/src/components/FlexPanel.tsx | 7 +++++++ frontend/src/components/IcomPanel.tsx | 7 +++++++ frontend/src/components/YaesuPanel.tsx | 7 +++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/changelog.json b/changelog.json index 8ee562b..64c6340 100644 --- a/changelog.json +++ b/changelog.json @@ -4,11 +4,13 @@ "date": "", "en": [ "Awards: the CW / Phone / Digital filter now applies to the whole award — bands, counts, confirmations and the contacts behind a cell — instead of only hiding rows from the reference list.", - "Yaesu and Kenwood: a new option lowers the DTR and RTS lines on connect, for interfaces that read either as PTT and keep the radio transmitting while OpsLog is open. Off by default — lowering them stops other interfaces transmitting at all." + "Yaesu and Kenwood: a new option lowers the DTR and RTS lines on connect, for interfaces that read either as PTT and keep the radio transmitting while OpsLog is open. Off by default — lowering them stops other interfaces transmitting at all.", + "Rig panels: the mouse wheel only moves a slider you have clicked on first. Scrolling the panel used to change whatever control the pointer happened to be over — including transmit power." ], "fr": [ "Diplômes : le filtre CW / Phonie / Numérique s’applique désormais à tout le diplôme — bandes, comptes, confirmations et QSO derrière une case — au lieu de masquer seulement des lignes de la liste des références.", - "Yaesu et Kenwood : une option abaisse les lignes DTR et RTS à la connexion, pour les interfaces qui les lisent comme PTT et laissent la radio en émission tant qu’OpsLog est ouvert. Désactivée par défaut — les abaisser empêche d’autres interfaces d’émettre." + "Yaesu et Kenwood : une option abaisse les lignes DTR et RTS à la connexion, pour les interfaces qui les lisent comme PTT et laissent la radio en émission tant qu’OpsLog est ouvert. Désactivée par défaut — les abaisser empêche d’autres interfaces d’émettre.", + "Panneaux radio : la molette n’agit que sur un curseur préalablement cliqué. Faire défiler le panneau modifiait le réglage survolé par le pointeur — y compris la puissance d’émission." ] }, { diff --git a/frontend/src/components/FlexPanel.tsx b/frontend/src/components/FlexPanel.tsx index d9c53f5..697bef1 100644 --- a/frontend/src/components/FlexPanel.tsx +++ b/frontend/src/components/FlexPanel.tsx @@ -86,6 +86,13 @@ function Slider({ value, onChange, disabled, accent = '#16a34a', step = 1, max = if (!el) return; const onWheel = (e: WheelEvent) => { if (disRef.current) return; + // The wheel only acts on a slider the operator has DELIBERATELY taken + // hold of — one that has focus. Hovering was enough before, so scrolling + // the panel with the pointer anywhere over these controls silently moved + // whatever sat under it: an IC-7800 owner watched his transmit power + // change on its own. Without focus the event is left alone and the panel + // scrolls, which is what the gesture was for. + if (document.activeElement !== el) return; e.preventDefault(); const d = e.deltaY < 0 ? stepRef.current : -stepRef.current; const nv = Math.max(0, Math.min(maxRef.current, valRef.current + d)); diff --git a/frontend/src/components/IcomPanel.tsx b/frontend/src/components/IcomPanel.tsx index 5dc9c7b..b759cae 100644 --- a/frontend/src/components/IcomPanel.tsx +++ b/frontend/src/components/IcomPanel.tsx @@ -125,6 +125,13 @@ function Slider({ value, onChange, disabled, accent = '#2563eb', step = 1 }: { if (!el) return; const onWheel = (e: WheelEvent) => { if (disRef.current) return; + // The wheel only acts on a slider the operator has DELIBERATELY taken + // hold of — one that has focus. Hovering was enough before, so scrolling + // the panel with the pointer anywhere over these controls silently moved + // whatever sat under it: an IC-7800 owner watched his transmit power + // change on its own. Without focus the event is left alone and the panel + // scrolls, which is what the gesture was for. + if (document.activeElement !== el) return; e.preventDefault(); const d = e.deltaY < 0 ? stepRef.current : -stepRef.current; const nv = Math.max(0, Math.min(100, valRef.current + d)); diff --git a/frontend/src/components/YaesuPanel.tsx b/frontend/src/components/YaesuPanel.tsx index 2506c0b..4c759b7 100644 --- a/frontend/src/components/YaesuPanel.tsx +++ b/frontend/src/components/YaesuPanel.tsx @@ -149,6 +149,13 @@ function Slider({ value, onChange, disabled, accent = 'var(--primary)', min = 0, if (!el) return; const onWheel = (e: WheelEvent) => { if (disRef.current) return; + // The wheel only acts on a slider the operator has DELIBERATELY taken + // hold of — one that has focus. Hovering was enough before, so scrolling + // the panel with the pointer anywhere over these controls silently moved + // whatever sat under it: an IC-7800 owner watched his transmit power + // change on its own. Without focus the event is left alone and the panel + // scrolls, which is what the gesture was for. + if (document.activeElement !== el) return; e.preventDefault(); const nv = Math.max(minRef.current, Math.min(maxRef.current, valRef.current + (e.deltaY < 0 ? 1 : -1))); if (nv !== valRef.current) cbRef.current(nv);