feat(overlay): clickable TX badge with slice-select groundwork

TX-индикатор теперь кликабельный (хит HIT_TX → колбэк OnTxSelect) — задел
под выбор TX-слайса в мультислайсах. Три состояния цвета:
- передача идёт → красный;
- слайс выбран для TX → янтарный (CLR_TX_SEL);
- не выбран → нейтральный.

Новое состояние FTxSel прокидывается через SetExtState (пока True — один
слайс всегда TX-слайс). MainForm.OnVfoOverlayTxSelect — заглушка с TODO под
мультислайсы.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 17:10:34 +03:00
co-authored by Claude Opus 4.8
parent 6ad5f29657
commit 08c71c47ad
2 changed files with 31 additions and 10 deletions
+11 -1
View File
@@ -523,6 +523,7 @@ type
procedure OnVfoOverlayMute(Sender: TObject); procedure OnVfoOverlayMute(Sender: TObject);
procedure OnVfoOverlayAudioDevice(DevIndex: Integer; const DevName: string); procedure OnVfoOverlayAudioDevice(DevIndex: Integer; const DevName: string);
procedure OnVfoOverlaySplit(Sender: TObject); procedure OnVfoOverlaySplit(Sender: TObject);
procedure OnVfoOverlayTxSelect(Sender: TObject);
procedure PushVfoOverlayExtState; procedure PushVfoOverlayExtState;
procedure PushVfoOverlayAudioDevices; procedure PushVfoOverlayAudioDevices;
procedure OnVfoOverlayInvalidate(Sender: TObject); procedure OnVfoOverlayInvalidate(Sender: TObject);
@@ -966,6 +967,7 @@ begin
FVfoOverlay.OnMute := OnVfoOverlayMute; FVfoOverlay.OnMute := OnVfoOverlayMute;
FVfoOverlay.OnAudioDevice := OnVfoOverlayAudioDevice; FVfoOverlay.OnAudioDevice := OnVfoOverlayAudioDevice;
FVfoOverlay.OnSplit := OnVfoOverlaySplit; FVfoOverlay.OnSplit := OnVfoOverlaySplit;
FVfoOverlay.OnTxSelect := OnVfoOverlayTxSelect;
FVfoOverlay.OnInvalidate := OnVfoOverlayInvalidate; FVfoOverlay.OnInvalidate := OnVfoOverlayInvalidate;
FVfoOverlay.Visible := False; FVfoOverlay.Visible := False;
FPanelHidden := False; FPanelHidden := False;
@@ -5144,6 +5146,13 @@ begin
PushVfoOverlayExtState; PushVfoOverlayExtState;
end; end;
procedure TMainForm.OnVfoOverlayTxSelect(Sender: TObject);
begin
// TODO(слайсы): выбрать этот слайс как TX-слайс. Пока один слайс —
// он всегда TX-слайс, поэтому клик ничего не меняет (хук под мультислайсы).
PushVfoOverlayExtState;
end;
procedure TMainForm.OnVfoOverlayAudioDevice(DevIndex: Integer; const DevName: string); procedure TMainForm.OnVfoOverlayAudioDevice(DevIndex: Integer; const DevName: string);
begin begin
ApplyAudioDevice(DevIndex, DevName); ApplyAudioDevice(DevIndex, DevName);
@@ -5153,8 +5162,9 @@ end;
procedure TMainForm.PushVfoOverlayExtState; procedure TMainForm.PushVfoOverlayExtState;
begin begin
if not (Assigned(FVfoOverlay) and FVfoOverlay.Visible) then Exit; if not (Assigned(FVfoOverlay) and FVfoOverlay.Visible) then Exit;
// TxSel: этот слайс выбран для передачи. Пока слайс один → всегда True.
FVfoOverlay.SetExtState(FController.FVolume, FController.FMuted, FVfoOverlay.SetExtState(FController.FVolume, FController.FMuted,
FController.FSplitTxB, FController.FTransmitting); FController.FSplitTxB, FController.FTransmitting, True);
end; end;
procedure TMainForm.PushVfoOverlayAudioDevices; procedure TMainForm.PushVfoOverlayAudioDevices;
+20 -9
View File
@@ -49,7 +49,8 @@ type
FVolume: Integer; // 0..100 FVolume: Integer; // 0..100
FMuted: Boolean; FMuted: Boolean;
FSplit: Boolean; FSplit: Boolean;
FTx: Boolean; FTx: Boolean; // передача идёт (красный)
FTxSel: Boolean; // этот слайс выбран для передачи (янтарный)
FSlice: Char; // буква слайса ('A') FSlice: Char; // буква слайса ('A')
FDevNames: TStringList; // имена устройств вывода FDevNames: TStringList; // имена устройств вывода
@@ -67,6 +68,7 @@ type
FOnMute: TNotifyEvent; FOnMute: TNotifyEvent;
FOnAudioDevice: TAudioDeviceEvent; FOnAudioDevice: TAudioDeviceEvent;
FOnSplit: TNotifyEvent; FOnSplit: TNotifyEvent;
FOnTxSelect: TNotifyEvent;
FOnInvalidate: TNotifyEvent; FOnInvalidate: TNotifyEvent;
FHitRects: array[0..63] of TRect; FHitRects: array[0..63] of TRect;
@@ -118,7 +120,7 @@ type
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);
procedure SetExtState(AVolume: Integer; AMuted, ASplit, ATx: Boolean); procedure SetExtState(AVolume: Integer; AMuted, ASplit, ATx, ATxSel: Boolean);
procedure SetAudioDevices(Names: TStrings; const Indices: array of Integer; procedure SetAudioDevices(Names: TStrings; const Indices: array of Integer;
const CurName: string); const CurName: string);
procedure UpdateSMeter(DB: Double); procedure UpdateSMeter(DB: Double);
@@ -132,6 +134,7 @@ type
property OnMute: TNotifyEvent read FOnMute write FOnMute; property OnMute: TNotifyEvent read FOnMute write FOnMute;
property OnAudioDevice: TAudioDeviceEvent read FOnAudioDevice write FOnAudioDevice; property OnAudioDevice: TAudioDeviceEvent read FOnAudioDevice write FOnAudioDevice;
property OnSplit: TNotifyEvent read FOnSplit write FOnSplit; property OnSplit: TNotifyEvent read FOnSplit write FOnSplit;
property OnTxSelect: TNotifyEvent read FOnTxSelect write FOnTxSelect;
property OnInvalidate: TNotifyEvent read FOnInvalidate write FOnInvalidate; property OnInvalidate: TNotifyEvent read FOnInvalidate write FOnInvalidate;
end; end;
@@ -155,6 +158,7 @@ const
HIT_MUTE = -23; HIT_MUTE = -23;
HIT_VOL = -24; HIT_VOL = -24;
HIT_SPLIT = -25; HIT_SPLIT = -25;
HIT_TX = -26;
HIT_AGC_PICK_BASE = 100000; HIT_AGC_PICK_BASE = 100000;
HIT_DEV_BASE = 200000; HIT_DEV_BASE = 200000;
@@ -184,7 +188,8 @@ const
CLR_FREQ = TColor($0050FF80); CLR_FREQ = TColor($0050FF80);
CLR_SVAL = TColor($0030C8FF); CLR_SVAL = TColor($0030C8FF);
CLR_BAR_BG = TColor($00101010); CLR_BAR_BG = TColor($00101010);
CLR_TX_ON = TColor($000030E0); // красный TX (BGR) CLR_TX_ON = TColor($000030E0); // красный TX идёт (BGR)
CLR_TX_SEL = TColor($0010A8F0); // янтарный: слайс выбран для передачи
CLR_SPLIT_ON = TColor($0020C0FF); // оранжевый SPLIT CLR_SPLIT_ON = TColor($0020C0FF); // оранжевый SPLIT
OVL_MODE_COUNT = 8; OVL_MODE_COUNT = 8;
@@ -326,7 +331,8 @@ begin
FModeFilter[3] := 500; FModeFilter[4] := 500; FModeFilter[5] := 11000; FModeFilter[3] := 500; FModeFilter[4] := 500; FModeFilter[5] := 11000;
FModeFilter[6] := 8000; FModeFilter[7] := 8000; FModeFilter[6] := 8000; FModeFilter[7] := 8000;
FNRMode := 0; FNBMode := 0; FSNBOn := False; FANFOn := False; FAGCMode := 0; FNRMode := 0; FNBMode := 0; FSNBOn := False; FANFOn := False; FAGCMode := 0;
FVolume := 70; FMuted := False; FSplit := False; FTx := False; FSlice := 'A'; FVolume := 70; FMuted := False; FSplit := False; FTx := False;
FTxSel := True; FSlice := 'A';
FPanel := fpNone; FPanel := fpNone;
FVolDrag := False; FVolDrag := False;
FDevNames := TStringList.Create; FDevNames := TStringList.Create;
@@ -710,10 +716,13 @@ begin
C.Font.Name := 'Courier New'; C.Font.Size := 8; C.Font.Style := []; C.Font.Name := 'Courier New'; C.Font.Size := 8; C.Font.Style := [];
C.Font.Color := CLR_DIM; C.Brush.Style := bsClear; C.Font.Color := CLR_DIM; C.Brush.Style := bsClear;
C.TextOut(X + 22, CurY + 1, BWStr); C.TextOut(X + 22, CurY + 1, BWStr);
// TX badge (правый край) // TX badge (правый край) — кликабельно: выбор TX-слайса.
// передача идёт → красный; слайс выбран для TX → янтарный; иначе → нейтральный.
R := Rect(W - PAD - 26, CurY, W - PAD, CurY + HDR_BADGE_H); R := Rect(W - PAD - 26, CurY, W - PAD, CurY + HDR_BADGE_H);
if FTx then DrawBadge(C, R, 'TX', CLR_TX_ON, clWhite) if FTx then DrawBadge(C, R, 'TX', CLR_TX_ON, clWhite)
else DrawBadge(C, R, 'TX', CLR_BTN_NORM, CLR_DIM); else if FTxSel then DrawBadge(C, R, 'TX', CLR_TX_SEL, CLR_CARD_BG)
else DrawBadge(C, R, 'TX', CLR_BTN_NORM, CLR_DIM);
RegisterHit(R, HIT_TX);
// SPLIT (левее TX) — кликабельно // SPLIT (левее TX) — кликабельно
R := Rect(W - PAD - 26 - 44, CurY, W - PAD - 26 - 4, CurY + HDR_BADGE_H); R := Rect(W - PAD - 26 - 44, CurY, W - PAD - 26 - 4, CurY + HDR_BADGE_H);
if FSplit then DrawBadge(C, R, 'SPLIT', CLR_SPLIT_ON, CLR_CARD_BG) if FSplit then DrawBadge(C, R, 'SPLIT', CLR_SPLIT_ON, CLR_CARD_BG)
@@ -847,6 +856,7 @@ begin
HIT_MUTE: begin FMuted := not FMuted; RequestInvalidate; HIT_MUTE: begin FMuted := not FMuted; RequestInvalidate;
if Assigned(FOnMute) then FOnMute(Self); Exit; end; if Assigned(FOnMute) then FOnMute(Self); Exit; end;
HIT_SPLIT: begin if Assigned(FOnSplit) then FOnSplit(Self); Exit; end; HIT_SPLIT: begin if Assigned(FOnSplit) then FOnSplit(Self); Exit; end;
HIT_TX: begin if Assigned(FOnTxSelect) then FOnTxSelect(Self); Exit; end;
end; end;
// Устройство аудио // Устройство аудио
@@ -1055,14 +1065,15 @@ begin
RequestInvalidate; RequestInvalidate;
end; end;
procedure TVfoOverlay.SetExtState(AVolume: Integer; AMuted, ASplit, ATx: Boolean); procedure TVfoOverlay.SetExtState(AVolume: Integer; AMuted, ASplit, ATx, ATxSel: Boolean);
begin begin
if (AVolume = FVolume) and (AMuted = FMuted) and (ASplit = FSplit) if (AVolume = FVolume) and (AMuted = FMuted) and (ASplit = FSplit)
and (ATx = FTx) then Exit; and (ATx = FTx) and (ATxSel = FTxSel) then Exit;
if not FVolDrag then FVolume := AVolume; // во время drag ведём сами if not FVolDrag then FVolume := AVolume; // во время drag ведём сами
FMuted := AMuted; FMuted := AMuted;
FSplit := ASplit; FSplit := ASplit;
FTx := ATx; FTx := ATx;
FTxSel := ATxSel;
RequestInvalidate; RequestInvalidate;
end; end;