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