ui(vfo): колесо мыши прокручивает список устройств в AUD

VfoOverlay запоминает прямоугольник списка (FAudListRect) и обрабатывает
колесо над ним (HandleMouseWheel): шаг = одна строка. Если курсор в этой
зоне, событие считается обработанным и не уходит в спектр — частота не
съезжает даже когда список целиком помещается и крутить нечего.

PanafallPanel.DispatchFlagsMouseWheel перебирает главный флаг и флаги
слайсов (как остальные Dispatch*), MainForm.FormMouseWheel зовёт его по
всем панам первым делом после дисплеев VFO; координаты берутся через
PbSpectrum.ScreenToClient(Mouse.CursorPos), поэтому работает и в pop-out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 09:29:32 +03:00
co-authored by Claude Opus 4.8
parent fb1c263460
commit c986232891
3 changed files with 57 additions and 0 deletions
+15
View File
@@ -7885,12 +7885,27 @@ var
SLo, SHi, SNew: Double; SLo, SHi, SNew: Double;
Sl: TCtrlSlice; Sl: TCtrlSlice;
SlicePan: TPanafallPanel; SlicePan: TPanafallPanel;
P: TPoint;
begin begin
// Над дисплеем VFO (A или B) колесо обрабатывает сам TFreqDisplay поразрядно // Над дисплеем VFO (A или B) колесо обрабатывает сам TFreqDisplay поразрядно
// (включая неактивный VFO). Не дублируем здесь, иначе менялись бы обе частоты: // (включая неактивный VFO). Не дублируем здесь, иначе менялись бы обе частоты:
// виджет крутил бы B, а этот хендлер — активный A. // виджет крутил бы B, а этот хендлер — активный A.
if OverFreqDisp(FreqDispA) or OverFreqDisp(FreqDispB) then Exit; 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; SliceId := 0;
SlicePan := nil; SlicePan := nil;
+21
View File
@@ -292,6 +292,7 @@ type
procedure DispatchFlagsMouseMove(X, Y: Integer); procedure DispatchFlagsMouseMove(X, Y: Integer);
function DispatchFlagsMouseUp(X, Y: Integer): Boolean; function DispatchFlagsMouseUp(X, Y: Integer): Boolean;
procedure DispatchFlagsMouseLeave; procedure DispatchFlagsMouseLeave;
function DispatchFlagsMouseWheel(X, Y, WheelDelta: Integer): Boolean;
property Controller: TRadioController read FController write FController; property Controller: TRadioController read FController write FController;
property MainFlag: TVfoOverlay read FMainFlag; property MainFlag: TVfoOverlay read FMainFlag;
@@ -1557,4 +1558,24 @@ begin
if FSliceFlags[i] <> nil then FSliceFlags[i].HandleMouseLeave; if FSliceFlags[i] <> nil then FSliceFlags[i].HandleMouseLeave;
end; 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. end.
+21
View File
@@ -101,6 +101,7 @@ type
FPanel: TFlyPanel; // открытая fly-out панель FPanel: TFlyPanel; // открытая fly-out панель
FAudScroll: Integer; // прокрутка списка аудио-устройств (верхний индекс) FAudScroll: Integer; // прокрутка списка аудио-устройств (верхний индекс)
FAudListRect: TRect; // область списка AUD (лок. коорд.) — зона колёсика
FVolTrack: TRect; // трек громкости (локальные координаты) FVolTrack: TRect; // трек громкости (локальные координаты)
FVolDrag: Boolean; FVolDrag: Boolean;
FSqlTrack: TRect; // трек squelch в DSP-панели (лок. координаты) FSqlTrack: TRect; // трек squelch в DSP-панели (лок. координаты)
@@ -196,6 +197,8 @@ type
function HandleMouseMove(X, Y: Integer): Boolean; function HandleMouseMove(X, Y: Integer): Boolean;
function HandleMouseUp(X, Y: Integer): Boolean; function HandleMouseUp(X, Y: Integer): Boolean;
function HandleMouseLeave: Boolean; function HandleMouseLeave: Boolean;
// Колесо над списком устройств AUD (координаты — как у HandleMouseDown).
function HandleMouseWheel(X, Y, WheelDelta: Integer): Boolean;
procedure SetState(AMode, ABW: Integer; AVfoHz, ASMeterDB: Double); procedure SetState(AMode, ABW: Integer; AVfoHz, ASMeterDB: Double);
procedure SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean; procedure SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean;
AAGCMode: Integer); AAGCMode: Integer);
@@ -1015,6 +1018,7 @@ begin
end; end;
VisN := Min(Cnt, AUD_MAX_VIS); VisN := Min(Cnt, AUD_MAX_VIS);
FAudListRect := Rect(X, Y, X + RowW, Y + VisN*AUD_ROW_H); // зона колёсика
Scrollable := Cnt > AUD_MAX_VIS; Scrollable := Cnt > AUD_MAX_VIS;
MaxScroll := Cnt - VisN; MaxScroll := Cnt - VisN;
if FAudScroll > MaxScroll then FAudScroll := MaxScroll; if FAudScroll > MaxScroll then FAudScroll := MaxScroll;
@@ -1093,6 +1097,7 @@ var
BarL, BarW, MeterX: Integer; BarL, BarW, MeterX: Integer;
begin begin
FHitCount := 0; FHitCount := 0;
FAudListRect := Rect(0, 0, 0, 0); // выставит DrawAudPanel, если панель открыта
// Фон карточки // Фон карточки
C.Brush.Color := CLR_CARD_BG; C.Brush.Color := CLR_CARD_BG;
@@ -1506,6 +1511,22 @@ begin
Result := True; // клик был по накладке — не пускаем его в спектр Result := True; // клик был по накладке — не пускаем его в спектр
end; 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; function TVfoOverlay.HandleMouseLeave: Boolean;
begin begin
Result := False; Result := False;