mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
feat(slices): пан-зум панов N — свой бар/кнопки, span-clip анализатора пана
Движок: TPanChan.ZoomFactor/PanSlider, span-clip в ApplyPanAnalyzerSettings (математика главного, ZOOM_LIMIT 100), SetPanZoomPan с no-op guard (SetAnalyzer сбрасывает FFT-историю). Зум переживает смену rate/ADC пана. Контроллер: формула окна вынесена в ViewWindowFor (главный GetViewWindow тоже через неё), GetPanViewWindow (PanId=0 делегирует), PanZoomIn/Out по лестнице кратностей с якорем на центре окна, PanZoomDefault, геттеры. UI: TPanZoomEvent получил Sender; у панов N включён ряд зума, бар диспетчеризуется по объекту, кнопки −/⌂/+ общие через PanOfZoomButton (матч по идентичности — MakeFlatBtn создаёт кнопки с Owner=контейнер, PanFromSender их не видит); SyncPanZoomUI/RefreshPanZoom, вся мышь панов зум-корректна через GetPanViewWindow. Темизация баров панов N. Смоук panzoomtest ALL PASS (пик тона совпадает с формулой окна ±0.6%), подтверждено на экране. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+98
-14
@@ -481,7 +481,8 @@ type
|
||||
procedure DoSpectrumDrag(PixelX: Integer; PanelWidth: Integer);
|
||||
procedure DoWidebandClick(PixelX: Integer; PanelWidth: Integer);
|
||||
// ---- Пан/зум (мышь полосы/сплиттера — внутри TPanafallPanel) ----
|
||||
procedure OnPanZoomWindow(AZoom, APan: Double);
|
||||
function PanOfZoomButton(Sender: TObject): TPanafallPanel;
|
||||
procedure OnPanZoomWindow(Sender: TObject; AZoom, APan: Double);
|
||||
procedure BtnZoomInClick(Sender: TObject);
|
||||
procedure BtnZoomDefClick(Sender: TObject);
|
||||
procedure BtnZoomOutClick(Sender: TObject);
|
||||
@@ -590,6 +591,8 @@ type
|
||||
procedure AddSliceAtFreqPan(P: TPanafallPanel; Hz: Double);
|
||||
procedure PanClickTune(P: TPanafallPanel; X, W: Integer); // клик по фону пана N
|
||||
procedure PanViewWindow(P: TPanafallPanel; out VC, VS: Double);
|
||||
procedure SyncPanZoomUI(P: TPanafallPanel); // вьюха+зум-бар ← контроллер
|
||||
procedure RefreshPanZoom(P: TPanafallPanel); // + флаги/инвалидции
|
||||
procedure SyncPanViews; // центр/span вьюх панов
|
||||
procedure MarkPanDirty(P: TPanafallPanel); // репейнт пана N
|
||||
// Мышь панов N>0 (у пана 0 семантика ниже, PbSpectrum*).
|
||||
@@ -2706,6 +2709,9 @@ begin
|
||||
FPans[i].SetFlagsTheme(T);
|
||||
if FPanSplitters[i] <> nil then FPanSplitters[i].Color := T.Border;
|
||||
if FPanFloatForm[i] <> nil then FPanFloatForm[i].Color := T.BG;
|
||||
// Зум-бар пана N (пан 0 — через алиас FPanZoomBar ниже).
|
||||
if FPans[i].ZoomBar <> nil then FPans[i].ZoomBar.SetTheme(T);
|
||||
if FPans[i].PbPanZoom <> nil then FPans[i].PbPanZoom.Color := T.SliderBG;
|
||||
end;
|
||||
end;
|
||||
if FPanZoomBar <> nil then
|
||||
@@ -4338,25 +4344,74 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.OnPanZoomWindow(AZoom, APan: Double);
|
||||
procedure TMainForm.OnPanZoomWindow(Sender: TObject; AZoom, APan: Double);
|
||||
var i: Integer;
|
||||
begin
|
||||
// Чей бар? Паны N — свой зум (пан-локальный, без band-персиста);
|
||||
// иначе пан 0 — контроллерный зум (rfZoom обновит UI).
|
||||
for i := 1 to MAX_PANS - 1 do
|
||||
if (FPans[i] <> nil) and (TObject(FPans[i].ZoomBar) = Sender) then
|
||||
begin
|
||||
FController.SetPanZoomPan(i, AZoom, APan);
|
||||
RefreshPanZoom(FPans[i]);
|
||||
Exit;
|
||||
end;
|
||||
// Окно-селектор задаёт и зум, и пан напрямую (без якоря на VFO).
|
||||
FController.ApplyZoom(AZoom, APan);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnZoomInClick(Sender: TObject);
|
||||
function TMainForm.PanOfZoomButton(Sender: TObject): TPanafallPanel;
|
||||
// Зум-кнопки создаются MakeFlatBtn с Owner = контейнер (PanelRight/окно), а не
|
||||
// панель — PanFromSender их НЕ находит (клик уходил в зум главного пана).
|
||||
// Матчим по идентичности контролов.
|
||||
var i: Integer;
|
||||
begin
|
||||
FController.ZoomIn;
|
||||
Result := nil;
|
||||
for i := 0 to MAX_PANS - 1 do
|
||||
if FPans[i] <> nil then
|
||||
if (Sender = TObject(FPans[i].BtnZoomIn)) or
|
||||
(Sender = TObject(FPans[i].BtnZoomDef)) or
|
||||
(Sender = TObject(FPans[i].BtnZoomOut)) then
|
||||
Exit(FPans[i]);
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnZoomInClick(Sender: TObject);
|
||||
var P: TPanafallPanel;
|
||||
begin
|
||||
P := PanOfZoomButton(Sender);
|
||||
if (P <> nil) and (P.PanId > 0) then
|
||||
begin
|
||||
FController.PanZoomIn(P.PanId);
|
||||
RefreshPanZoom(P);
|
||||
end
|
||||
else
|
||||
FController.ZoomIn;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnZoomDefClick(Sender: TObject);
|
||||
var P: TPanafallPanel;
|
||||
begin
|
||||
FController.ZoomDefault;
|
||||
P := PanOfZoomButton(Sender);
|
||||
if (P <> nil) and (P.PanId > 0) then
|
||||
begin
|
||||
FController.PanZoomDefault(P.PanId);
|
||||
RefreshPanZoom(P);
|
||||
end
|
||||
else
|
||||
FController.ZoomDefault;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnZoomOutClick(Sender: TObject);
|
||||
var P: TPanafallPanel;
|
||||
begin
|
||||
FController.ZoomOut;
|
||||
P := PanOfZoomButton(Sender);
|
||||
if (P <> nil) and (P.PanId > 0) then
|
||||
begin
|
||||
FController.PanZoomOut(P.PanId);
|
||||
RefreshPanZoom(P);
|
||||
end
|
||||
else
|
||||
FController.ZoomOut;
|
||||
end;
|
||||
|
||||
// Спектр
|
||||
@@ -5298,13 +5353,37 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMainForm.PanViewWindow(P: TPanafallPanel; out VC, VS: Double);
|
||||
// Видимое окно доп. пана: центр DDC ± rate/2 (пан-зума пока нет).
|
||||
// Видимое окно доп. пана (с учётом его пан-зума).
|
||||
begin
|
||||
VC := FController.PanDDCFreq(P.PanId);
|
||||
VS := FController.PanDDCRateKHz(P.PanId) * 1000.0;
|
||||
FController.GetPanViewWindow(P.PanId, VC, VS);
|
||||
if VS <= 0 then VS := 384000;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SyncPanZoomUI(P: TPanafallPanel);
|
||||
// Вьюха и зум-бар пана ← контроллер (после смены зума/центра/rate пана).
|
||||
var VC, VS: Double;
|
||||
begin
|
||||
if (P = nil) or (P.PanId = 0) then Exit;
|
||||
FController.GetPanViewWindow(P.PanId, VC, VS);
|
||||
P.View.CenterFreq := VC;
|
||||
P.View.SpanHz := VS;
|
||||
P.ZoomBar.SetFreq(FController.PanDDCFreq(P.PanId),
|
||||
FController.PanDDCRateKHz(P.PanId) * 1000.0);
|
||||
P.ZoomBar.SetState(FController.PanZoomFactor(P.PanId),
|
||||
FController.PanPanSlider(P.PanId));
|
||||
if P.PbPanZoom <> nil then P.PbPanZoom.Invalidate;
|
||||
end;
|
||||
|
||||
procedure TMainForm.RefreshPanZoom(P: TPanafallPanel);
|
||||
// Полное обновление пана после смены зума: окно вьюхи, бар, флаги, спектр.
|
||||
begin
|
||||
if P = nil then Exit;
|
||||
SyncPanZoomUI(P);
|
||||
P.LayoutFlags;
|
||||
MarkPanDirty(P);
|
||||
if P.PbWaterfall <> nil then P.PbWaterfall.Invalidate;
|
||||
end;
|
||||
|
||||
procedure TMainForm.AddSliceAtFreqPan(P: TPanafallPanel; Hz: Double);
|
||||
// Слайс в доп. пане (режим/полоса копируются с главного, звуковуха default).
|
||||
var Lo, Hi, Id: Integer;
|
||||
@@ -5624,7 +5703,10 @@ begin
|
||||
P := TPanafallPanel.Create(nil, FUseOpenGLSpectrum);
|
||||
P.PanId := PanId;
|
||||
P.Controller := FController;
|
||||
P.ShowZoomRow := False; // пан-зум доп. панов — этап 3.3+
|
||||
P.ShowZoomRow := True; // пан-зум пана: свой бар/кнопки (диспетчер по Sender)
|
||||
P.ZoomInClick := BtnZoomInClick; // до Build — кнопки создаются в Build
|
||||
P.ZoomDefClick := BtnZoomDefClick;
|
||||
P.ZoomOutClick := BtnZoomOutClick;
|
||||
P.OnWireFlag := WireOverlayEvents;
|
||||
P.OnSliceClosed := OnPanSliceClosed;
|
||||
P.OnFlagsInvalidate := OnVfoOverlayInvalidate;
|
||||
@@ -5643,6 +5725,9 @@ begin
|
||||
P.WaterfallMouseMove := PanNSpectrumMouseMove;
|
||||
P.WaterfallMouseUp := PanNSpectrumMouseUp;
|
||||
P.Build(PanelRight, Max(1, FController.FSpecMSAA));
|
||||
P.ZoomBar.OnZoomPan := OnPanZoomWindow; // drag окна-селектора
|
||||
P.ZoomBar.SetFreq(Freq, FController.PanDDCRateKHz(PanId) * 1000.0);
|
||||
P.ZoomBar.SetState(0.0, 0.5);
|
||||
|
||||
// Параметры отображения — с главного view (пан-персональные — позже).
|
||||
P.View.WfAGCEnabled := FController.FWfAGCEnabled;
|
||||
@@ -5753,9 +5838,8 @@ begin
|
||||
begin
|
||||
P := FPans[i];
|
||||
if P = nil then Continue;
|
||||
P.View.CenterFreq := FController.PanDDCFreq(i);
|
||||
P.View.SpanHz := FController.PanDDCRateKHz(i) * 1000.0;
|
||||
P.View.WDSPReady := FController.FWDSPReady;
|
||||
SyncPanZoomUI(P); // центр/span вьюхи (с пан-зумом) + зум-бар
|
||||
P.View.WDSPReady := FController.FWDSPReady;
|
||||
end;
|
||||
// Шапки следуют за частотами (Caption-сеттер — no-op при том же тексте).
|
||||
if PanCount > 1 then UpdatePanHeaders;
|
||||
@@ -5891,7 +5975,7 @@ begin
|
||||
NewHz := Max(FController.BackendCaps.MinFreqHz,
|
||||
Min(FController.BackendCaps.MaxFreqHz, NewHz));
|
||||
FController.SetPanDDCFreq(P.PanId, NewHz);
|
||||
P.View.CenterFreq := NewHz;
|
||||
SyncPanZoomUI(P); // окно вьюхи с учётом зума + freq зум-бара
|
||||
P.LayoutFlags;
|
||||
UpdatePanHeaders;
|
||||
MarkPanDirty(P);
|
||||
|
||||
Reference in New Issue
Block a user