diff --git a/MainForm.pas b/MainForm.pas index 80682d6..008abea 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -433,7 +433,6 @@ type procedure BtnFMRptMinusClick(Sender: TObject); procedure BtnFMRptPlusClick(Sender: TObject); procedure EdFMRptOffsetChange(Sender: TObject); - procedure ApplyFMRpt; procedure UpdateRptAutoState; procedure SetFMStep(Idx: Integer); procedure CloseFMStepPopup; @@ -1468,6 +1467,22 @@ begin end; rfFMCTCSSTone: if FCTCSSDropDown <> nil then FCTCSSDropDown.SetItemIndex(FController.FFMCTCSSToneIdx); + rfFMRpt: + begin + if BtnFMRptMinus <> nil then + begin + StyleButton(BtnFMRptMinus, FController.FFMRptDir = RPT_MINUS); + BtnFMRptMinus.Repaint; + end; + if BtnFMRptPlus <> nil then + begin + StyleButton(BtnFMRptPlus, FController.FFMRptDir = RPT_PLUS); + BtnFMRptPlus.Repaint; + end; + // Текст оффсета не трогаем, пока пользователь печатает в поле. + if (EdFMRptOffset <> nil) and not EdFMRptOffset.Focused then + EdFMRptOffset.Text := RptFormatOffset(FController.FFMRptOffsetHz); + end; end; finally FSyncingFromController := False; @@ -5241,91 +5256,41 @@ end; procedure TMainForm.BtnFMRptMinusClick(Sender: TObject); begin + if FSyncingFromController then Exit; + // Toggle решает UI; команда несёт сетевой сдвиг + рендер кнопок (OnControllerState). if FController.FFMRptDir = RPT_MINUS then - FController.FFMRptDir := RPT_NONE + FController.SetFMRpt(RPT_NONE) else - FController.FFMRptDir := RPT_MINUS; - FController.FFMRptAutoActive := False; // ручное действие снимает авто-флаг - StyleButton(BtnFMRptMinus, FController.FFMRptDir = RPT_MINUS); - StyleButton(BtnFMRptPlus, FController.FFMRptDir = RPT_PLUS); - BtnFMRptMinus.Repaint; - BtnFMRptPlus.Repaint; - ApplyFMRpt; + FController.SetFMRpt(RPT_MINUS); SaveCurrentBand; end; procedure TMainForm.BtnFMRptPlusClick(Sender: TObject); begin + if FSyncingFromController then Exit; if FController.FFMRptDir = RPT_PLUS then - FController.FFMRptDir := RPT_NONE + FController.SetFMRpt(RPT_NONE) else - FController.FFMRptDir := RPT_PLUS; - FController.FFMRptAutoActive := False; // ручное действие снимает авто-флаг - StyleButton(BtnFMRptMinus, FController.FFMRptDir = RPT_MINUS); - StyleButton(BtnFMRptPlus, FController.FFMRptDir = RPT_PLUS); - BtnFMRptMinus.Repaint; - BtnFMRptPlus.Repaint; - ApplyFMRpt; + FController.SetFMRpt(RPT_PLUS); SaveCurrentBand; end; procedure TMainForm.EdFMRptOffsetChange(Sender: TObject); var Hz: Double; begin + if FSyncingFromController then Exit; Hz := RptParseOffset(EdFMRptOffset.Text); if Hz > 0.0 then begin - FController.FFMRptOffsetHz := Hz; - if FController.FFMRptDir <> RPT_NONE then - begin - ApplyFMRpt; - SaveCurrentBand; - end; - end; -end; - -procedure TMainForm.ApplyFMRpt; -begin - if FController.FNetwork.Connected and FController.FNetwork.Running then - begin - FController.FNetwork.UpdateState(XvtrTranslate(FController.FCenterFreq), XvtrTranslate(ActiveTXFreqHz), - FController.FDriveLevel, FController.FTransmitting, True, True); - FController.FNetwork.SendFullHP; + FController.SetFMRptOffset(Hz); // применяет, если RPT вкл; OnControllerState + if FController.FFMRptDir <> RPT_NONE then SaveCurrentBand; end; end; procedure TMainForm.UpdateRptAutoState; -var InRange: Boolean; begin - InRange := RptAutoDir(FController.FVfoA) = RPT_MINUS; - if InRange then - begin - // Auto-enable minus only when currently off. - if FController.FFMRptDir = RPT_NONE then - begin - FController.FFMRptDir := RPT_MINUS; - FController.FFMRptAutoActive := True; - if BtnFMRptMinus <> nil then - begin - StyleButton(BtnFMRptMinus, True); - BtnFMRptMinus.Repaint; - end; - end; - end - else - begin - // Auto-disable only if this minus was set automatically. - if (FController.FFMRptDir = RPT_MINUS) and FController.FFMRptAutoActive then - begin - FController.FFMRptDir := RPT_NONE; - FController.FFMRptAutoActive := False; - if BtnFMRptMinus <> nil then - begin - StyleButton(BtnFMRptMinus, False); - BtnFMRptMinus.Repaint; - end; - end; - end; + // Логика авто-MINUS — в контроллере; рендер кнопок — OnControllerState(rfFMRpt). + FController.UpdateRptAutoState; end; procedure TMainForm.CloseFMStepPopup; diff --git a/RadioController.pas b/RadioController.pas index 2a812d9..ebc0ba1 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -110,6 +110,7 @@ type procedure Changed(Field: TRadioField); procedure ApplyAGCToEngine; // применяет FAGCMode к WDSP (единый маппинг) procedure ApplyModeDefaults; // дефолтный фильтр/девиация под текущий FMode + procedure PushNetworkState; // полный HP-кадр в радио (RX/TX freq+drive) public // ============================================================ // ПУБЛИЧНЫЕ ПОЛЯ (миграционные — имена совпадают с TMainForm). @@ -277,7 +278,9 @@ type procedure SetFMCTCSSTone(Idx: Integer); procedure SetFMSquelch(On_: Boolean); procedure SetFMSquelchLevel(V: Integer); - procedure SetFMRpt(Dir: Integer); + procedure SetFMRpt(Dir: Integer); // явное направление; снимает авто-флаг + procedure SetFMRptOffset(Hz: Double); // сдвиг репитера; применяет, если RPT вкл + procedure UpdateRptAutoState; // авто-MINUS для 2 м под FVfoA // Каналы procedure ApplyChannel(Idx: Integer); @@ -323,6 +326,18 @@ begin if Assigned(FOnStateChanged) then FOnStateChanged(Self, Field); end; +procedure TRadioController.PushNetworkState; +// Полный HP-кадр в радио: RX/TX частоты (через трансвертор), drive, состояние +// MOX. Вызывается командами, которые меняют центр/частоту/репитер-сдвиг. +begin + if Assigned(FNetwork) and FNetwork.Connected and FNetwork.Running then + begin + FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), + FDriveLevel, FTransmitting, True, True); + FNetwork.SendFullHP; + end; +end; + procedure TRadioController.Invoke(M: TThreadMethod); begin if Assigned(FOnInvoke) then FOnInvoke(M) @@ -586,12 +601,7 @@ begin // движок — FCenterFreq остаётся как есть, спектр не прыгает.) FCenterFreq := FVfoA; if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0); - if Assigned(FNetwork) and FNetwork.Connected and FNetwork.Running then - begin - FNetwork.UpdateState(XvtrTranslate(FCenterFreq), XvtrTranslate(ActiveTXFreqHz), - FDriveLevel, FTransmitting, True, True); - FNetwork.SendFullHP; - end; + PushNetworkState; end; Changed(rfCTun); end; @@ -682,7 +692,44 @@ begin end; procedure TRadioController.SetFMRpt(Dir: Integer); -begin FFMRptDir := Dir; Changed(rfFMRpt); { TODO wiring } end; +begin + FFMRptDir := Dir; + FFMRptAutoActive := False; // явная установка направления — ручное действие + PushNetworkState; // TX-сдвиг применяется через ActiveTXFreqHz + Changed(rfFMRpt); +end; + +procedure TRadioController.SetFMRptOffset(Hz: Double); +begin + if Hz <= 0.0 then Exit; + FFMRptOffsetHz := Hz; + if FFMRptDir <> RPT_NONE then PushNetworkState; + Changed(rfFMRpt); +end; + +procedure TRadioController.UpdateRptAutoState; +// Авто-включение MINUS-сдвига в 2-метровом репитерном сегменте и авто-снятие +// при уходе из него (только если MINUS был выставлен автоматически). +begin + if RptAutoDir(FVfoA) = RPT_MINUS then + begin + if FFMRptDir = RPT_NONE then + begin + FFMRptDir := RPT_MINUS; + FFMRptAutoActive := True; + Changed(rfFMRpt); + end; + end + else + begin + if (FFMRptDir = RPT_MINUS) and FFMRptAutoActive then + begin + FFMRptDir := RPT_NONE; + FFMRptAutoActive := False; + Changed(rfFMRpt); + end; + end; +end; procedure TRadioController.ApplyChannel(Idx: Integer); begin Changed(rfChannel); { TODO wiring } end;