From c986232891b8785163f342788a0cb7e4e0ea6e6a Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 22 Jul 2026 09:29:32 +0300 Subject: [PATCH] =?UTF-8?q?ui(vfo):=20=D0=BA=D0=BE=D0=BB=D0=B5=D1=81=D0=BE?= =?UTF-8?q?=20=D0=BC=D1=8B=D1=88=D0=B8=20=D0=BF=D1=80=D0=BE=D0=BA=D1=80?= =?UTF-8?q?=D1=83=D1=87=D0=B8=D0=B2=D0=B0=D0=B5=D1=82=20=D1=81=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=BE=D0=BA=20=D1=83=D1=81=D1=82=D1=80=D0=BE=D0=B9=D1=81?= =?UTF-8?q?=D1=82=D0=B2=20=D0=B2=20AUD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VfoOverlay запоминает прямоугольник списка (FAudListRect) и обрабатывает колесо над ним (HandleMouseWheel): шаг = одна строка. Если курсор в этой зоне, событие считается обработанным и не уходит в спектр — частота не съезжает даже когда список целиком помещается и крутить нечего. PanafallPanel.DispatchFlagsMouseWheel перебирает главный флаг и флаги слайсов (как остальные Dispatch*), MainForm.FormMouseWheel зовёт его по всем панам первым делом после дисплеев VFO; координаты берутся через PbSpectrum.ScreenToClient(Mouse.CursorPos), поэтому работает и в pop-out. Co-Authored-By: Claude Opus 4.8 --- MainForm.pas | 15 +++++++++++++++ PanafallPanel.pas | 21 +++++++++++++++++++++ VfoOverlay.pas | 21 +++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/MainForm.pas b/MainForm.pas index c07556c..3334ebb 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -7885,12 +7885,27 @@ var SLo, SHi, SNew: Double; Sl: TCtrlSlice; SlicePan: TPanafallPanel; + P: TPoint; begin // Над дисплеем VFO (A или B) колесо обрабатывает сам TFreqDisplay поразрядно // (включая неактивный VFO). Не дублируем здесь, иначе менялись бы обе частоты: // виджет крутил бы B, а этот хендлер — активный A. if OverFreqDisp(FreqDispA) or OverFreqDisp(FreqDispB) then Exit; + // Колесо над раскрытым списком устройств во флаге — прокрутка этого списка. + for i := 0 to MAX_PANS - 1 do + if (FPans[i] <> nil) and Assigned(FPans[i].PbSpectrum) and + FPans[i].PbSpectrum.Visible then + begin + P := FPans[i].PbSpectrum.ScreenToClient(Mouse.CursorPos); + if FPans[i].DispatchFlagsMouseWheel(P.X, P.Y, WheelDelta) then + begin + MarkPanDirty(FPans[i]); + Handled := True; + Exit; + end; + end; + // Колесо над маркером слайса (любого пана) — двигаем частоту ЭТОГО слайса. SliceId := 0; SlicePan := nil; diff --git a/PanafallPanel.pas b/PanafallPanel.pas index 35027a7..9f221d2 100644 --- a/PanafallPanel.pas +++ b/PanafallPanel.pas @@ -292,6 +292,7 @@ type procedure DispatchFlagsMouseMove(X, Y: Integer); function DispatchFlagsMouseUp(X, Y: Integer): Boolean; procedure DispatchFlagsMouseLeave; + function DispatchFlagsMouseWheel(X, Y, WheelDelta: Integer): Boolean; property Controller: TRadioController read FController write FController; property MainFlag: TVfoOverlay read FMainFlag; @@ -1557,4 +1558,24 @@ begin if FSliceFlags[i] <> nil then FSliceFlags[i].HandleMouseLeave; end; +// Колесо над раскрытым списком устройств во флаге: прокрутка списка вместо +// перестройки частоты. Координаты — в системе спектра (как у остальных Handle*). +function TPanafallPanel.DispatchFlagsMouseWheel(X, Y, WheelDelta: Integer): Boolean; +var i: Integer; +begin + Result := False; + if Assigned(FMainFlag) and FMainFlag.Visible then + begin + FActiveFlag := FMainFlag; + if FMainFlag.HandleMouseWheel(X, Y, WheelDelta) then Exit(True); + end; + for i := 0 to High(FSliceFlags) do + if (FSliceFlags[i] <> nil) and FSliceFlags[i].Visible then + begin + FActiveFlag := FSliceFlags[i]; + if FSliceFlags[i].HandleMouseWheel(X, Y, WheelDelta) then Exit(True); + end; + FActiveFlag := nil; +end; + end. diff --git a/VfoOverlay.pas b/VfoOverlay.pas index cb7c248..3bc84fc 100644 --- a/VfoOverlay.pas +++ b/VfoOverlay.pas @@ -101,6 +101,7 @@ type FPanel: TFlyPanel; // открытая fly-out панель FAudScroll: Integer; // прокрутка списка аудио-устройств (верхний индекс) + FAudListRect: TRect; // область списка AUD (лок. коорд.) — зона колёсика FVolTrack: TRect; // трек громкости (локальные координаты) FVolDrag: Boolean; FSqlTrack: TRect; // трек squelch в DSP-панели (лок. координаты) @@ -196,6 +197,8 @@ type function HandleMouseMove(X, Y: Integer): Boolean; function HandleMouseUp(X, Y: Integer): Boolean; function HandleMouseLeave: Boolean; + // Колесо над списком устройств AUD (координаты — как у HandleMouseDown). + function HandleMouseWheel(X, Y, WheelDelta: Integer): Boolean; procedure SetState(AMode, ABW: Integer; AVfoHz, ASMeterDB: Double); procedure SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean; AAGCMode: Integer); @@ -1015,6 +1018,7 @@ begin end; VisN := Min(Cnt, AUD_MAX_VIS); + FAudListRect := Rect(X, Y, X + RowW, Y + VisN*AUD_ROW_H); // зона колёсика Scrollable := Cnt > AUD_MAX_VIS; MaxScroll := Cnt - VisN; if FAudScroll > MaxScroll then FAudScroll := MaxScroll; @@ -1093,6 +1097,7 @@ var BarL, BarW, MeterX: Integer; begin FHitCount := 0; + FAudListRect := Rect(0, 0, 0, 0); // выставит DrawAudPanel, если панель открыта // Фон карточки C.Brush.Color := CLR_CARD_BG; @@ -1506,6 +1511,22 @@ begin Result := True; // клик был по накладке — не пускаем его в спектр end; +function TVfoOverlay.HandleMouseWheel(X, Y, WheelDelta: Integer): Boolean; +var + MaxScroll, Old: Integer; +begin + Result := False; + if (not Visible) or (FPanel <> fpAud) then Exit; + if not PtInRect(FAudListRect, Point(X - Left, Y - Top)) then Exit; + Result := True; // зона наша — колесо в спектр не пускаем + MaxScroll := AudRowCount - AUD_MAX_VIS; + if MaxScroll <= 0 then Exit; // список целиком виден — крутить нечего + Old := FAudScroll; + if WheelDelta > 0 then Dec(FAudScroll) else Inc(FAudScroll); + FAudScroll := EnsureRange(FAudScroll, 0, MaxScroll); + if FAudScroll <> Old then RequestInvalidate; +end; + function TVfoOverlay.HandleMouseLeave: Boolean; begin Result := False;