mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
refactor(slices): этап 3.0A — панадаптер выделен в TPanafallPanel
PanafallPanel.pas: view (CPU/GL), контролы стека (спектр/линейка/сплиттер/ водопад/пан-зум/кнопки зума), геометрия Layout, drag сплиттера и мышь пан/зум-полосы. MainForm работает через алиасы (FSpecView/PbSpectrum/… = FPan.*), размеры областей — FPan.SpectrumWidth/SpectrumHeight/WaterfallHeight. Семантика мыши/флаги/тик пока в MainForm (фаза B). GL-аудит per-instance пройден (глобальных GL-ресурсов нет). План: doc/SLICES_PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+71
-393
@@ -33,7 +33,7 @@ uses
|
||||
WebServer, WebAdapter,
|
||||
CATAdapter,
|
||||
SpectrumView, SpectrumViewOpengl,
|
||||
PanZoomBar,
|
||||
PanZoomBar, PanafallPanel,
|
||||
WidebandView,
|
||||
StatusBar,
|
||||
PlatformUtils,
|
||||
@@ -156,12 +156,14 @@ type
|
||||
// живут в TRadioController.
|
||||
|
||||
// ---- Spectrum / Waterfall view ----
|
||||
// Панадаптер (спектр+линейка+сплиттер+водопад+пан/зум) — composite-объект
|
||||
// (Этап 3.0 мультислайсов). FSpecView и Pb*-поля ниже — алиасы его членов
|
||||
// (исторические имена; постепенная миграция на FPan.*). Размеры областей —
|
||||
// FPan.SpectrumWidth/SpectrumHeight/WaterfallHeight.
|
||||
FPan: TPanafallPanel;
|
||||
FSpecView: TSpectrumView;
|
||||
FWidebandView: TWidebandView;
|
||||
FUseOpenGLSpectrum: Boolean;
|
||||
FSpectrumWidth: Integer; // актуальная ширина для FDSPEngine и resize-детектора
|
||||
FSpectrumHeight: Integer;
|
||||
FWaterfallHeight:Integer;
|
||||
FDisplayFPS: Integer;
|
||||
FWaterfallDirty: Boolean;
|
||||
FWidebandDirty: Boolean;
|
||||
@@ -170,11 +172,6 @@ type
|
||||
// Снимок последнего кадра спектра/водопада для web переехал в TRadioController
|
||||
// (FSpectrumBuf/FWaterfallBuf) — нужен headless-демону.
|
||||
FAgcLineCounter: Integer;
|
||||
// ---- Splitter ----
|
||||
FSplitterDrag: Boolean;
|
||||
FSplitterDragY0: Integer;
|
||||
FSplitterSH0: Integer;
|
||||
FSplitterRatio: Double;
|
||||
// --- Settings ---
|
||||
FWebServer: TWebServer;
|
||||
FWebAdapter: TWebAdapter; // мост web-сервер ↔ контроллер (вынесенные WebOnXxx)
|
||||
@@ -301,6 +298,7 @@ type
|
||||
|
||||
// ---- Right panel ----
|
||||
PanelRight: TPanel;
|
||||
// Контролы панадаптера — алиасы членов FPan (владелец FPan; см. выше).
|
||||
PbSpectrum: TControl;
|
||||
PbWideband: TControl;
|
||||
PbWidebandRuler: TPaintBox;
|
||||
@@ -454,18 +452,11 @@ type
|
||||
procedure DoSpectrumClick(PixelX: Integer; PanelWidth: Integer);
|
||||
procedure DoSpectrumDrag(PixelX: Integer; PanelWidth: Integer);
|
||||
procedure DoWidebandClick(PixelX: Integer; PanelWidth: Integer);
|
||||
// ---- Пан/зум ----
|
||||
procedure PbPanZoomMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
procedure PbPanZoomMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
||||
procedure PbPanZoomMouseUp(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
procedure PbPanZoomDblClick(Sender: TObject);
|
||||
// ---- Пан/зум (мышь полосы/сплиттера — внутри TPanafallPanel) ----
|
||||
procedure OnPanZoomWindow(AZoom, APan: Double);
|
||||
procedure BtnZoomInClick(Sender: TObject);
|
||||
procedure BtnZoomDefClick(Sender: TObject);
|
||||
procedure BtnZoomOutClick(Sender: TObject);
|
||||
procedure PositionPanZoomBar(BottomY, RW, H: Integer; AVisible: Boolean);
|
||||
procedure UpdatePanZoomBar;
|
||||
procedure BtnVfoSwapClick(Sender: TObject);
|
||||
procedure BtnVfoACopyBClick(Sender: TObject);
|
||||
@@ -577,13 +568,6 @@ type
|
||||
procedure SpectrumTimerTick(Sender: TObject);
|
||||
procedure RightPanelResize(Sender: TObject);
|
||||
procedure AfterShowTick(Sender: TObject);
|
||||
// Splitter handlers
|
||||
procedure SplitterMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
procedure SplitterMouseMove(Sender: TObject; Shift: TShiftState;
|
||||
X, Y: Integer);
|
||||
procedure SplitterMouseUp(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
|
||||
public
|
||||
// Методы для SettingsForm — немедленное применение настроек
|
||||
@@ -1008,16 +992,15 @@ begin
|
||||
FController.FSpectrumFill := True;
|
||||
FDisplayFPS := 60;
|
||||
FFreqMhzDigits := 3;
|
||||
FSplitterRatio := 0.40;
|
||||
FSplitterDrag := False;
|
||||
|
||||
// OpenGLContextEx (QOpenGLWidget-бэкенд) работает и в нативном Wayland,
|
||||
// старая X11-заглушка больше не нужна
|
||||
FUseOpenGLSpectrum := HasOpenGLSpectrumSwitch;
|
||||
if FUseOpenGLSpectrum then
|
||||
FSpecView := TSpectrumViewOpenGL.Create
|
||||
else
|
||||
FSpecView := TSpectrumView.Create;
|
||||
// Панадаптер: владеет view/зум-баром/контролами спектра; контролы создаст
|
||||
// FPan.Build в BuildUI. Owner=nil — освобождаем сами в FormDestroy.
|
||||
FPan := TPanafallPanel.Create(nil, FUseOpenGLSpectrum);
|
||||
FSpecView := FPan.View; // алиас (историческое имя)
|
||||
FPanZoomBar := FPan.ZoomBar; // алиас
|
||||
FSpecView.VfoOverlay := FVfoOverlay;
|
||||
FSpecView.VfoA := FController.FVfoA;
|
||||
FSpecView.VfoB := FController.FVfoB;
|
||||
@@ -1114,9 +1097,16 @@ begin
|
||||
if FController.FNetwork.Running then
|
||||
FController.FNetwork.SetRunAndFreq(False, XvtrTranslate(FController.FCenterFreq), XvtrTranslate(FController.FCenterFreq), 0);
|
||||
FController.FNetwork.Disconnect;
|
||||
FreeAndNil(FSpecView);
|
||||
// Панадаптер освобождает view, зум-бар и свои контролы; алиасы обнуляем.
|
||||
FSpecView := nil;
|
||||
FPanZoomBar := nil;
|
||||
PbSpectrum := nil;
|
||||
PbRuler := nil;
|
||||
PanelSplitter := nil;
|
||||
PbWaterfall := nil;
|
||||
PbPanZoom := nil;
|
||||
FreeAndNil(FPan);
|
||||
FreeAndNil(FWidebandView);
|
||||
FreeAndNil(FPanZoomBar);
|
||||
|
||||
// Сохраняем настройки при закрытии
|
||||
if FController.FDevConnected then
|
||||
@@ -1416,7 +1406,7 @@ begin
|
||||
// ChangeSampleRate пересоздал WDSP-канал — пересчёт AGC-линий под
|
||||
// актуальную ширину спектра (UI-зависимая величина).
|
||||
if FController.FWDSPReady then
|
||||
FController.FDSPEngine.UpdateAGCLines(FSpectrumWidth);
|
||||
FController.FDSPEngine.UpdateAGCLines(FPan.SpectrumWidth);
|
||||
UpdatePanZoomBar;
|
||||
end;
|
||||
rfZoom:
|
||||
@@ -2215,190 +2205,42 @@ begin
|
||||
PbWidebandRuler.Cursor := crDefault;
|
||||
PbWidebandRuler.Visible := False;
|
||||
|
||||
if FUseOpenGLSpectrum then
|
||||
begin
|
||||
PbSpectrum := TOpenGLControl.Create(Self);
|
||||
TOpenGLControl(PbSpectrum).AutoResizeViewport := False;
|
||||
TOpenGLControl(PbSpectrum).DoubleBuffered := True;
|
||||
TOpenGLControl(PbSpectrum).MultiSampling := Max(1, FController.FSpecMSAA);
|
||||
TOpenGLControl(PbSpectrum).OnPaint := FSpecView.PaintSpectrum;
|
||||
TOpenGLControl(PbSpectrum).OnMouseDown := PbSpectrumMouseDown;
|
||||
TOpenGLControl(PbSpectrum).OnDblClick := PbSpectrumDblClick;
|
||||
TOpenGLControl(PbSpectrum).OnMouseMove := PbSpectrumMouseMove;
|
||||
TOpenGLControl(PbSpectrum).OnMouseUp := PbSpectrumMouseUp;
|
||||
TOpenGLControl(PbSpectrum).OnMouseLeave := PbSpectrumMouseLeave;
|
||||
TSpectrumViewOpenGL(FSpecView).AttachControl(TOpenGLControl(PbSpectrum));
|
||||
end
|
||||
else
|
||||
begin
|
||||
PbSpectrum := TPaintBox.Create(Self);
|
||||
TPaintBox(PbSpectrum).OnPaint := FSpecView.PaintSpectrum;
|
||||
TPaintBox(PbSpectrum).OnMouseDown := PbSpectrumMouseDown;
|
||||
TPaintBox(PbSpectrum).OnDblClick := PbSpectrumDblClick;
|
||||
TPaintBox(PbSpectrum).OnMouseMove := PbSpectrumMouseMove;
|
||||
TPaintBox(PbSpectrum).OnMouseUp := PbSpectrumMouseUp;
|
||||
TPaintBox(PbSpectrum).OnMouseLeave := PbSpectrumMouseLeave;
|
||||
end;
|
||||
PbSpectrum.Parent := PanelRight;
|
||||
|
||||
PbRuler := TPaintBox.Create(Self);
|
||||
PbRuler.Parent := PanelRight;
|
||||
PbRuler.OnPaint := FSpecView.PaintRuler;
|
||||
PbRuler.Cursor := crDefault;
|
||||
FSpecView.PbRuler := PbRuler;
|
||||
|
||||
// ---- Splitter между спектром+линейкой и водопадом ----
|
||||
PanelSplitter := TPanel.Create(Self);
|
||||
PanelSplitter.Parent := PanelRight;
|
||||
PanelSplitter.BevelOuter := bvNone;
|
||||
PanelSplitter.Color := TColor($00303030);
|
||||
PanelSplitter.Cursor := crVSplit;
|
||||
PanelSplitter.Height := 5;
|
||||
PanelSplitter.OnMouseDown := SplitterMouseDown;
|
||||
PanelSplitter.OnMouseMove := SplitterMouseMove;
|
||||
PanelSplitter.OnMouseUp := SplitterMouseUp;
|
||||
|
||||
if FUseOpenGLSpectrum then
|
||||
begin
|
||||
PbWaterfall := TOpenGLControl.Create(Self);
|
||||
TOpenGLControl(PbWaterfall).AutoResizeViewport := False;
|
||||
TOpenGLControl(PbWaterfall).DoubleBuffered := True;
|
||||
TOpenGLControl(PbWaterfall).OnPaint := FSpecView.PaintWaterfall;
|
||||
TOpenGLControl(PbWaterfall).OnMouseDown := PbWaterfallMouseDown;
|
||||
TOpenGLControl(PbWaterfall).OnMouseMove := PbWaterfallMouseMove;
|
||||
TOpenGLControl(PbWaterfall).OnMouseUp := PbWaterfallMouseUp;
|
||||
TSpectrumViewOpenGL(FSpecView).AttachWaterfallControl(TOpenGLControl(PbWaterfall));
|
||||
end
|
||||
else
|
||||
begin
|
||||
PbWaterfall := TPaintBox.Create(Self);
|
||||
TPaintBox(PbWaterfall).OnPaint := FSpecView.PaintWaterfall;
|
||||
TPaintBox(PbWaterfall).OnMouseDown := PbWaterfallMouseDown;
|
||||
TPaintBox(PbWaterfall).OnMouseMove := PbWaterfallMouseMove;
|
||||
TPaintBox(PbWaterfall).OnMouseUp := PbWaterfallMouseUp;
|
||||
end;
|
||||
PbWaterfall.Parent := PanelRight;
|
||||
|
||||
// ---- Панель пана/зума под водопадом ----
|
||||
// Кнопки создаём с дефолтными цветами; финальная тема — в ApplyDarkTheme.
|
||||
FPanZoomBar := TPanZoomBar.Create;
|
||||
// ---- Панадаптер: контролы спектра/линейки/сплиттера/водопада/пан-зума ----
|
||||
// Создаёт и раскладывает TPanafallPanel; семантика мыши остаётся здесь —
|
||||
// обработчики подвешиваются ДО Build.
|
||||
FPan.SpectrumMouseDown := PbSpectrumMouseDown;
|
||||
FPan.SpectrumMouseMove := PbSpectrumMouseMove;
|
||||
FPan.SpectrumMouseUp := PbSpectrumMouseUp;
|
||||
FPan.SpectrumMouseLeave := PbSpectrumMouseLeave;
|
||||
FPan.SpectrumDblClick := PbSpectrumDblClick;
|
||||
FPan.WaterfallMouseDown := PbWaterfallMouseDown;
|
||||
FPan.WaterfallMouseMove := PbWaterfallMouseMove;
|
||||
FPan.WaterfallMouseUp := PbWaterfallMouseUp;
|
||||
FPan.ZoomInClick := BtnZoomInClick;
|
||||
FPan.ZoomDefClick := BtnZoomDefClick;
|
||||
FPan.ZoomOutClick := BtnZoomOutClick;
|
||||
FPan.OnSplitterMoved := RightPanelResize;
|
||||
FPan.Build(PanelRight, Max(1, FController.FSpecMSAA));
|
||||
// Алиасы контролов (исторические имена; постепенная миграция на FPan.*)
|
||||
PbSpectrum := FPan.PbSpectrum;
|
||||
PbRuler := FPan.PbRuler;
|
||||
PanelSplitter := FPan.Splitter;
|
||||
PbWaterfall := FPan.PbWaterfall;
|
||||
PbPanZoom := FPan.PbPanZoom;
|
||||
BtnZoomIn := FPan.BtnZoomIn;
|
||||
BtnZoomDef := FPan.BtnZoomDef;
|
||||
BtnZoomOut := FPan.BtnZoomOut;
|
||||
FPanZoomBar.OnZoomPan := OnPanZoomWindow;
|
||||
PbPanZoom := TPaintBox.Create(Self);
|
||||
PbPanZoom.Parent := PanelRight;
|
||||
PbPanZoom.OnPaint := FPanZoomBar.Paint;
|
||||
PbPanZoom.OnMouseDown := PbPanZoomMouseDown;
|
||||
PbPanZoom.OnMouseMove := PbPanZoomMouseMove;
|
||||
PbPanZoom.OnMouseUp := PbPanZoomMouseUp;
|
||||
PbPanZoom.OnDblClick := PbPanZoomDblClick;
|
||||
FPanZoomBar.PaintBox := PbPanZoom;
|
||||
BtnZoomOut := MakeFlatBtn(PanelRight, '−', 0, 0, 10, 10, BtnZoomOutClick);
|
||||
BtnZoomDef := MakeFlatBtn(PanelRight, '⌂', 0, 0, 10, 10, BtnZoomDefClick);
|
||||
BtnZoomIn := MakeFlatBtn(PanelRight, '+', 0, 0, 10, 10, BtnZoomInClick);
|
||||
|
||||
// Initial layout
|
||||
ResizeSpectrumPanels;
|
||||
UpdatePanZoomBar;
|
||||
end;
|
||||
|
||||
// ===========================================================================
|
||||
// Splitter — перетаскивание границы спектр/водопад
|
||||
// Обновление размеров происходит только при отпускании мыши (MouseUp),
|
||||
// чтобы исключить фризы во время перетаскивания.
|
||||
// Во время перетаскивания рисуем только призрак-линию на PanelSplitter.
|
||||
// ===========================================================================
|
||||
|
||||
procedure TMainForm.SplitterMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
var
|
||||
P: TPoint;
|
||||
begin
|
||||
if Button <> mbLeft then Exit;
|
||||
FSplitterDrag := True;
|
||||
FSplitterSH0 := FSpectrumHeight;
|
||||
// Y в координатах PanelRight
|
||||
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
||||
FSplitterDragY0 := P.Y;
|
||||
PanelSplitter.Color := TColor($005050A0); // подсветка при захвате
|
||||
{$IFDEF WINDOWS}
|
||||
SetCapture(PanelSplitter.Handle);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TMainForm.SplitterMouseMove(Sender: TObject; Shift: TShiftState;
|
||||
X, Y: Integer);
|
||||
var
|
||||
P: TPoint;
|
||||
DeltaY: Integer;
|
||||
NewSH: Integer;
|
||||
TopOff, AvailH: Integer;
|
||||
RULER_H: Integer;
|
||||
const
|
||||
SPLITTER_H = 5;
|
||||
MIN_SH = 60;
|
||||
MIN_WH = 40;
|
||||
begin
|
||||
RULER_H := MulDiv(18, Screen.PixelsPerInch, 96);
|
||||
if not FSplitterDrag then Exit;
|
||||
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
||||
DeltaY := P.Y - FSplitterDragY0;
|
||||
|
||||
TopOff := 0;
|
||||
// Низ зарезервирован под панель пана/зума (она видна, пока виден водопад).
|
||||
AvailH := PanelRight.ClientHeight - TopOff - RULER_H - SPLITTER_H
|
||||
- MulDiv(22, Screen.PixelsPerInch, 96);
|
||||
if AvailH <= 0 then Exit;
|
||||
|
||||
NewSH := FSplitterSH0 + DeltaY;
|
||||
if NewSH < MIN_SH then NewSH := MIN_SH;
|
||||
if NewSH > AvailH - MIN_WH then NewSH := AvailH - MIN_WH;
|
||||
|
||||
// Только двигаем сплиттер визуально — без пересчёта битмапов
|
||||
PanelSplitter.Top := TopOff + NewSH + RULER_H;
|
||||
PbWaterfall.Top := TopOff + NewSH + RULER_H + SPLITTER_H;
|
||||
PbWaterfall.Height := AvailH - NewSH;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SplitterMouseUp(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
var
|
||||
P: TPoint;
|
||||
DeltaY: Integer;
|
||||
NewSH: Integer;
|
||||
TopOff, AvailH: Integer;
|
||||
RULER_H: Integer;
|
||||
const
|
||||
SPLITTER_H = 5;
|
||||
MIN_SH = 60;
|
||||
MIN_WH = 40;
|
||||
begin
|
||||
RULER_H := MulDiv(18, Screen.PixelsPerInch, 96);
|
||||
if not FSplitterDrag then Exit;
|
||||
FSplitterDrag := False;
|
||||
{$IFDEF WINDOWS}
|
||||
ReleaseCapture;
|
||||
{$ENDIF}
|
||||
PanelSplitter.Color := TColor($00303030); // обычный цвет
|
||||
|
||||
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
||||
DeltaY := P.Y - FSplitterDragY0;
|
||||
|
||||
TopOff := 0;
|
||||
// Низ зарезервирован под панель пана/зума (она видна, пока виден водопад).
|
||||
AvailH := PanelRight.ClientHeight - TopOff - RULER_H - SPLITTER_H
|
||||
- MulDiv(22, Screen.PixelsPerInch, 96);
|
||||
if AvailH <= 0 then Exit;
|
||||
|
||||
NewSH := FSplitterSH0 + DeltaY;
|
||||
if NewSH < MIN_SH then NewSH := MIN_SH;
|
||||
if NewSH > AvailH - MIN_WH then NewSH := AvailH - MIN_WH;
|
||||
|
||||
// Сохраняем новое соотношение и делаем полный пересчёт с перерисовкой
|
||||
FSplitterRatio := NewSH / AvailH;
|
||||
ResizeSpectrumPanels;
|
||||
end;
|
||||
|
||||
// ===========================================================================
|
||||
// Resize handler (normal method instead of anonymous procedure)
|
||||
// Сплиттер спектр/водопад живёт в TPanafallPanel; по OnSplitterMoved панель
|
||||
// зовёт RightPanelResize → полный пересчёт.
|
||||
// ===========================================================================
|
||||
|
||||
procedure TMainForm.RightPanelResize(Sender: TObject);
|
||||
@@ -2581,27 +2423,22 @@ end;
|
||||
|
||||
procedure TMainForm.ResizeSpectrumPanels;
|
||||
const
|
||||
SPLITTER_H = 5;
|
||||
WB_H = 118;
|
||||
MIN_SH = 60; // минимальная высота спектра
|
||||
MIN_WH = 40; // минимальная высота водопада
|
||||
WB_H = 118;
|
||||
var
|
||||
RW, RH, SH, WH, TopOff, WideH, WideSpecH: Integer;
|
||||
AvailH: Integer;
|
||||
RW, RH, WideH, WideSpecH: Integer;
|
||||
RULER_H: Integer;
|
||||
PANZOOM_H: Integer;
|
||||
ShowPZ: Boolean;
|
||||
begin
|
||||
RULER_H := MulDiv(18, Screen.PixelsPerInch, 96);
|
||||
if PanelRight = nil then Exit;
|
||||
if Assigned(FSpecView) then SyncSpecViewFreq;
|
||||
RW := PanelRight.ClientWidth;
|
||||
RH := PanelRight.ClientHeight;
|
||||
// Резервируем низ под панель пана/зума (видна, если виден спектр или водопад).
|
||||
// Низ занят панелью пана/зума (позиционирует FPan.Layout той же формулой) —
|
||||
// wideband-блок делит оставшуюся высоту.
|
||||
PANZOOM_H := MulDiv(22, Screen.PixelsPerInch, 96);
|
||||
ShowPZ := FController.FShowSpectrum or FController.FShowWaterfall;
|
||||
PositionPanZoomBar(RH - PANZOOM_H, RW, PANZOOM_H, ShowPZ);
|
||||
if ShowPZ then RH := RH - PANZOOM_H;
|
||||
if FController.FShowSpectrum or FController.FShowWaterfall then
|
||||
RH := RH - PANZOOM_H;
|
||||
UpdateWidebandFrequencyView;
|
||||
WideH := 0;
|
||||
WideSpecH := 0;
|
||||
@@ -2609,7 +2446,6 @@ begin
|
||||
WideH := Min(MulDiv(WB_H, Screen.PixelsPerInch, 96), Max(40, RH div 2));
|
||||
if WideH > 0 then
|
||||
WideSpecH := Max(1, WideH - RULER_H);
|
||||
TopOff := WideH;
|
||||
if PbWideband <> nil then
|
||||
begin
|
||||
PbWideband.SetBounds(0, 0, RW, WideSpecH);
|
||||
@@ -2633,124 +2469,9 @@ begin
|
||||
// S-метр позиционируется отдельно в ResizeSMeter
|
||||
ResizeSMeter;
|
||||
|
||||
// ---- Оба скрыты ----
|
||||
if (not FController.FShowSpectrum) and (not FController.FShowWaterfall) then
|
||||
begin
|
||||
PbSpectrum.Visible := False;
|
||||
PbRuler.Visible := False;
|
||||
PanelSplitter.Visible := False;
|
||||
PbWaterfall.Visible := False;
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := 0;
|
||||
FWaterfallHeight := 0;
|
||||
PositionSampleRateOverlay;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// ---- Только спектр (водопад скрыт) ----
|
||||
if FController.FShowSpectrum and (not FController.FShowWaterfall) then
|
||||
begin
|
||||
AvailH := RH - TopOff - RULER_H;
|
||||
if AvailH < MIN_SH then AvailH := MIN_SH;
|
||||
SH := AvailH;
|
||||
WH := 0;
|
||||
PbSpectrum.SetBounds(0, TopOff, RW, SH);
|
||||
PbSpectrum.Visible := True;
|
||||
PbRuler.SetBounds(0, TopOff + SH, RW, RULER_H);
|
||||
PbRuler.Visible := True;
|
||||
PanelSplitter.Visible := False;
|
||||
PbWaterfall.Visible := False;
|
||||
PositionSampleRateOverlay;
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := SH;
|
||||
FWaterfallHeight := 0;
|
||||
if RW > 0 then
|
||||
begin
|
||||
FSpecView.SetSpectrumBitmapSize(RW, SH);
|
||||
FSpecView.SetWaterfallBitmapSize(1, 1);
|
||||
FSpecView.SetRulerSize(RW, RULER_H);
|
||||
FSpecView.DrawSpectrum;
|
||||
PbSpectrum.Invalidate;
|
||||
PbRuler.Invalidate;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// ---- Только водопад (спектр скрыт): линейка под водопадом ----
|
||||
if (not FController.FShowSpectrum) and FController.FShowWaterfall then
|
||||
begin
|
||||
AvailH := RH - TopOff - RULER_H;
|
||||
if AvailH < MIN_WH then AvailH := MIN_WH;
|
||||
SH := 0;
|
||||
WH := AvailH;
|
||||
PbSpectrum.Visible := False;
|
||||
PanelSplitter.Visible := False;
|
||||
PbWaterfall.SetBounds(0, TopOff, RW, WH);
|
||||
PbWaterfall.Visible := True;
|
||||
PbRuler.SetBounds(0, TopOff + WH, RW, RULER_H);
|
||||
PbRuler.Visible := True;
|
||||
PositionSampleRateOverlay;
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := 0;
|
||||
FWaterfallHeight := WH;
|
||||
if RW > 0 then
|
||||
begin
|
||||
FSpecView.SetSpectrumBitmapSize(1, 1);
|
||||
FSpecView.SetWaterfallBitmapSize(RW, WH);
|
||||
FSpecView.SetRulerSize(RW, RULER_H);
|
||||
FSpecView.DrawWaterfall;
|
||||
PbWaterfall.Invalidate;
|
||||
PbRuler.Invalidate;
|
||||
end;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
// ---- Оба видимы: стандартный режим со сплиттером ----
|
||||
PbSpectrum.Visible := True;
|
||||
PbRuler.Visible := True;
|
||||
PanelSplitter.Visible := True;
|
||||
PbWaterfall.Visible := True;
|
||||
|
||||
AvailH := RH - TopOff - RULER_H - SPLITTER_H;
|
||||
if AvailH < (MIN_SH + MIN_WH) then Exit;
|
||||
|
||||
// Ограничиваем соотношение, чтобы каждая зона имела минимальный размер
|
||||
if FSplitterRatio < MIN_SH / AvailH then
|
||||
FSplitterRatio := MIN_SH / AvailH;
|
||||
if FSplitterRatio > 1.0 - MIN_WH / AvailH then
|
||||
FSplitterRatio := 1.0 - MIN_WH / AvailH;
|
||||
|
||||
SH := Round(AvailH * FSplitterRatio);
|
||||
WH := AvailH - SH;
|
||||
if WH < MIN_WH then WH := MIN_WH;
|
||||
|
||||
// Спектр
|
||||
PbSpectrum.SetBounds(0, TopOff, RW, SH);
|
||||
// Линейка частот — всегда прижата к низу спектра
|
||||
PbRuler.SetBounds(0, TopOff + SH, RW, RULER_H);
|
||||
// Сплиттер — между линейкой и водопадом
|
||||
PanelSplitter.SetBounds(0, TopOff + SH + RULER_H, RW, SPLITTER_H);
|
||||
// Водопад — под сплиттером
|
||||
PbWaterfall.SetBounds(0, TopOff + SH + RULER_H + SPLITTER_H, RW, WH);
|
||||
|
||||
// Стек спектр/линейка/сплиттер/водопад/пан-зум раскладывает панадаптер.
|
||||
FPan.Layout(WideH, FController.FShowSpectrum, FController.FShowWaterfall);
|
||||
PositionSampleRateOverlay;
|
||||
|
||||
// Обновляем переменные размеров
|
||||
FSpectrumWidth := RW;
|
||||
FSpectrumHeight := SH;
|
||||
FWaterfallHeight := WH;
|
||||
|
||||
// Пересоздаём bitmap точно под новый размер
|
||||
if RW > 0 then
|
||||
begin
|
||||
if SH > 0 then FSpecView.SetSpectrumBitmapSize(RW, SH);
|
||||
if WH > 0 then FSpecView.SetWaterfallBitmapSize(RW, WH);
|
||||
FSpecView.SetRulerSize(RW, RULER_H);
|
||||
FSpecView.DrawSpectrum;
|
||||
PbSpectrum.Invalidate;
|
||||
if PbRuler <> nil then PbRuler.Invalidate;
|
||||
PbWaterfall.Invalidate;
|
||||
end;
|
||||
end;
|
||||
|
||||
// ===========================================================================
|
||||
@@ -3234,17 +2955,17 @@ var
|
||||
begin
|
||||
// Синхронизируем размеры если размер панели изменился (после ресайза).
|
||||
// Важно: проверяем только видимые панели — когда спектр скрыт,
|
||||
// PbSpectrum.Height может быть ненулевым при FSpectrumHeight=0,
|
||||
// PbSpectrum.Height может быть ненулевым при FPan.SpectrumHeight=0,
|
||||
// что вызвало бы сброс буфера водопада на каждом тике.
|
||||
if (FSpectrumWidth = 0) or
|
||||
(FController.FShowWideband and (PbWideband.Width <> FSpectrumWidth)) or
|
||||
(FController.FShowSpectrum and ((PbSpectrum.Width <> FSpectrumWidth) or
|
||||
(PbSpectrum.Height <> FSpectrumHeight))) or
|
||||
if (FPan.SpectrumWidth = 0) or
|
||||
(FController.FShowWideband and (PbWideband.Width <> FPan.SpectrumWidth)) or
|
||||
(FController.FShowSpectrum and ((PbSpectrum.Width <> FPan.SpectrumWidth) or
|
||||
(PbSpectrum.Height <> FPan.SpectrumHeight))) or
|
||||
(FController.FShowWaterfall and not FController.FShowSpectrum and
|
||||
((PbWaterfall.Width <> FSpectrumWidth) or
|
||||
(PbWaterfall.Height <> FWaterfallHeight))) then
|
||||
((PbWaterfall.Width <> FPan.SpectrumWidth) or
|
||||
(PbWaterfall.Height <> FPan.WaterfallHeight))) then
|
||||
ResizeSpectrumPanels;
|
||||
if FSpectrumWidth <= 0 then Exit;
|
||||
if FPan.SpectrumWidth <= 0 then Exit;
|
||||
SyncSpecViewFreq;
|
||||
|
||||
// Проверка таймаута — трансивер не отвечает
|
||||
@@ -3290,11 +3011,11 @@ begin
|
||||
if FController.FWDSPReady then
|
||||
begin
|
||||
FController.FLastSMeter := FController.FDSPEngine.GetSMeterDBm;
|
||||
FController.FDSPEngine.SetSpectrumWidth(FSpectrumWidth);
|
||||
FController.FDSPEngine.SetSpectrumWidth(FPan.SpectrumWidth);
|
||||
Inc(FAgcLineCounter);
|
||||
if FAgcLineCounter >= 6 then
|
||||
begin
|
||||
FController.FDSPEngine.UpdateAGCLines(FSpectrumWidth);
|
||||
FController.FDSPEngine.UpdateAGCLines(FPan.SpectrumWidth);
|
||||
FSpecView.AGCThresh := FController.FDSPEngine.AGCThresh;
|
||||
FSpecView.AGCHangLevel := FController.FDSPEngine.AGCHangLevel;
|
||||
FAgcLineCounter := 0;
|
||||
@@ -3350,9 +3071,9 @@ begin
|
||||
if not FController.FNetwork.Connected then
|
||||
begin
|
||||
// При первом старте показываем демо-спектр
|
||||
if FSpecView.SpectrumBitmapWidth <> FSpectrumWidth then
|
||||
if FSpecView.SpectrumBitmapWidth <> FPan.SpectrumWidth then
|
||||
begin
|
||||
FSpecView.SetSpectrumBitmapSize(FSpectrumWidth, FSpectrumHeight);
|
||||
FSpecView.SetSpectrumBitmapSize(FPan.SpectrumWidth, FPan.SpectrumHeight);
|
||||
FSpecView.ResetSpectrumBuf;
|
||||
FSpecView.DrawSpectrum;
|
||||
PbSpectrum.Invalidate;
|
||||
@@ -3891,7 +3612,7 @@ begin
|
||||
// вся оркестрация в контроллере (ConnectAndRun); рендер device/band/run-
|
||||
// виджетов идёт через события (rfDevice/rfBandRestore/rfXvtr/rfActiveVfo/
|
||||
// rfRunning). Здесь — только UI-extras (статус-строки/AGCTop/resize).
|
||||
if not FController.ConnectAndRun(Dev, FSpectrumWidth) then
|
||||
if not FController.ConnectAndRun(Dev, FPan.SpectrumWidth) then
|
||||
begin
|
||||
ShowMessage('Failed to connect to ' + Dev.IPAddress +
|
||||
IfThen(FController.FNetwork.LastError <> '', ': ' + FController.FNetwork.LastError, ''));
|
||||
@@ -4437,27 +4158,6 @@ end;
|
||||
// Панель пана / зума
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
procedure TMainForm.PositionPanZoomBar(BottomY, RW, H: Integer; AVisible: Boolean);
|
||||
var BtnW, Gap, StripW, X: Integer;
|
||||
begin
|
||||
if (PbPanZoom = nil) or (BtnZoomIn = nil) then Exit;
|
||||
PbPanZoom.Visible := AVisible;
|
||||
BtnZoomIn.Visible := AVisible;
|
||||
BtnZoomDef.Visible := AVisible;
|
||||
BtnZoomOut.Visible := AVisible;
|
||||
if not AVisible then Exit;
|
||||
Gap := MulDiv(2, Screen.PixelsPerInch, 96);
|
||||
BtnW := H; // квадратные кнопки в высоту строки
|
||||
StripW := RW - 3 * BtnW - 4 * Gap;
|
||||
if StripW < 20 then StripW := 20;
|
||||
PbPanZoom.SetBounds(0, BottomY, StripW, H);
|
||||
X := StripW + Gap;
|
||||
BtnZoomOut.SetBounds(X, BottomY, BtnW, H); Inc(X, BtnW + Gap);
|
||||
BtnZoomDef.SetBounds(X, BottomY, BtnW, H); Inc(X, BtnW + Gap);
|
||||
BtnZoomIn.SetBounds(X, BottomY, BtnW, H);
|
||||
PbPanZoom.Invalidate;
|
||||
end;
|
||||
|
||||
procedure TMainForm.UpdatePanZoomBar;
|
||||
begin
|
||||
if FPanZoomBar <> nil then
|
||||
@@ -4475,28 +4175,6 @@ begin
|
||||
FController.ApplyZoom(AZoom, APan);
|
||||
end;
|
||||
|
||||
procedure TMainForm.PbPanZoomDblClick(Sender: TObject);
|
||||
begin
|
||||
if FPanZoomBar <> nil then FPanZoomBar.HandleDblClick;
|
||||
end;
|
||||
|
||||
procedure TMainForm.PbPanZoomMouseDown(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
if FPanZoomBar <> nil then FPanZoomBar.HandleMouseDown(Button, X, Y);
|
||||
end;
|
||||
|
||||
procedure TMainForm.PbPanZoomMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
if FPanZoomBar <> nil then FPanZoomBar.HandleMouseMove(X, Y);
|
||||
end;
|
||||
|
||||
procedure TMainForm.PbPanZoomMouseUp(Sender: TObject; Button: TMouseButton;
|
||||
Shift: TShiftState; X, Y: Integer);
|
||||
begin
|
||||
if FPanZoomBar <> nil then FPanZoomBar.HandleMouseUp;
|
||||
end;
|
||||
|
||||
procedure TMainForm.BtnZoomInClick(Sender: TObject);
|
||||
begin
|
||||
FController.ZoomIn;
|
||||
|
||||
Reference in New Issue
Block a user