diff --git a/ChannelController.pas b/ChannelController.pas index fb9efed..e0dae70 100644 --- a/ChannelController.pas +++ b/ChannelController.pas @@ -12,10 +12,8 @@ unit ChannelController; // + мощность «до канала») — это снимает последний UI-блокер для headless-режима. // // Наружу юнит эмитит собственное событие OnActiveChanged (рендер кнопки Channel). -// Две UI-композитные XVTR-операции (вход/выход трансвертера с wideband-видом и -// web-пушем) пока живут в MainForm-обёртках — юнит зовёт их через колбэки -// OnActivateXvtr/OnDeactivateXvtr (сократятся при переносе xvtr render-extras в -// OnControllerState). +// Вход/выход трансвертера идёт через FRadio.SetXvtrBand (команда несёт DSP/сеть + +// рендер/wideband/web через rfXvtr) — host-колбэков у юнита больше нет. // ----------------------------------------------------------------------------- {$mode delphi}{$H+} @@ -29,8 +27,6 @@ uses type // Рендер активного канала: Active=True → подсветка + Name; False → сброс. TChannelActiveEvent = procedure(Idx: Integer; const Name: string; Active: Boolean) of object; - TChannelXvtrEvent = procedure(Idx: Integer) of object; - TChannelNotifyEvent = procedure of object; TChannelController = class private @@ -38,9 +34,8 @@ type FActiveIdx: Integer; // -1 = нет активного канала FPreChannelPower: Integer; // drive % до применения канала (-1 = не сохранён) FRestoringDrive: Boolean; // True пока юнит сам ставит drive (apply/restore) + FApplying: Boolean; // True пока идёт Apply (гасит промежуточный OnVfoTuned) FOnActiveChanged: TChannelActiveEvent; - FOnActivateXvtr: TChannelXvtrEvent; - FOnDeactivateXvtr: TChannelNotifyEvent; procedure EmitActive(Active: Boolean; const Name: string); procedure SetDriveGuarded(V: Integer); // SetDrive, не сбрасывающий память канала public @@ -54,8 +49,6 @@ type property ActiveIdx: Integer read FActiveIdx write FActiveIdx; property OnActiveChanged: TChannelActiveEvent read FOnActiveChanged write FOnActiveChanged; - property OnActivateXvtr: TChannelXvtrEvent read FOnActivateXvtr write FOnActivateXvtr; - property OnDeactivateXvtr: TChannelNotifyEvent read FOnDeactivateXvtr write FOnDeactivateXvtr; end; implementation @@ -107,6 +100,12 @@ procedure TChannelController.Apply(const Ch: TChannel); var i, NewBand, XvtrIdx: Integer; begin + // Промежуточные retune внутри Apply (XVTR-выход → RestoreBand → SetVfoA на + // СТАРУЮ частоту) фаерят OnAfterTune→OnVfoTuned; без этого гарда CheckActive + // деактивировал бы канал прямо посреди его применения. Финальное состояние + // (FActiveIdx + Ch.RXFreq) выставляем сами — оркестрация снаружи Apply. + FApplying := True; + try // Сохраняем текущее состояние до любых изменений FRadio.SaveCurrentBand; @@ -125,15 +124,15 @@ begin if XvtrIdx >= 0 then begin // Канал на трансвертерном диапазоне — активируем XVTR если не активен - if (FRadio.FCurrentXvtr <> XvtrIdx) and Assigned(FOnActivateXvtr) then - FOnActivateXvtr(XvtrIdx); + if FRadio.FCurrentXvtr <> XvtrIdx then + FRadio.SetXvtrBand(XvtrIdx); // вход в слот + рендер/wideband/web (rfXvtr) end else begin // Канал на HF (или неизвестная частота). Если были на XVTR — выходим в HF, // иначе SetVfoA заклэмпит частоту. - if (FRadio.FCurrentXvtr >= 0) and Assigned(FOnDeactivateXvtr) then - FOnDeactivateXvtr; + if FRadio.FCurrentXvtr >= 0 then + FRadio.SetXvtrBand(-1); // выход в HF (DeactivateXvtr несёт HF-возврат) NewBand := FreqToBandIdx(Ch.RXFreq); if (NewBand >= 0) and (NewBand <> FRadio.FCurrentBand) then FRadio.SetCurrentBandIdx(NewBand); // band-индекс + drive-кал + рендер кнопок @@ -170,6 +169,9 @@ begin // Сохраняем итог в band/XVTR-кэш if (XvtrIdx >= 0) or (NewBand >= 0) then FRadio.SaveCurrentBand; + finally + FApplying := False; + end; end; procedure TChannelController.CheckActive; @@ -217,6 +219,7 @@ procedure TChannelController.OnVfoTuned; // Без активного канала: сброс авто-CTCSS + восстановление pre-channel drive. // С активным каналом: CheckActive деактивирует при уходе с частоты канала. begin + if FApplying then Exit; // промежуточные retune внутри Apply — не трогаем канал if FActiveIdx < 0 then begin if FRadio.FFMCTCSSAutoActive then diff --git a/MainForm.pas b/MainForm.pas index 32b469b..f13423f 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -756,8 +756,6 @@ begin // XVTR-вход/выход — через UI-обёртки (wideband/web живут в них). FChannelController := TChannelController.Create(FController); FChannelController.OnActiveChanged := OnChannelActiveChanged; - FChannelController.OnActivateXvtr := ActivateXvtrBand; - FChannelController.OnDeactivateXvtr := DeactivateXvtr; // Канал-оркестрация фаером из контроллера в конце SetVfoA (любой путь тюнинга). FController.OnAfterTune := FChannelController.OnVfoTuned; FController.FVfoA := 14200000; @@ -1218,9 +1216,17 @@ begin StyleButton(BtnBand[i], (FController.FCurrentXvtr < 0) and (i = FController.FCurrentBand)); rfXvtr: - for i := 0 to CFG_XVTR_COUNT - 1 do - if BtnXvtrBand[i] <> nil then - StyleButton(BtnXvtrBand[i], i = FController.FCurrentXvtr); + begin + for i := 0 to CFG_XVTR_COUNT - 1 do + if BtnXvtrBand[i] <> nil then + StyleButton(BtnXvtrBand[i], i = FController.FCurrentXvtr); + // Wideband-вид + web-зеркало xvtr (ранее в обёртках Activate/Deactivate). + // rfXvtr эмитят ТОЛЬКО ActivateXvtr/DeactivateXvtr — состояние финальное. + UpdateWidebandFrequencyView; + if PbWideband <> nil then PbWideband.Invalidate; + if PbWidebandRuler <> nil then PbWidebandRuler.Invalidate; + PushXvtrToWeb; + end; rfBandRestore: // Явная смена диапазона: сброс порогов водопада (не на каждом тюне). FSpecView.ResetWfAvgBuf; @@ -5141,13 +5147,9 @@ end; // середине [FreqBegin..FreqEnd], применяет network XVTR-режим. procedure TMainForm.ActivateXvtrBand(Idx: Integer); begin - // Вход в XVTR-слот (state+DSP+VFO+сеть) — в контроллере; рендер кнопок/частот/ - // спектра — через события (rfXvtr/rfBand/rfActiveVfo). Здесь только UI: wideband+web. + // Тонкий делегат: вход в XVTR-слот + рендер кнопок/частот/спектра/wideband/web — + // всё в команде/событиях (rfXvtr/rfBand/rfActiveVfo). FController.ActivateXvtr(Idx); - UpdateWidebandFrequencyView; - if PbWideband <> nil then PbWideband.Invalidate; - if PbWidebandRuler <> nil then PbWidebandRuler.Invalidate; - PushXvtrToWeb; end; // Деактивирует XVTR — возвращает к HF-режиму. FController.FCurrentBand указывает @@ -5155,17 +5157,9 @@ end; // VFO/Mode/Filter/AGC/CTUN/Span этого диапазона и обновит подсветку HF band-кнопки. procedure TMainForm.DeactivateXvtr; begin - if FController.FCurrentXvtr < 0 then Exit; - // Сохранение слота + выход (+ гашение XVTR-кнопок через rfXvtr) — в контроллере. + // Тонкий делегат: выход в HF (SaveCurrentBand + HF-возврат RestoreBand + рендер + // кнопок/wideband/web) — всё в команде/событиях. FController.DeactivateXvtr; - // HF-возврат: состояние/DSP из кэша + финальная перестройка активного VFO - // (через UI-путь RestoreBand: ResetWfAvgBuf + controller.RestoreBand + ApplyVfoA/SetVfoB). - if (FController.FCurrentBand >= 0) and (FController.FCurrentBand < CFG_BAND_COUNT) then - RestoreBand(FController.FCurrentBand); - UpdateWidebandFrequencyView; - if PbWideband <> nil then PbWideband.Invalidate; - if PbWidebandRuler <> nil then PbWidebandRuler.Invalidate; - PushXvtrToWeb; end; procedure TMainForm.OnXvtrSettingsChange(const X: TXvtrSettings); diff --git a/RadioController.pas b/RadioController.pas index 591b7ab..65b1269 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -1631,15 +1631,19 @@ begin end; procedure TRadioController.DeactivateXvtr; -// Сохраняет текущий XVTR-слот и выходит в HF. Сам HF-возврат (RestoreBand + -// финальная перестройка активного VFO) делает UI-обёртка — там же ResetWfAvgBuf. +// Сохраняет текущий XVTR-слот и выходит в HF: HF-возврат (RestoreBand + финальная +// перестройка активного VFO + ResetWfAvgBuf через rfBandRestore) делается здесь. +// Changed(rfXvtr) шлём ПОСЛЕ RestoreBand — чтобы wideband/web-extras в его рендере +// увидели уже восстановленное HF-состояние. begin if FCurrentXvtr < 0 then Exit; SaveCurrentBand; // XVTR-ветка: пишет весь слот + SaveXvtr if FDevConnected then FSettings.Save; FCurrentXvtr := -1; ApplyXvtrToNetwork; // снять XVTR enable bit - Changed(rfXvtr); // погасить XVTR-кнопки + if (FCurrentBand >= 0) and (FCurrentBand < CFG_BAND_COUNT) then + RestoreBand(FCurrentBand); // HF-возврат (состояние/DSP/retune) + Changed(rfXvtr); // погасить XVTR-кнопки + wideband/web (rfXvtr-рендер) end; procedure TRadioController.SetXvtrBand(Idx: Integer);