feat(tx): TX-профиль на слайс — пилюля в шапке флага

Передатчик один, профиль до сих пор был один на устройство: активный профиль
звучал независимо от того, какой слайс взял передачу. С панадаптером на FT8 и
вторым на FM это значит, что компрессия и EQ голосового профиля уходили в
эфир на FT8 (FMRAW прикрыт сам — ApplyTXModeSettings глушит там всю обработку,
а DIGU/DIGL нет). У Flex это решается дисциплиной и внешним API; делаем в радио.

Привязка «источник передачи → профиль» (-1 = не переключать, звучит активный):
TCtrlSlice.TXProfile для B..G, TTXProfileList.MainBind для главного (слайс A).
Персист: ключ tx_profile в слайсе пана и main_bind в секции tx_profiles.
SetTxSlice зовёт ApplyBoundTXProfile ДО пуша режима и цепи, иначе
ApplyTXSettingsToDSP лёг бы на старый режим. Привязали источник, который
передаёт прямо сейчас, — применяем сразу.

Привязки — индексы, поэтому RemapTXProfileBindings: удаление профиля из
середины снимает привязки на него и сдвигает те, что правее; Factory-сброс
снимает все (список заменён целиком).

UI: пилюля с именем профиля в первой строке флага сразу за шириной фильтра
(ЛКМ — fly-out список, первая строка «As active»). Правая граница считается
до SPLIT у главного и до RXM у слайса; не рисуем при пустом списке, в DMR
(передачи нет) и в FMRAW (профиль там ни на что не влияет). Прокрутка списка
общая с AUD — блок стрелок вынесен в DrawScrollArrows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 17:06:08 +03:00
co-authored by Claude Opus 5
parent 8563c4e4cc
commit 013d0406ac
5 changed files with 397 additions and 41 deletions
+18
View File
@@ -533,6 +533,7 @@ type
procedure OnTXProfileRenameFromSettings(Idx: Integer; const AName: string);
procedure OnTXProfileDeleteFromSettings(Idx: Integer);
procedure OnTXProfileFactoryFromSettings(Sender: TObject);
procedure OnVfoOverlayTXProfile(Idx: Integer);
procedure OnChannelStoreChanged(Sender: TObject);
procedure OnChannelActiveChanged(Idx: Integer; const Name: string; Active: Boolean);
procedure PbSpectrumMouseDown(Sender: TObject; Button: TMouseButton;
@@ -5708,6 +5709,10 @@ begin
FController.FNetwork.Device.BoardType, FPendingBoardType));
PushTXProfilesToSettings;
end;
// Пилюли профиля на флагах: список общий, привязки могли съехать после
// удаления/сброса — обновляем на всех панах.
for i := 0 to MAX_PANS - 1 do
if FPans[i] <> nil then FPans[i].PushAllFlagTXProfiles;
end;
procedure TMainForm.PushTXProfilesToSettings;
@@ -6098,6 +6103,16 @@ begin
PushFlagStateAllPans(CurSliceId);
end;
procedure TMainForm.OnVfoOverlayTXProfile(Idx: Integer);
// Пилюля TX-профиля во флаге: «этот источник передачи звучит вот так».
// Idx = -1 — привязки нет, передаёт активный профиль.
begin
// Привязка главного живёт в секции профилей (контроллер её уже сохранил),
// привязка слайса уедет в конфиг с общим персистом панов — как RxMuteOnTx.
FController.SetSliceTXProfile(CurSliceId, Idx);
PushFlagStateAllPans(CurSliceId);
end;
procedure TMainForm.RefreshTxIndicators;
// Обновить TX-бейджи (TxSel/Tx) на всех флагах всех панов после смены
// TX-слайса / состояния передачи.
@@ -6198,6 +6213,7 @@ begin
O.OnSplit := OnVfoOverlaySplit;
O.OnTxSelect := OnVfoOverlayTxSelect;
O.OnRxMuteTx := OnVfoOverlayRxMuteTx;
O.OnTXProfile := OnVfoOverlayTXProfile;
O.OnSliceSelect := OnVfoOverlaySliceSelect;
O.OnClose := OnVfoOverlayClose;
O.OnInvalidate := OnVfoOverlayInvalidate;
@@ -7160,6 +7176,7 @@ begin
Cfg.Pans[i].Slices[n].FMSQLevel := FController.FSlices[s].FMSQLevel;
Cfg.Pans[i].Slices[n].DevName := FController.FSlices[s].DevName;
Cfg.Pans[i].Slices[n].InDevName := FController.FSlices[s].InDevName;
Cfg.Pans[i].Slices[n].TXProfile := FController.FSlices[s].TXProfile;
Inc(n);
end;
end;
@@ -7186,6 +7203,7 @@ begin
FController.FAudioIn.FindDeviceByName(SC.InDevName), SC.InDevName);
if SC.Muted then FController.SetSliceMute(Id, True);
FController.SetSliceRxMuteOnTx(Id, SC.RxMuteOnTx);
FController.SetSliceTXProfile(Id, SC.TXProfile); // «этот слайс звучит вот так»
if SC.FMSQOn then FController.SetSliceFMSquelch(Id, True, SC.FMSQLevel);
P.CreateSliceFlag(Id);
FActiveSliceId := Id;