From eb10283c850d8ea598c9817afac82a4bef9fca43 Mon Sep 17 00:00:00 2001 From: Uladzimir Karpenka Date: Thu, 4 Jun 2026 20:25:55 +0300 Subject: [PATCH] Phase 3 (batch 12): consolidate VFO B tuning into controller command The "set VFO B" engine block was duplicated inline across three tune paths (DoSpectrumClick, DoSpectrumDrag, FreqDispBChanged), each subtly different (drag had no band-detect/ruler; click had no drive recalc). - TRadioController.SetVfoB(Hz): always stores FVfoB; when B is the active VFO, retunes the receiver (DDC=VFO B, no CTUN, shift 0), HF band-detects (FCurrentBand + drive recalc -> Changed(rfBand)) and pushes to the radio; when B is inactive (split, listening on A) it only stores the freq for TX. Fires Changed(rfVfoB). - OnControllerState(rfVfoB): renders FreqDispB and, when B active, the spectrum/ruler (deferred via FSpectrumDirty, matching the rfVfoA path). The three call sites collapse to a single FController.SetVfoB(...) each; FreqDispBChanged is now a one-liner. Behavior unified: click/FreqDispB drop from sync DrawSpectrum to deferred (consistent with VFO A click-to-tune, imperceptible); drag gains band-detect + ruler refresh; click gains drive recalc on band change. Net -23 lines. Left inline (not identical): DoWidebandClick VFO B (extra XVTR clamp + wideband-specific render) and SyncWebFreq (uses SetRunAndFreq, the web/run network path, not UpdateState+SendFullHP). Builds clean, links. Co-Authored-By: Claude Opus 4.8 --- MainForm.pas | 81 ++++++++++----------------------------------- RadioController.pas | 26 ++++++++++++++- 2 files changed, 42 insertions(+), 65 deletions(-) diff --git a/MainForm.pas b/MainForm.pas index 38bca4c..f241616 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -1410,6 +1410,18 @@ begin if PbWaterfall <> nil then PbWaterfall.Invalidate; end; end; + rfVfoB: + begin + FreqDispB.Frequency := Round(FController.FVfoB); + if FController.FActiveVfo = 1 then + begin + FSpecView.InvalidateRulerCache; + SyncSpecViewFreq; + FSpectrumDirty := True; + PbSpectrum.Invalidate; + if PbRuler <> nil then PbRuler.Invalidate; + end; + end; rfBand: for i := 0 to BAND_COUNT - 1 do StyleButton(BtnBand[i], i = FController.FCurrentBand); @@ -4485,35 +4497,10 @@ begin end; procedure TMainForm.FreqDispBChanged(Sender: TObject; NewFreq: Int64); -var - BandIdx: Integer; begin - FController.FVfoB := NewFreq; - if FController.FActiveVfo = 1 then - begin - // VFO-B активен: перестраиваем приёмник - FController.FCenterFreq := FController.FVfoB; - if FController.FWDSPReady then FController.FDSPEngine.SetShift(0.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); - FController.FNetwork.SendFullHP; - end; - // Обновляем диапазон - BandIdx := FreqToBandIdx(FController.FVfoB); - if (BandIdx >= 0) and (BandIdx <> FController.FCurrentBand) then - begin - StyleButton(BtnBand[FController.FCurrentBand], False); - FController.FCurrentBand := BandIdx; - StyleButton(BtnBand[FController.FCurrentBand], True); - FController.FDriveLevel := CalcDriveByte; - end; - FSpecView.InvalidateRulerCache; - SyncSpecViewFreq; - FSpecView.DrawSpectrum; - PbSpectrum.Invalidate; - if PbRuler <> nil then PbRuler.Invalidate; - end; + // Движок (сохранение B, перестройка при активном B, диапазон, сеть) — в + // контроллере; рендер — OnControllerState(rfVfoB). + FController.SetVfoB(NewFreq); end; // --------------------------------------------------------------------------- @@ -4773,7 +4760,6 @@ procedure TMainForm.DoSpectrumClick(PixelX: Integer; PanelWidth: Integer); var ClickFreq: Int64; StepHz: Int64; - BandIdx: Integer; begin if PanelWidth <= 0 then Exit; if (FController.FMode = MODE_FM) and FController.FFMStepOn then @@ -4785,29 +4771,7 @@ begin if FController.FActiveVfo = 0 then ApplyVfoA(ClickFreq) else - begin - FController.FVfoB := ClickFreq; - FreqDispB.Frequency := Round(FController.FVfoB); - FController.FCenterFreq := ClickFreq; - if FController.FWDSPReady then FController.FDSPEngine.SetShift(0.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); - FController.FNetwork.SendFullHP; - end; - BandIdx := FreqToBandIdx(FController.FVfoB); - if (BandIdx >= 0) and (BandIdx <> FController.FCurrentBand) then - begin - StyleButton(BtnBand[FController.FCurrentBand], False); - FController.FCurrentBand := BandIdx; - StyleButton(BtnBand[FController.FCurrentBand], True); - end; - FSpecView.InvalidateRulerCache; - SyncSpecViewFreq; - FSpecView.DrawSpectrum; - PbSpectrum.Invalidate; - if PbRuler <> nil then PbRuler.Invalidate; - end; + FController.SetVfoB(ClickFreq); // движок + рендер через OnControllerState(rfVfoB) end; procedure TMainForm.DoWidebandClick(PixelX: Integer; PanelWidth: Integer); @@ -4931,18 +4895,7 @@ begin if FController.FActiveVfo = 0 then ApplyVfoA(Round(FSpecDragFreq - dFreq)) else - begin - FController.FVfoB := FSpecDragFreq - dFreq; - FreqDispB.Frequency := Round(FController.FVfoB); - FController.FCenterFreq := FController.FVfoB; - if FController.FWDSPReady then FController.FDSPEngine.SetShift(0.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); - FController.FNetwork.SendFullHP; - end; - FSpectrumDirty := True; - end; + FController.SetVfoB(FSpecDragFreq - dFreq); // движок + рендер (rfVfoB) end; end; diff --git a/RadioController.pas b/RadioController.pas index 57d5220..b233a31 100644 --- a/RadioController.pas +++ b/RadioController.pas @@ -571,7 +571,31 @@ begin end; procedure TRadioController.SetVfoB(Hz: Double); -begin FVfoB := Hz; Changed(rfVfoB); { TODO wiring } end; +// VFO B всегда сохраняется. Если B активен — перестраиваем приёмник (DDC=VFO B, +// без CTUN, сдвиг 0), детектим диапазон и толкаем в сеть. Если B неактивен +// (split, слушаем A) — только сохраняем частоту (используется для TX). +// Рендер FreqDispB/спектра — в UI через OnControllerState(rfVfoB). +var BandIdx: Integer; +begin + FVfoB := Hz; + if FActiveVfo = 1 then + begin + FCenterFreq := FVfoB; + if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0); + if FCurrentXvtr < 0 then + begin + BandIdx := FreqToBandIdx(FVfoB); + if (BandIdx >= 0) and (BandIdx <> FCurrentBand) then + begin + FCurrentBand := BandIdx; + FDriveLevel := CalcDriveByte; + Changed(rfBand); + end; + end; + PushNetworkState; + end; + Changed(rfVfoB); +end; procedure TRadioController.SetActiveVfo(Idx: Integer); begin FActiveVfo := Idx; Changed(rfActiveVfo); { TODO wiring: ActivateVfo } end;