Phase 2: move widget-stored state into TRadioController

NR/NB modes, SNB/ANF flags, and drive % were stored only in the widgets
themselves (Btn*.Tag, TrkDrive.Position) — the last hard blocker to a
headless/daemon mode, since without those controls the state had nowhere
to live and CAT/Web read them directly.

- NR/NB: BtnNR.Tag/BtnNB.Tag -> FController.FNRMode/FNBMode (Integer).
- SNB/ANF: BtnSNB.Tag/BtnANF.Tag (0/1) -> FController.FSNB/FANF (Boolean).
- Drive %: TrkDrive.Position -> new FController.FDrivePercent; the slider
  is now pure input (TrkDriveChange pushes its value into the controller),
  while FDriveLevel stays the derived hardware byte.

Buttons/sliders become pure view+input: click handlers and UpdateXButton
read/write the controller field; CAT getters, the web snapshot, and
GetSnapshot all source state from the controller, not the widgets.

No behavioral change. Builds clean (cocoa).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Uladzimir Karpenka
2026-06-04 10:48:51 +03:00
co-authored by Claude Opus 4.8
parent 63eb2c701f
commit 2cf01036a3
2 changed files with 62 additions and 60 deletions
+56 -55
View File
@@ -841,17 +841,17 @@ function TMainForm.MakeGlobalSettings: TGlobalSettings;
var i: Integer;
begin
Result.Volume := FController.FVolume;
Result.DriveLevel := TrkDrive.Position;
Result.DriveLevel := FController.FDrivePercent;
Result.PAMaxPower := FController.FPAMaxPower;
for i := 0 to BAND_COUNT - 1 do
Result.PABandCal[i] := FController.FPABandCal[i];
for i := 0 to CFG_XVTR_COUNT - 1 do
Result.VHFBandCal[i] := FController.FVHFBandCal[i];
Result.ActiveVfo := FController.FActiveVfo;
Result.NRMode := BtnNR.Tag;
Result.NBMode := BtnNB.Tag;
Result.SNBEnabled := BtnSNB.Tag <> 0;
Result.ANFEnabled := BtnANF.Tag <> 0;
Result.NRMode := FController.FNRMode;
Result.NBMode := FController.FNBMode;
Result.SNBEnabled := FController.FSNB;
Result.ANFEnabled := FController.FANF;
Result.AGCSlope := 0;
Result.AGCHangThreshold := 100;
Result.WfAGCEnabled := FController.FWfAGCEnabled;
@@ -3191,10 +3191,10 @@ begin
FController.FCurrentBand,
FController.FRunning and FController.FNetwork.Connected,
FController.FRunning, FController.FMuted, FController.FCTun,
BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0,
FController.FNRMode, FController.FNBMode, FController.FSNB, FController.FANF,
FController.FCenterFreq, FController.FFilter,
FController.FVfoB, FController.FActiveVfo,
FController.FTransmitting, TrkDrive.Position,
FController.FTransmitting, FController.FDrivePercent,
FController.FAtten, FController.FTuning, FController.FDisplayDuplex,
FLastFwdW, FLastSWR, FController.FPAMaxPower,
WebStatusText, WebBoardText, WebIPText, WebSupplyText,
@@ -4041,10 +4041,10 @@ begin
if Assigned(FSampleRateOverlay) then
FSampleRateOverlay.SetCurrentRate(FController.FSampleRate);
end;
BtnNR.Tag := EnsureRange(G_Settings.NRMode, 0, 4); UpdateNRButton;
BtnNB.Tag := EnsureRange(G_Settings.NBMode, 0, 2); UpdateNBButton;
BtnSNB.Tag := Ord(G_Settings.SNBEnabled); UpdateSNBButton;
BtnANF.Tag := Ord(G_Settings.ANFEnabled); UpdateANFButton;
FController.FNRMode := EnsureRange(G_Settings.NRMode, 0, 4); UpdateNRButton;
FController.FNBMode := EnsureRange(G_Settings.NBMode, 0, 2); UpdateNBButton;
FController.FSNB := G_Settings.SNBEnabled; UpdateSNBButton;
FController.FANF := G_Settings.ANFEnabled; UpdateANFButton;
FController.FWfAGCEnabled := G_Settings.WfAGCEnabled;
FController.FWfNFEnabled := G_Settings.WfNFEnabled;
FController.FDitherEnabled := G_Settings.DitherEnabled;
@@ -4632,7 +4632,7 @@ begin
FPreChannelPower := -1;
FController.FDriveLevel := CalcDriveByte;
if FController.FWDSPReady then
FController.FDSPEngine.SetDriveLevel(TrkDrive.Position / 100.0);
FController.FDSPEngine.SetDriveLevel(FController.FDrivePercent / 100.0);
end;
end;
@@ -4758,7 +4758,7 @@ begin
StyleButton(BtnTUN, False);
FController.FDriveLevel := CalcDriveByte;
if FController.FWDSPReady then
FController.FDSPEngine.SetDriveLevel(TrkDrive.Position / 100.0);
FController.FDSPEngine.SetDriveLevel(FController.FDrivePercent / 100.0);
if FController.FNetwork.Connected and FController.FNetwork.Running then
begin
FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FController.FDriveLevel,
@@ -5531,7 +5531,7 @@ begin
// поэтому сохраняем оригинал в локальную переменную и восстанавливаем после.
if Ch.Power >= 0 then
begin
i := TrkDrive.Position; // запомнить до срабатывания OnChange
i := FController.FDrivePercent; // запомнить до срабатывания OnChange
TrkDrive.Position := EnsureRange(Ch.Power, 0, 100); // TrkDriveChange обновит FController.FDriveLevel и WDSP
if FPreChannelPower < 0 then
FPreChannelPower := i; // установить после (TrkDriveChange уже сбросил в -1)
@@ -5596,7 +5596,7 @@ begin
FPreChannelPower := -1;
FController.FDriveLevel := CalcDriveByte;
if FController.FWDSPReady then
FController.FDSPEngine.SetDriveLevel(TrkDrive.Position / 100.0);
FController.FDSPEngine.SetDriveLevel(FController.FDrivePercent / 100.0);
end;
end;
end;
@@ -5839,7 +5839,7 @@ end;
procedure TMainForm.UpdateNRButton;
begin
case BtnNR.Tag of
case FController.FNRMode of
1: BtnNR.Caption := 'NR';
2: BtnNR.Caption := 'NR2';
3: BtnNR.Caption := 'NR3';
@@ -5847,71 +5847,71 @@ begin
else
BtnNR.Caption := 'NR';
end;
StyleButton(BtnNR, BtnNR.Tag <> 0);
StyleButton(BtnNR, FController.FNRMode <> 0);
BtnNR.Invalidate;
end;
procedure TMainForm.UpdateNBButton;
begin
case BtnNB.Tag of
case FController.FNBMode of
1: BtnNB.Caption := 'NB';
2: BtnNB.Caption := 'NB2';
else
BtnNB.Caption := 'NB';
end;
StyleButton(BtnNB, BtnNB.Tag <> 0);
StyleButton(BtnNB, FController.FNBMode <> 0);
BtnNB.Invalidate;
end;
procedure TMainForm.UpdateSNBButton;
begin
BtnSNB.Caption := 'SNB';
StyleButton(BtnSNB, BtnSNB.Tag <> 0);
StyleButton(BtnSNB, FController.FSNB);
BtnSNB.Invalidate;
end;
procedure TMainForm.UpdateANFButton;
begin
BtnANF.Caption := 'ANF';
StyleButton(BtnANF, BtnANF.Tag <> 0);
StyleButton(BtnANF, FController.FANF);
BtnANF.Invalidate;
end;
procedure TMainForm.ApplyNoiseFilterButtonsToDSP;
begin
if not FController.FWDSPReady then Exit;
FController.FDSPEngine.SetNRMode(BtnNR.Tag);
FController.FDSPEngine.SetNBMode(BtnNB.Tag);
FController.FDSPEngine.SetSNB(BtnSNB.Tag <> 0);
FController.FDSPEngine.SetANF(BtnANF.Tag <> 0);
FController.FDSPEngine.SetNRMode(FController.FNRMode);
FController.FDSPEngine.SetNBMode(FController.FNBMode);
FController.FDSPEngine.SetSNB(FController.FSNB);
FController.FDSPEngine.SetANF(FController.FANF);
end;
procedure TMainForm.BtnNRClick(Sender: TObject);
begin
BtnNR.Tag := (BtnNR.Tag + 1) mod 5;
FController.FNRMode := (FController.FNRMode + 1) mod 5;
UpdateNRButton;
if FController.FWDSPReady then FController.FDSPEngine.SetNRMode(BtnNR.Tag);
if FController.FWDSPReady then FController.FDSPEngine.SetNRMode(FController.FNRMode);
end;
procedure TMainForm.BtnNBClick(Sender: TObject);
begin
BtnNB.Tag := (BtnNB.Tag + 1) mod 3;
FController.FNBMode := (FController.FNBMode + 1) mod 3;
UpdateNBButton;
if FController.FWDSPReady then FController.FDSPEngine.SetNBMode(BtnNB.Tag);
if FController.FWDSPReady then FController.FDSPEngine.SetNBMode(FController.FNBMode);
end;
procedure TMainForm.BtnSNBClick(Sender: TObject);
begin
BtnSNB.Tag := 1 - BtnSNB.Tag;
FController.FSNB := not FController.FSNB;
UpdateSNBButton;
if FController.FWDSPReady then FController.FDSPEngine.SetSNB(BtnSNB.Tag <> 0);
if FController.FWDSPReady then FController.FDSPEngine.SetSNB(FController.FSNB);
end;
procedure TMainForm.BtnANFClick(Sender: TObject);
begin
BtnANF.Tag := 1 - BtnANF.Tag;
FController.FANF := not FController.FANF;
UpdateANFButton;
if FController.FWDSPReady then FController.FDSPEngine.SetANF(BtnANF.Tag <> 0);
if FController.FWDSPReady then FController.FDSPEngine.SetANF(FController.FANF);
end;
@@ -5962,7 +5962,7 @@ begin
FVfoOverlay.Width := 260;
FVfoOverlay.Height := 136; // OVL_H_NORM — расширяется сам при открытии AGC-пикера
FVfoOverlay.SetState(FController.FMode, FController.FFilterBW, FController.FVfoA, FLastSMeter);
FVfoOverlay.SetDSPState(BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0, FController.FAGCMode);
FVfoOverlay.SetDSPState(FController.FNRMode, FController.FNBMode, FController.FSNB, FController.FANF, FController.FAGCMode);
FVfoOverlay.Visible := True;
PositionVfoOverlay;
end
@@ -6047,17 +6047,17 @@ begin
if Assigned(FVfoOverlay) and FVfoOverlay.Visible then
begin
FVfoOverlay.SetState(FController.FMode, FController.FFilterBW, FController.FVfoA, FLastSMeter);
FVfoOverlay.SetDSPState(BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0, FController.FAGCMode);
FVfoOverlay.SetDSPState(FController.FNRMode, FController.FNBMode, FController.FSNB, FController.FANF, FController.FAGCMode);
PositionVfoOverlay; // перепозиционируем при смене LSB↔USB
end;
end;
procedure TMainForm.OnVfoOverlayDSPChange(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
begin
BtnNR.Tag := NRMode; UpdateNRButton;
BtnNB.Tag := NBMode; UpdateNBButton;
BtnSNB.Tag := Ord(SNBOn); UpdateSNBButton;
BtnANF.Tag := Ord(ANFOn); UpdateANFButton;
FController.FNRMode := NRMode; UpdateNRButton;
FController.FNBMode := NBMode; UpdateNBButton;
FController.FSNB := SNBOn; UpdateSNBButton;
FController.FANF := ANFOn; UpdateANFButton;
ApplyNoiseFilterButtonsToDSP;
end;
@@ -6462,11 +6462,11 @@ procedure TMainForm.SyncWebNR;
begin
if FWebSyncInt < 0 then FWebSyncInt := 0;
if FWebSyncInt > 4 then FWebSyncInt := 4;
if BtnNR.Tag <> FWebSyncInt then
if FController.FNRMode <> FWebSyncInt then
begin
BtnNR.Tag := FWebSyncInt;
FController.FNRMode := FWebSyncInt;
UpdateNRButton;
if FController.FWDSPReady then FController.FDSPEngine.SetNRMode(BtnNR.Tag);
if FController.FWDSPReady then FController.FDSPEngine.SetNRMode(FController.FNRMode);
end;
end;
@@ -6483,11 +6483,11 @@ procedure TMainForm.SyncWebNB;
begin
if FWebSyncInt < 0 then FWebSyncInt := 0;
if FWebSyncInt > 2 then FWebSyncInt := 2;
if BtnNB.Tag <> FWebSyncInt then
if FController.FNBMode <> FWebSyncInt then
begin
BtnNB.Tag := FWebSyncInt;
FController.FNBMode := FWebSyncInt;
UpdateNBButton;
if FController.FWDSPReady then FController.FDSPEngine.SetNBMode(BtnNB.Tag);
if FController.FWDSPReady then FController.FDSPEngine.SetNBMode(FController.FNBMode);
end;
end;
@@ -6500,7 +6500,7 @@ end;
procedure TMainForm.SyncWebSNB;
begin
if FWebSyncBool <> (BtnSNB.Tag <> 0) then
if FWebSyncBool <> (FController.FSNB) then
BtnSNBClick(BtnSNB);
end;
@@ -6515,7 +6515,7 @@ end;
procedure TMainForm.SyncWebANF;
begin
if FWebSyncBool <> (BtnANF.Tag <> 0) then
if FWebSyncBool <> (FController.FANF) then
BtnANFClick(BtnANF);
end;
@@ -6690,10 +6690,11 @@ end;
procedure TMainForm.TrkDriveChange(Sender: TObject);
begin
FController.FDrivePercent := TrkDrive.Position; // слайдер — ввод; контроллер — истина
FPreChannelPower := -1; // ручное изменение снимает сохранённую мощность канала
FController.FDriveLevel := CalcDriveByte;
if FController.FWDSPReady then
FController.FDSPEngine.SetDriveLevel(TrkDrive.Position / 100.0);
FController.FDSPEngine.SetDriveLevel(FController.FDrivePercent / 100.0);
if FController.FNetwork.Connected and FController.FNetwork.Running then
begin
FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), XvtrTranslate(ActiveTXFreqHz), FController.FDriveLevel, FController.FTransmitting, True, True);
@@ -6739,9 +6740,9 @@ begin
else
begin
if XvtrActive then
Pos := Round(TrkDrive.Position * FController.FXvtrSettings.Entries[FController.FCurrentXvtr].TXPower / 100.0)
Pos := Round(FController.FDrivePercent * FController.FXvtrSettings.Entries[FController.FCurrentXvtr].TXPower / 100.0)
else
Pos := TrkDrive.Position;
Pos := FController.FDrivePercent;
end;
if Pos <= 0 then begin Result := 0; Exit; end;
@@ -7750,13 +7751,13 @@ function TMainForm.CATGetMode: Integer; begin Result := FController.FMode;
function TMainForm.CATGetActiveVfo: Integer; begin Result := FController.FActiveVfo; end;
function TMainForm.CATGetAGCMode: Integer; begin Result := FController.FAGCMode; end;
function TMainForm.CATGetVolume: Integer; begin Result := FController.FVolume; end;
function TMainForm.CATGetDriveLevel: Integer;begin Result := TrkDrive.Position; end;
function TMainForm.CATGetDriveLevel: Integer;begin Result := FController.FDrivePercent; end;
function TMainForm.CATGetFilterIdx: Integer; begin Result := FController.FFilter; end;
function TMainForm.CATGetFilterBW: Integer; begin Result := FController.FFilterBW; end;
function TMainForm.CATGetNRMode: Integer; begin Result := BtnNR.Tag; end;
function TMainForm.CATGetNBMode: Integer; begin Result := BtnNB.Tag; end;
function TMainForm.CATGetSNB: Boolean; begin Result := BtnSNB.Tag <> 0; end;
function TMainForm.CATGetANF: Boolean; begin Result := BtnANF.Tag <> 0; end;
function TMainForm.CATGetNRMode: Integer; begin Result := FController.FNRMode; end;
function TMainForm.CATGetNBMode: Integer; begin Result := FController.FNBMode; end;
function TMainForm.CATGetSNB: Boolean; begin Result := FController.FSNB; end;
function TMainForm.CATGetANF: Boolean; begin Result := FController.FANF; end;
function TMainForm.CATGetTX: Boolean; begin Result := FController.FTransmitting; end;
function TMainForm.CATGetRunning: Boolean; begin Result := FController.FRunning; end;
function TMainForm.CATGetSMeter: Double; begin Result := FLastSMeter; end;