Phase 3 (batch 14): route VFO swap / A>B / B>A through controller

Filled the three VFO-transfer commands (the skeletons were also backwards:
VfoACopyB stored A:=B etc).

- VfoSwap: swaps A/B, retunes the receiver to the active VFO freq
  (center=freq, shift 0), HF band-detect, network push. Fires
  rfVfoA/rfVfoB/rfBand. UI handler is thin (+ ruler-cache invalidate, since
  a swap is a large freq jump).
- VfoACopyB (A>B): delegates to SetVfoB(FVfoA) — store B:=A, retune when B
  active, render via rfVfoB.
- VfoBCopyA (B>A): copies B->A; when A active goes through SetVfoA, else
  just fires rfVfoA. The desktop B>A handler still calls ApplyVfoA for the
  active-A case to preserve channel orchestration (auto-CTCSS / pre-channel
  drive), matching the original (A>B never had that path).

Net simplification; builds clean, links.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Uladzimir Karpenka
2026-06-04 21:17:50 +03:00
co-authored by Claude Opus 4.8
parent 38947113f5
commit a8a192a3a3
2 changed files with 41 additions and 63 deletions
+10 -57
View File
@@ -5395,78 +5395,31 @@ begin
end;
procedure TMainForm.BtnVfoSwapClick(Sender: TObject);
var
Tmp: Double;
BandIdx: Integer;
ActiveFreq: Int64;
begin
// Меняем частоты местами
Tmp := FController.FVfoA; FController.FVfoA := FController.FVfoB; FController.FVfoB := Tmp;
// Определяем новую частоту активного VFO
if FController.FActiveVfo = 0 then ActiveFreq := Round(FController.FVfoA)
else ActiveFreq := Round(FController.FVfoB);
// Перестраиваем приёмник
FController.FCenterFreq := ActiveFreq;
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(ActiveFreq);
if (BandIdx >= 0) and (BandIdx <> FController.FCurrentBand) then
begin
StyleButton(BtnBand[FController.FCurrentBand], False);
FController.FCurrentBand := BandIdx;
StyleButton(BtnBand[FController.FCurrentBand], True);
end;
// Своп + перестройка — в контроллере; рендер дисплеев/спектра/band — через
// OnControllerState(rfVfoA/rfVfoB/rfBand). Кэш линейки сбрасываем здесь
// (большой скачок частоты — позиции тиков меняются).
FController.VfoSwap;
FSpecView.InvalidateRulerCache;
UpdateVfoDisplay;
SyncSpecViewFreq;
FSpecView.DrawSpectrum;
PbSpectrum.Invalidate;
if PbRuler <> nil then PbRuler.Invalidate;
end;
procedure TMainForm.BtnVfoACopyBClick(Sender: TObject);
begin
// A>B: копируем частоту A в B (VFO-B получает частоту VFO-A)
FController.FVfoB := FController.FVfoA;
if FController.FActiveVfo = 1 then
begin
// B активен — перестраиваем приёмник на новую частоту B
FController.FCenterFreq := Round(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;
FSpecView.InvalidateRulerCache;
SyncSpecViewFreq;
FSpecView.DrawSpectrum; PbSpectrum.Invalidate;
if PbRuler <> nil then PbRuler.Invalidate;
end;
FreqDispB.Frequency := Round(FController.FVfoB);
UpdateVfoDisplay;
// A>B: B получает частоту A. Команда сохраняет B, перестраивает если B
// активен, рендерит через OnControllerState(rfVfoB).
FController.VfoACopyB;
end;
procedure TMainForm.BtnVfoBCopyAClick(Sender: TObject);
begin
// B>A: копируем частоту B в A (VFO-A получает частоту VFO-B)
// B>A: A получает частоту B. При активном A идём через ApplyVfoA (сохраняем
// канальную оркестрацию); иначе только сохраняем + рендер дисплея.
FController.FVfoA := FController.FVfoB;
if FController.FActiveVfo = 0 then
ApplyVfoA(Round(FController.FVfoA)) // A активен — перестраиваем приёмник
ApplyVfoA(Round(FController.FVfoA))
else
begin
FreqDispA.Frequency := Round(FController.FVfoA);
UpdateVfoDisplay;
end;
end;
function TMainForm.ActiveTXFreqHz: Double;
+31 -6
View File
@@ -672,14 +672,39 @@ procedure TRadioController.SetCenter(Hz: Double);
begin FCenterFreq := Hz; Changed(rfCenterFreq); { TODO wiring } end;
procedure TRadioController.VfoSwap;
var T: Double;
begin T := FVfoA; FVfoA := FVfoB; FVfoB := T; Changed(rfVfoA); Changed(rfVfoB); { TODO wiring } end;
// Меняем VFO A/B местами и перестраиваем приёмник на новую частоту активного
// VFO (центр=частота, shift 0 — CTUN-оффсет после свопа теряет смысл).
var
T: Double;
ActiveFreq: Double;
BandIdx: Integer;
begin
T := FVfoA; FVfoA := FVfoB; FVfoB := T;
ActiveFreq := ActiveVfoHz;
FCenterFreq := ActiveFreq;
if FWDSPReady and Assigned(FDSPEngine) then FDSPEngine.SetShift(0.0);
BandIdx := FreqToBandIdx(ActiveFreq);
if (BandIdx >= 0) and (BandIdx <> FCurrentBand) then
begin
FCurrentBand := BandIdx;
Changed(rfBand);
end;
PushNetworkState;
Changed(rfVfoA);
Changed(rfVfoB);
end;
procedure TRadioController.VfoACopyB;
begin FVfoA := FVfoB; Changed(rfVfoA); { TODO wiring } end;
procedure TRadioController.VfoACopyB; // A>B: частота A копируется в B
begin
SetVfoB(FVfoA); // сохраняет B:=A, перестраивает если B активен, рендер rfVfoB
end;
procedure TRadioController.VfoBCopyA;
begin FVfoB := FVfoA; Changed(rfVfoB); { TODO wiring } end;
procedure TRadioController.VfoBCopyA; // B>A: частота B копируется в A
begin
FVfoA := FVfoB;
if FActiveVfo = 0 then SetVfoA(FVfoA) // A активен — перестраиваем приёмник
else Changed(rfVfoA); // A неактивен — только рендер дисплея
end;
procedure TRadioController.SetMode(M: Integer);
begin