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. Поля состояния/движков теперь живут в
|
// RadioController.pas. Поля состояния/движков теперь живут в
|
||||||
// FController; обращения идут как FController.FXxx. ----
|
// FController; обращения идут как FController.FXxx. ----
|
||||||
FController: TRadioController;
|
FController: TRadioController;
|
||||||
|
// True пока OnControllerState обновляет виджеты — чтобы программное
|
||||||
|
// изменение слайдера/кнопки не вызывало повторно команду из OnChange.
|
||||||
|
FSyncingFromController: Boolean;
|
||||||
|
|
||||||
// ---- Network ----
|
// ---- Network ----
|
||||||
FDevices: array of TDeviceItem;
|
FDevices: array of TDeviceItem;
|
||||||
@@ -368,6 +371,7 @@ type
|
|||||||
|
|
||||||
// ---- Helpers ----
|
// ---- Helpers ----
|
||||||
procedure DoInvoke(M: TThreadMethod); // маршалинг команд контроллера в UI-поток
|
procedure DoInvoke(M: TThreadMethod); // маршалинг команд контроллера в UI-поток
|
||||||
|
procedure OnControllerState(Sender: TObject; Field: TRadioField); // контроллер → UI
|
||||||
procedure BuildUI;
|
procedure BuildUI;
|
||||||
function LeftPanelButtonLeft(PanelWidth, ColCount, ColIndex: Integer): Integer;
|
function LeftPanelButtonLeft(PanelWidth, ColCount, ColIndex: Integer): Integer;
|
||||||
function LeftPanelButtonWidth(PanelWidth, ColCount, ColIndex: Integer): Integer;
|
function LeftPanelButtonWidth(PanelWidth, ColCount, ColIndex: Integer): Integer;
|
||||||
@@ -1065,6 +1069,7 @@ begin
|
|||||||
// освобождаются здесь же (в полях FController) — Фаза 1 миграции.
|
// освобождаются здесь же (в полях FController) — Фаза 1 миграции.
|
||||||
FController := TRadioController.Create;
|
FController := TRadioController.Create;
|
||||||
FController.OnInvoke := DoInvoke;
|
FController.OnInvoke := DoInvoke;
|
||||||
|
FController.OnStateChanged := OnControllerState;
|
||||||
FController.FVfoA := 14200000;
|
FController.FVfoA := 14200000;
|
||||||
FController.FVfoB := 7100000;
|
FController.FVfoB := 7100000;
|
||||||
FController.FActiveVfo := 0;
|
FController.FActiveVfo := 0;
|
||||||
@@ -1410,6 +1415,28 @@ begin
|
|||||||
TThread.Synchronize(nil, M);
|
TThread.Synchronize(nil, M);
|
||||||
end;
|
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);
|
procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
||||||
begin
|
begin
|
||||||
// Сохраняем позицию здесь — окно ещё полностью видимо и стабильно.
|
// Сохраняем позицию здесь — окно ещё полностью видимо и стабильно.
|
||||||
@@ -5830,11 +5857,8 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.BtnMuteClick(Sender: TObject);
|
procedure TMainForm.BtnMuteClick(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
FController.FMuted := not FController.FMuted;
|
if FSyncingFromController then Exit;
|
||||||
StyleButton(BtnMute, FController.FMuted);
|
FController.ToggleMute; // логика (движок) + OnControllerState обновит кнопку
|
||||||
if FController.FMuted then BtnMute.Caption := 'UNMUTE'
|
|
||||||
else BtnMute.Caption := 'MUTE';
|
|
||||||
if FController.FWDSPReady then FController.FDSPEngine.SetMute(FController.FMuted);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.UpdateNRButton;
|
procedure TMainForm.UpdateNRButton;
|
||||||
@@ -6430,8 +6454,7 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.SyncWebMute;
|
procedure TMainForm.SyncWebMute;
|
||||||
begin
|
begin
|
||||||
if FWebSyncBool <> FController.FMuted then
|
FController.SetMute(FWebSyncBool); // идемпотентно; OnControllerState обновит UI
|
||||||
BtnMuteClick(nil);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ── CTUN ──────────────────────────────────────────────────────────────────
|
// ── CTUN ──────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
+5
-1
@@ -397,7 +397,11 @@ procedure TRadioController.VolumeBy(Delta: Integer);
|
|||||||
begin SetVolume(FVolume + Delta); end;
|
begin SetVolume(FVolume + Delta); end;
|
||||||
|
|
||||||
procedure TRadioController.SetMute(On_: Boolean);
|
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;
|
procedure TRadioController.ToggleMute;
|
||||||
begin SetMute(not FMuted); end;
|
begin SetMute(not FMuted); end;
|
||||||
|
|||||||
Reference in New Issue
Block a user