mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
fix(tci): клик по DX-споту на доп. пане слал номер ПАНА вместо номера приёмника
Приёмником TCI в этой ветке стал слот СЛАЙСА (TCI_MAX_RX = 1 + MAX_SLICES,
«панадаптером приёмник быть перестал»), а PanNSpectrumMouseDown отдавал в
rx_clicked_on_spot P.PanId. Клик по пану 1 уезжал как «rx_clicked_on_spot:1,…»,
то есть адресовал слайс в слоте 0 — возможно, стоящий на ГЛАВНОМ пане, — а то и
приёмник, которого нет вовсе: клиенты, фильтрующие по номеру, такое уведомление
просто теряют. Вызов rx0 с главного пана был и остаётся верным.
Теперь номер берётся у слайса, который на спот и увели: DXTuneSpotOnPan стал
функцией и возвращает его, TTCIAdapter.RxOfSlice переводит id в номер TCI.
Заодно два следствия того же места:
* Не увели ничего (спот вне полосы захвата зумнутого пана, слоты кончились) —
молчим. Иначе уведомление уходило под номером 0, то есть от имени главного
приёмника, который никуда не двигался, и логгер открывал карточку QSO с QSY
на частоту, где радио не стоит.
* AddSliceAtFreqPan стал функцией и честно сообщает, что получилось. При
неудаче (нет свободных слотов, частота вне захвата) он не трогает
FActiveSliceId, а DXTuneSpotOnPan читал именно его — и уводил на спот ЧУЖОЙ
слайс, вообще говоря с другого пана, вместе с SetSliceModeBW и
PushSliceFlagState не на том пане.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+33
-12
@@ -520,7 +520,8 @@ type
|
||||
procedure ApplyDXClusterSettings(const D: TDXClusterSettings);
|
||||
procedure AttachPanDXSpots(P: TPanafallPanel); // свой оверлей спотов на пан
|
||||
procedure ApplyDXOverlayCfg(O: TDXSpotOverlay); // настройки вида → один оверлей
|
||||
procedure DXTuneSpotOnPan(P: TPanafallPanel; FreqHz: Double; Mode: TDXMode);
|
||||
function DXTuneSpotOnPan(P: TPanafallPanel; FreqHz: Double;
|
||||
Mode: TDXMode): Integer;
|
||||
procedure UpdateDXClusterButton;
|
||||
procedure BtnDXClusterClick(Sender: TObject);
|
||||
procedure BtnDXClusterMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
@@ -746,7 +747,7 @@ type
|
||||
procedure PanFloatResize(Sender: TObject);
|
||||
function PanFloating(PanId: Integer): Boolean;
|
||||
procedure ResetPanGLCaches(P: TPanafallPanel); // после смены родителя
|
||||
procedure AddSliceAtFreqPan(P: TPanafallPanel; Hz: Double);
|
||||
function AddSliceAtFreqPan(P: TPanafallPanel; Hz: Double): Integer;
|
||||
procedure PanClickTune(P: TPanafallPanel; X, W: Integer); // клик по фону пана N
|
||||
procedure PanViewWindow(P: TPanafallPanel; out VC, VS: Double);
|
||||
procedure SyncPanZoomUI(P: TPanafallPanel); // вьюха+зум-бар ← контроллер
|
||||
@@ -5303,17 +5304,19 @@ begin
|
||||
FController.SetMode(NewMode);
|
||||
end;
|
||||
|
||||
procedure TMainForm.DXTuneSpotOnPan(P: TPanafallPanel; FreqHz: Double;
|
||||
Mode: TDXMode);
|
||||
function TMainForm.DXTuneSpotOnPan(P: TPanafallPanel; FreqHz: Double;
|
||||
Mode: TDXMode): Integer;
|
||||
// QSY по споту на доп. пане. Цель — слайс ЭТОГО пана (активный, если он здесь,
|
||||
// иначе первый; нет ни одного — создаём в точке), ровно как у клика по фону
|
||||
// пана: своего VFO у панов N нет, а ретюнить их DDC под спот нельзя — это
|
||||
// увезло бы весь пан.
|
||||
// увезло бы весь пан. Возвращает слайс, который увели на спот (0 — не увели):
|
||||
// его номер и адресуют уведомления TCI.
|
||||
var
|
||||
Id, NewMode: Integer;
|
||||
Hz: Int64;
|
||||
S: TCtrlSlice;
|
||||
begin
|
||||
Result := 0;
|
||||
if (P = nil) or (FreqHz <= 0) then Exit;
|
||||
Hz := Round(FreqHz);
|
||||
// Спот видим в окне пана, но окно может быть шире полосы захвата (зум) —
|
||||
@@ -5329,8 +5332,11 @@ begin
|
||||
NewMode := DXSpotRadioMode(FreqHz, Mode);
|
||||
if Id = 0 then
|
||||
begin
|
||||
AddSliceAtFreqPan(P, Hz); // ставит FActiveSliceId
|
||||
Id := FActiveSliceId;
|
||||
// ★Берём то, что вернул сам вызов, а не FActiveSliceId: слоты могли
|
||||
// кончиться, и тогда в нём лежит прежний активный слайс — возможно, вообще
|
||||
// с другого пана. Раньше его и уводили на спот, а теперь ещё и объявляли
|
||||
// клиентам TCI приёмником, который «встал на спот».
|
||||
Id := AddSliceAtFreqPan(P, Hz);
|
||||
if Id = 0 then Exit;
|
||||
end
|
||||
else
|
||||
@@ -5344,6 +5350,7 @@ begin
|
||||
FController.FilterBWFor(NewMode, FilterDefIdx(NewMode)));
|
||||
|
||||
FActiveSliceId := Id;
|
||||
Result := Id;
|
||||
P.PushSliceFlagState(Id);
|
||||
P.LayoutFlags;
|
||||
MarkPanDirty(P);
|
||||
@@ -7015,18 +7022,23 @@ begin
|
||||
if P.PbPanZoom <> nil then P.PbPanZoom.Invalidate; // событийный путь — можно
|
||||
end;
|
||||
|
||||
procedure TMainForm.AddSliceAtFreqPan(P: TPanafallPanel; Hz: Double);
|
||||
function TMainForm.AddSliceAtFreqPan(P: TPanafallPanel; Hz: Double): Integer;
|
||||
// Слайс в доп. пане (режим/полоса копируются с главного, звуковуха default).
|
||||
// Возвращает созданный слайс, 0 — не создали (вне полосы захвата, слоты
|
||||
// кончились). Спрашивать об этом FActiveSliceId нельзя: при неудаче там
|
||||
// остаётся ПРЕЖНИЙ активный слайс, вообще говоря с другого пана.
|
||||
var Lo, Hi, Id: Integer;
|
||||
begin
|
||||
Result := 0;
|
||||
if not FController.SliceFitsCapture(Hz, P.PanId) then Exit;
|
||||
TRadioController.FilterEdgesFor(FController.FMode, FController.FFilterBW, Lo, Hi);
|
||||
Id := FController.AddSlice(Hz, FController.FMode, Lo, Hi,
|
||||
TRadioController.AGCModeFromUI(FController.FAGCMode), 0.7, -1, '',
|
||||
P.PanId);
|
||||
if Id < 0 then Exit;
|
||||
if Id <= 0 then Exit;
|
||||
P.CreateSliceFlag(Id);
|
||||
FActiveSliceId := Id;
|
||||
Result := Id;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnPanRateClick(Sender: TObject);
|
||||
@@ -8031,9 +8043,18 @@ begin
|
||||
if IsSpec and (Button = mbLeft) and (P.DXOverlay <> nil) and
|
||||
P.DXOverlay.SpotAtPixel(X, Y, DXSpot) then
|
||||
begin
|
||||
DXTuneSpotOnPan(P, DXSpot.FreqHz, DXSpot.Mode);
|
||||
if FTCIAdapter <> nil then
|
||||
FTCIAdapter.NotifySpotClicked(DXSpot.Call, DXSpot.FreqHz, P.PanId, 0);
|
||||
Id := DXTuneSpotOnPan(P, DXSpot.FreqHz, DXSpot.Mode);
|
||||
// ★Приёмник TCI — это слот СЛАЙСА (панадаптером приёмник быть перестал),
|
||||
// поэтому спрашиваем номер того слайса, который на спот и увели. Номер
|
||||
// пана здесь адресовал чужой приёмник, а то и несуществующий — клиенты с
|
||||
// фильтром по rx уведомление просто теряли.
|
||||
// ★Ничего не увели (спот вне полосы захвата зумнутого пана, слоты
|
||||
// кончились) — молчим. Иначе уведомление уезжало бы под номером 0, то есть
|
||||
// от имени ГЛАВНОГО приёмника, который никуда не двигался: логгер открывал
|
||||
// бы карточку QSO и тянул за собой VFO на частоту, где радио не стоит.
|
||||
if (Id <> 0) and (FTCIAdapter <> nil) then
|
||||
FTCIAdapter.NotifySpotClicked(DXSpot.Call, DXSpot.FreqHz,
|
||||
FTCIAdapter.RxOfSlice(Id), 0);
|
||||
Exit;
|
||||
end;
|
||||
W := TControl(Sender).Width;
|
||||
|
||||
@@ -353,6 +353,10 @@ type
|
||||
{ Уведомление о клике по споту на панораме (§4.4) — зовёт UI. }
|
||||
procedure NotifySpotClicked(const Call: string; FreqHz: Double;
|
||||
Rx: Integer = 0; Ch: Integer = 0);
|
||||
{ Номер TCI-приёмника, за которым стоит слайс Id. Нужен UI: уведомления
|
||||
адресуются номерами TCI, а он знает только id слайса. 0 — слайса нет в
|
||||
снимке (или Id = 0): адресуем главный тракт, он есть всегда. }
|
||||
function RxOfSlice(Id: Integer): Integer;
|
||||
{ Статус фокуса главного окна (APP_FOCUS) — зовёт UI. }
|
||||
procedure NotifyAppFocus(InFocus: Boolean);
|
||||
|
||||
@@ -3790,6 +3794,12 @@ end;
|
||||
Уведомления, которые инициирует UI
|
||||
═══════════════════════════════════════════════════════════════════════════ }
|
||||
|
||||
function TTCIAdapter.RxOfSlice(Id: Integer): Integer;
|
||||
var Rx, Ch: Integer;
|
||||
begin
|
||||
if SliceRxCh(Id, Rx, Ch) then Result := Rx else Result := 0;
|
||||
end;
|
||||
|
||||
procedure TTCIAdapter.NotifySpotClicked(const Call: string; FreqHz: Double;
|
||||
Rx, Ch: Integer);
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user