mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Phase 3 (slice): event-driven UI plumbing + Mute through controller
Vertical slice to establish the Phase 3 pattern before replicating it across all commands: logic moves into controller commands, the UI becomes event-driven, and frontends call commands instead of poking widgets. - TRadioController.SetMute now carries the real logic (state + FDSPEngine. SetMute), then fires OnStateChanged(rfMute). - MainForm subscribes via OnControllerState (controller -> UI). It restyles BtnMute from controller state. FSyncingFromController guards against re-entrancy when a programmatic widget change would retrigger OnChange. - BtnMuteClick -> FController.ToggleMute; SyncWebMute -> FController.SetMute. The button/web no longer own the mute logic or the restyle. Proves the command/event/refresh loop end-to-end (UI click and web both route through the controller). Remaining commands follow this pattern. Builds clean (cocoa); behavior unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2cf01036a3
commit
b577a0d67a
+30
-7
@@ -149,6 +149,9 @@ type
|
||||
// RadioController.pas. Поля состояния/движков теперь живут в
|
||||
// FController; обращения идут как FController.FXxx. ----
|
||||
FController: TRadioController;
|
||||
// True пока OnControllerState обновляет виджеты — чтобы программное
|
||||
// изменение слайдера/кнопки не вызывало повторно команду из OnChange.
|
||||
FSyncingFromController: Boolean;
|
||||
|
||||
// ---- Network ----
|
||||
FDevices: array of TDeviceItem;
|
||||
@@ -368,6 +371,7 @@ type
|
||||
|
||||
// ---- Helpers ----
|
||||
procedure DoInvoke(M: TThreadMethod); // маршалинг команд контроллера в UI-поток
|
||||
procedure OnControllerState(Sender: TObject; Field: TRadioField); // контроллер → UI
|
||||
procedure BuildUI;
|
||||
function LeftPanelButtonLeft(PanelWidth, ColCount, ColIndex: Integer): Integer;
|
||||
function LeftPanelButtonWidth(PanelWidth, ColCount, ColIndex: Integer): Integer;
|
||||
@@ -1065,6 +1069,7 @@ begin
|
||||
// освобождаются здесь же (в полях FController) — Фаза 1 миграции.
|
||||
FController := TRadioController.Create;
|
||||
FController.OnInvoke := DoInvoke;
|
||||
FController.OnStateChanged := OnControllerState;
|
||||
FController.FVfoA := 14200000;
|
||||
FController.FVfoB := 7100000;
|
||||
FController.FActiveVfo := 0;
|
||||
@@ -1410,6 +1415,28 @@ begin
|
||||
TThread.Synchronize(nil, M);
|
||||
end;
|
||||
|
||||
// Контроллер изменил состояние — обновляем соответствующие виджеты.
|
||||
// Выполняется в UI-потоке (команды контроллера вызываются из UI-потока либо
|
||||
// маршалятся адаптерами). FSyncingFromController защищает от рекурсии, когда
|
||||
// программное изменение виджета триггерит его OnChange.
|
||||
procedure TMainForm.OnControllerState(Sender: TObject; Field: TRadioField);
|
||||
begin
|
||||
FSyncingFromController := True;
|
||||
try
|
||||
case Field of
|
||||
rfMute:
|
||||
begin
|
||||
StyleButton(BtnMute, FController.FMuted);
|
||||
if FController.FMuted then BtnMute.Caption := 'UNMUTE'
|
||||
else BtnMute.Caption := 'MUTE';
|
||||
BtnMute.Invalidate;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
FSyncingFromController := False;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||
begin
|
||||
// Сохраняем позицию здесь — окно ещё полностью видимо и стабильно.
|
||||
@@ -5830,11 +5857,8 @@ end;
|
||||
|
||||
procedure TMainForm.BtnMuteClick(Sender: TObject);
|
||||
begin
|
||||
FController.FMuted := not FController.FMuted;
|
||||
StyleButton(BtnMute, FController.FMuted);
|
||||
if FController.FMuted then BtnMute.Caption := 'UNMUTE'
|
||||
else BtnMute.Caption := 'MUTE';
|
||||
if FController.FWDSPReady then FController.FDSPEngine.SetMute(FController.FMuted);
|
||||
if FSyncingFromController then Exit;
|
||||
FController.ToggleMute; // логика (движок) + OnControllerState обновит кнопку
|
||||
end;
|
||||
|
||||
procedure TMainForm.UpdateNRButton;
|
||||
@@ -6430,8 +6454,7 @@ end;
|
||||
|
||||
procedure TMainForm.SyncWebMute;
|
||||
begin
|
||||
if FWebSyncBool <> FController.FMuted then
|
||||
BtnMuteClick(nil);
|
||||
FController.SetMute(FWebSyncBool); // идемпотентно; OnControllerState обновит UI
|
||||
end;
|
||||
|
||||
// ── CTUN ──────────────────────────────────────────────────────────────────
|
||||
|
||||
+5
-1
@@ -397,7 +397,11 @@ procedure TRadioController.VolumeBy(Delta: Integer);
|
||||
begin SetVolume(FVolume + Delta); end;
|
||||
|
||||
procedure TRadioController.SetMute(On_: Boolean);
|
||||
begin FMuted := On_; Changed(rfMute); { TODO wiring } end;
|
||||
begin
|
||||
FMuted := On_;
|
||||
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetMute(FMuted);
|
||||
Changed(rfMute);
|
||||
end;
|
||||
|
||||
procedure TRadioController.ToggleMute;
|
||||
begin SetMute(not FMuted); end;
|
||||
|
||||
Reference in New Issue
Block a user