fix(slice-cat): перестройка слайса внутри полосы захвата обновляет флаг

TuneSliceInBand в быстрой ветке (цель уже внутри захваченной полосы) звал
только SetSliceTarget и не слал ни одного Changed. Позицию флага UI держит
сам (TickFlags -> LayoutFlags читает живой TargetHz), а частота и кромки
фильтра живут в собственных полях оверлея и заливаются только из
PushSliceFlagState. Итог: флаг уезжал на новую частоту, показывая старые
цифры и старую полосу фильтра. Дальний QSY выглядел исправным лишь потому,
что там двигалось окно DDC и приходил rfPanFreq с PushAllSliceFlagStates.

Новое поле rfSliceFreq (+ FSliceFreqId как полезная нагрузка) и хелпер
SliceFreqChanged: шлётся из быстрой ветки и из ветки пана 0 (rfCenterFreq
флаги не перезаливает). MainForm обновляет только тронутый слайс.

Тракт передачи не менялся: ActiveTXFreqHz и так берёт TargetHz слайса-
источника, а SetSliceTarget сразу пушит сетевое состояние (DUC).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 23:46:05 +03:00
co-authored by Claude Opus 5
parent b02b68aa6a
commit 00860e5154
2 changed files with 33 additions and 1 deletions
+22 -1
View File
@@ -87,7 +87,8 @@ type
rfBeaconLock, // QO-100 beacon lock: статус/коррекция
rfDevice, // подключённое устройство сменилось
rfDeviceList, // список discovered устройств обновился
rfPanFreq // центр доп. пана уехал (ретюн DDC извне)
rfPanFreq, // центр доп. пана уехал (ретюн DDC извне)
rfSliceFreq // слайс перестроен извне (CAT); Id — FSliceFreqId
);
TRadioStateEvent = procedure(Sender: TObject; Field: TRadioField) of object;
@@ -366,6 +367,9 @@ type
FTwoTone: Boolean; // 2TON активен
FSplitTxB: Boolean;
FTxSliceId: Integer; // 0 = главный VFO (A/B split); >0 = слайс-источник TX
// Id слайса, перестроенного извне (CAT): полезная нагрузка rfSliceFreq —
// Changed несёт только поле, а обработчику нужен конкретный флаг.
FSliceFreqId: Integer;
// Auto TX слайса (индекс = СЛОТ слайса, не Id): PTT по CAT-порту слайса сам
// назначает его TX-источником. Флаг живёт на слоте, а не на слайсе, потому
// что настройка привязана к букве (B..G) и переживает удаление слайса.
@@ -884,6 +888,9 @@ type
// вне захваченной полосы пана — двигаем окно DDC. False = отказ (другой
// диапазон либо окно не подвинуть, не оглушив главный приёмник).
function TuneSliceInBand(Id: Integer; TargetHz: Double): Boolean;
// Уведомление UI «частота слайса пришла извне»: перезалить флаг (цифры +
// кромки фильтра), позиция флага и так живая.
procedure SliceFreqChanged(Id: Integer);
// ---- Панадаптеры на аппаратных DDC (этап 3.1; UI/движок — 3.2/3.3) ----
// Создаёт пан PanId (1..MAX_PANS-1) на своём DDC: FreqHz = центр в ВИДИМЫХ
@@ -1948,6 +1955,17 @@ begin
Result := BandEdges(FCurrentBand, IsPluto, LoHz, HiHz);
end;
procedure TRadioController.SliceFreqChanged(Id: Integer);
// Слайс перестроен НЕ из UI (CAT-порт слайса). Позицию флага UI держит сам
// (TickFlags → LayoutFlags читает живой TargetHz), а вот ЧАСТОТА и кромки
// фильтра во флаге живут в его собственных полях и обновляются только
// PushSliceFlagState. Без этого уведомления флаг уезжал на новую частоту,
// показывая старые цифры и старую полосу фильтра.
begin
FSliceFreqId := Id;
Changed(rfSliceFreq);
end;
function TRadioController.TuneSliceInBand(Id: Integer; TargetHz: Double): Boolean;
// Свобода внешней программы: она двигает слайс куда угодно ВНУТРИ включённого
// диапазона (2 м на трансвертере: 144.174 при окне на 145.5 — можно), но сменить
@@ -1971,6 +1989,7 @@ begin
if SliceFitsCapture(TargetHz, PanId) then
begin
SetSliceTarget(Id, TargetHz);
SliceFreqChanged(Id);
Exit(True);
end;
@@ -1982,6 +2001,7 @@ begin
SetPanDDCFreq(PanId, NewCenter);
SetSliceTarget(Id, TargetHz);
Changed(rfPanFreq); // UI: шапка/зум-бар/флаги пана под новый центр
// (несёт и перезалив флагов — SliceFreqChanged лишний)
Result := True;
end
else
@@ -1995,6 +2015,7 @@ begin
NewCenter := (TargetHz + ActiveVfoHz) / 2;
SetCenter(NewCenter); // несёт Changed(rfCenterFreq) + сдвиги слайсов
SetSliceTarget(Id, TargetHz);
SliceFreqChanged(Id); // rfCenterFreq флаги не перезаливает — нужен свой
Result := True;
end;
end;