mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-26 04:47:35 +00:00
Replace PanelSpanButtons with SampleRateOverlay overlay
- Add SampleRateOverlay.pas: TCustomControl overlay (top-left of spectrum) with hide-panel button and 6 span buttons (48k–1536k), same hit-test pattern as VfoOverlay - Consolidate toolbar: move PanelTopVfoGroup and PanelSMeterRight into PanelToolbar (height 72) instead of floating on the form - Remove PanelSpanButtons (alTop spacer) that caused the ~1cm black strip at the top of the spectrum - Add separator line inside PanelToolbar anchored to its bottom edge, with 16px left/right margins - Fix left panel blocks starting Y offset (was 38, now 0) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+72
-209
@@ -22,7 +22,8 @@ unit MainForm;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, StrUtils, FreqDisplay, DeviceForm, VfoOverlay, FlatButton, FlatSlider, FlatDropDown, AppTheme, Forms, Controls, Graphics, Dialogs,
|
Classes, SysUtils, StrUtils, FreqDisplay, DeviceForm, VfoOverlay, SampleRateOverlay,
|
||||||
|
FlatButton, FlatSlider, FlatDropDown, AppTheme, Forms, Controls, Graphics, Dialogs,
|
||||||
StdCtrls, ExtCtrls, ComCtrls, Buttons, Menus, Math, Types,
|
StdCtrls, ExtCtrls, ComCtrls, Buttons, Menus, Math, Types,
|
||||||
LCLIntf, LCLType, GraphType,
|
LCLIntf, LCLType, GraphType,
|
||||||
HPSDRProtocol, HPSDRNetwork,
|
HPSDRProtocol, HPSDRNetwork,
|
||||||
@@ -180,6 +181,7 @@ type
|
|||||||
FDeviceDialog: TDeviceDialog;
|
FDeviceDialog: TDeviceDialog;
|
||||||
FPendingIP: string; // IP устройства для подключения
|
FPendingIP: string; // IP устройства для подключения
|
||||||
FVfoOverlay: TVfoOverlay; // накладка SmartSDR-стиль на спектре
|
FVfoOverlay: TVfoOverlay; // накладка SmartSDR-стиль на спектре
|
||||||
|
FSampleRateOverlay: TSampleRateOverlay; // оверлей span/hide слева вверху спектра
|
||||||
FPanelHidden: Boolean; // True = левая панель скрыта
|
FPanelHidden: Boolean; // True = левая панель скрыта
|
||||||
FPendingBoardType: Integer; // BoardType устройства для подключения
|
FPendingBoardType: Integer; // BoardType устройства для подключения
|
||||||
|
|
||||||
@@ -341,12 +343,11 @@ type
|
|||||||
FSpectrumTimer: TTimer;
|
FSpectrumTimer: TTimer;
|
||||||
FAfterShowTimer:TTimer; // однократный таймер для пост-инициализации
|
FAfterShowTimer:TTimer; // однократный таймер для пост-инициализации
|
||||||
|
|
||||||
// ---- Toolbar ----
|
// ---- Top panel (toolbar + VFO group + S-meter) ----
|
||||||
PanelToolbar: TPanel;
|
PanelToolbar: TPanel;
|
||||||
BtnDiscover: TFlatButton;
|
BtnDiscover: TFlatButton;
|
||||||
BtnStartStop: TFlatButton; // START / STOP (connect+run в одном)
|
BtnStartStop: TFlatButton;
|
||||||
BtnSettings: TFlatButton; // открыть диалог настроек
|
BtnSettings: TFlatButton;
|
||||||
PanelSep: TPanel; // 1px разделитель под тулбаром
|
|
||||||
|
|
||||||
// ---- Left panel ----
|
// ---- Left panel ----
|
||||||
PanelLeft: TPanel;
|
PanelLeft: TPanel;
|
||||||
@@ -419,15 +420,6 @@ type
|
|||||||
|
|
||||||
// ---- Right panel ----
|
// ---- Right panel ----
|
||||||
PanelRight: TPanel;
|
PanelRight: TPanel;
|
||||||
PanelSpanButtons: TPanel;
|
|
||||||
LblSpan: TLabel;
|
|
||||||
BtnSpan48k: TFlatButton;
|
|
||||||
BtnSpan96k: TFlatButton;
|
|
||||||
BtnSpan192k: TFlatButton;
|
|
||||||
BtnSpan384k: TFlatButton;
|
|
||||||
BtnSpan768k: TFlatButton;
|
|
||||||
BtnSpan1536k: TFlatButton;
|
|
||||||
BtnHidePanel: TFlatButton; // скрыть/показать левую панель
|
|
||||||
PbSpectrum: TPaintBox;
|
PbSpectrum: TPaintBox;
|
||||||
PbRuler: TPaintBox; // полоса частотных меток между спектром и водопадом
|
PbRuler: TPaintBox; // полоса частотных меток между спектром и водопадом
|
||||||
PanelSplitter: TPanel; // перетаскиваемый разделитель спектр/водопад
|
PanelSplitter: TPanel; // перетаскиваемый разделитель спектр/водопад
|
||||||
@@ -445,7 +437,9 @@ type
|
|||||||
procedure SetStatusText(Index: Integer; const Text: string);
|
procedure SetStatusText(Index: Integer; const Text: string);
|
||||||
procedure SetRadioOfflineStatus(const ConnText: string; ClearDevice: Boolean = False);
|
procedure SetRadioOfflineStatus(const ConnText: string; ClearDevice: Boolean = False);
|
||||||
procedure ApplyStatusTheme(const T: TAppTheme);
|
procedure ApplyStatusTheme(const T: TAppTheme);
|
||||||
procedure PositionSpanOverlayButtons;
|
procedure PositionSampleRateOverlay;
|
||||||
|
procedure OnSampleRateSelect(SampleRate: Integer);
|
||||||
|
procedure OnSampleRateHidePanel;
|
||||||
procedure UpdateVfoDisplay;
|
procedure UpdateVfoDisplay;
|
||||||
function FormatFreq(Hz: Double): string;
|
function FormatFreq(Hz: Double): string;
|
||||||
procedure LayoutTopVfoBlock;
|
procedure LayoutTopVfoBlock;
|
||||||
@@ -551,7 +545,6 @@ type
|
|||||||
procedure BtnNBClick(Sender: TObject);
|
procedure BtnNBClick(Sender: TObject);
|
||||||
procedure BtnSNBClick(Sender: TObject);
|
procedure BtnSNBClick(Sender: TObject);
|
||||||
procedure BtnANFClick(Sender: TObject);
|
procedure BtnANFClick(Sender: TObject);
|
||||||
procedure BtnSpanClick(Sender: TObject);
|
|
||||||
// Веб-интерфейс: callbacks от TWebServer
|
// Веб-интерфейс: callbacks от TWebServer
|
||||||
procedure WebOnFreq(Hz: Double);
|
procedure WebOnFreq(Hz: Double);
|
||||||
procedure WebOnMode(Mode: Integer);
|
procedure WebOnMode(Mode: Integer);
|
||||||
@@ -660,7 +653,6 @@ type
|
|||||||
procedure ActivateXvtrBand(Idx: Integer);
|
procedure ActivateXvtrBand(Idx: Integer);
|
||||||
procedure DeactivateXvtr;
|
procedure DeactivateXvtr;
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
procedure BtnHidePanelClick(Sender: TObject);
|
|
||||||
procedure BtnSettingsClick(Sender: TObject);
|
procedure BtnSettingsClick(Sender: TObject);
|
||||||
procedure PositionVfoOverlay;
|
procedure PositionVfoOverlay;
|
||||||
procedure OnModeFilterSelect(Mode: Integer; FilterBW: Integer);
|
procedure OnModeFilterSelect(Mode: Integer; FilterBW: Integer);
|
||||||
@@ -1127,14 +1119,9 @@ begin
|
|||||||
|
|
||||||
// --- Sample Rate / Span ---
|
// --- Sample Rate / Span ---
|
||||||
// SampleRate — глобальный, не per-band. Не восстанавливаем из диапазона.
|
// SampleRate — глобальный, не per-band. Не восстанавливаем из диапазона.
|
||||||
// Обновляем только FSpanHz для отображения (берём текущий FSampleRate)
|
|
||||||
FSpanHz := FSampleRate;
|
FSpanHz := FSampleRate;
|
||||||
StyleSpanButton(BtnSpan48k, FSampleRate = 48000);
|
if Assigned(FSampleRateOverlay) then
|
||||||
StyleSpanButton(BtnSpan96k, FSampleRate = 96000);
|
FSampleRateOverlay.SetCurrentRate(FSampleRate);
|
||||||
StyleSpanButton(BtnSpan192k, FSampleRate = 192000);
|
|
||||||
StyleSpanButton(BtnSpan384k, FSampleRate = 384000);
|
|
||||||
StyleSpanButton(BtnSpan768k, FSampleRate = 768000);
|
|
||||||
StyleSpanButton(BtnSpan1536k, FSampleRate = 1536000);
|
|
||||||
|
|
||||||
// --- VFO A: центрируем на новой частоте, сбрасываем shift ---
|
// --- VFO A: центрируем на новой частоте, сбрасываем shift ---
|
||||||
FCenterFreq := B.VfoA; // DDC = центр диапазона
|
FCenterFreq := B.VfoA; // DDC = центр диапазона
|
||||||
@@ -1375,12 +1362,6 @@ begin
|
|||||||
FCurrentXvtr := -1;
|
FCurrentXvtr := -1;
|
||||||
|
|
||||||
BuildUI;
|
BuildUI;
|
||||||
StyleSpanButton(BtnSpan48k, FSampleRate = 48000);
|
|
||||||
StyleSpanButton(BtnSpan96k, FSampleRate = 96000);
|
|
||||||
StyleSpanButton(BtnSpan192k, FSampleRate = 192000);
|
|
||||||
StyleSpanButton(BtnSpan384k, FSampleRate = 384000);
|
|
||||||
StyleSpanButton(BtnSpan768k, FSampleRate = 768000);
|
|
||||||
StyleSpanButton(BtnSpan1536k, FSampleRate = 1536000);
|
|
||||||
ResizeSMeter;
|
ResizeSMeter;
|
||||||
ApplyDarkTheme;
|
ApplyDarkTheme;
|
||||||
UpdateVfoDisplay;
|
UpdateVfoDisplay;
|
||||||
@@ -1501,6 +1482,7 @@ const
|
|||||||
var
|
var
|
||||||
i, X, Y, W: Integer;
|
i, X, Y, W: Integer;
|
||||||
B: TFlatButton;
|
B: TFlatButton;
|
||||||
|
SepLine: TPanel;
|
||||||
|
|
||||||
function MakeBtn(Parent: TWinControl; const Cap: string;
|
function MakeBtn(Parent: TWinControl; const Cap: string;
|
||||||
ALeft, ATop, AW, AH: Integer; Handler: TNotifyEvent): TFlatButton;
|
ALeft, ATop, AW, AH: Integer; Handler: TNotifyEvent): TFlatButton;
|
||||||
@@ -1535,7 +1517,7 @@ begin
|
|||||||
PanelToolbar := TPanel.Create(Self);
|
PanelToolbar := TPanel.Create(Self);
|
||||||
PanelToolbar.Parent := Self;
|
PanelToolbar.Parent := Self;
|
||||||
PanelToolbar.Align := alTop;
|
PanelToolbar.Align := alTop;
|
||||||
PanelToolbar.Height := 36;
|
PanelToolbar.Height := 72;
|
||||||
PanelToolbar.BevelOuter := bvNone;
|
PanelToolbar.BevelOuter := bvNone;
|
||||||
PanelToolbar.Color := CLR_PANEL;
|
PanelToolbar.Color := CLR_PANEL;
|
||||||
|
|
||||||
@@ -1557,7 +1539,13 @@ begin
|
|||||||
BtnStartStop.ClrBorder := TColor($00304830);
|
BtnStartStop.ClrBorder := TColor($00304830);
|
||||||
BtnStartStop.ClrText := TColor($0090C090);
|
BtnStartStop.ClrText := TColor($0090C090);
|
||||||
|
|
||||||
// ---- Separator line ----
|
// Линия-разделитель внутри PanelToolbar, прижата к его нижнему краю
|
||||||
|
SepLine := TPanel.Create(Self);
|
||||||
|
SepLine.Parent := PanelToolbar;
|
||||||
|
SepLine.BevelOuter := bvNone;
|
||||||
|
SepLine.Color := TColor($00606060);
|
||||||
|
SepLine.SetBounds(16, PanelToolbar.Height - 10, PanelToolbar.Width - 32, 2);
|
||||||
|
SepLine.Anchors := [akLeft, akRight, akBottom];
|
||||||
|
|
||||||
// ---- Status bar ----
|
// ---- Status bar ----
|
||||||
StatusPanel := TMainStatusBar.Create(Self);
|
StatusPanel := TMainStatusBar.Create(Self);
|
||||||
@@ -1570,11 +1558,11 @@ begin
|
|||||||
PanelLeft.Width := LEFT_W;
|
PanelLeft.Width := LEFT_W;
|
||||||
PanelLeft.BevelOuter := bvNone;
|
PanelLeft.BevelOuter := bvNone;
|
||||||
|
|
||||||
Y := 38; // gap below separator: separator at y=66, content starts at y=74
|
Y := 0;
|
||||||
|
|
||||||
// Compact top VFO group
|
// Compact top VFO group
|
||||||
PanelTopVfoGroup := TPanel.Create(Self);
|
PanelTopVfoGroup := TPanel.Create(Self);
|
||||||
PanelTopVfoGroup.Parent := Self;
|
PanelTopVfoGroup.Parent := PanelToolbar;
|
||||||
PanelTopVfoGroup.SetBounds(0, 0, TOP_VFO_W * 2 + 64, 60);
|
PanelTopVfoGroup.SetBounds(0, 0, TOP_VFO_W * 2 + 64, 60);
|
||||||
PanelTopVfoGroup.BevelOuter := bvNone;
|
PanelTopVfoGroup.BevelOuter := bvNone;
|
||||||
PanelTopVfoGroup.Color := TColor($00181818);
|
PanelTopVfoGroup.Color := TColor($00181818);
|
||||||
@@ -1940,59 +1928,15 @@ begin
|
|||||||
PanelRight.BevelOuter := bvNone;
|
PanelRight.BevelOuter := bvNone;
|
||||||
PanelRight.OnResize := RightPanelResize;
|
PanelRight.OnResize := RightPanelResize;
|
||||||
|
|
||||||
PanelSpanButtons := TPanel.Create(Self);
|
FSampleRateOverlay := TSampleRateOverlay.Create(Self);
|
||||||
PanelSpanButtons.Parent := PanelRight;
|
FSampleRateOverlay.Parent := PanelRight;
|
||||||
PanelSpanButtons.Align := alTop;
|
FSampleRateOverlay.OnSpanSelect := OnSampleRateSelect;
|
||||||
PanelSpanButtons.Height := 38;
|
FSampleRateOverlay.OnHidePanel := OnSampleRateHidePanel;
|
||||||
PanelSpanButtons.BevelOuter := bvNone;
|
FSampleRateOverlay.SetCurrentRate(FSampleRate);
|
||||||
|
|
||||||
LblSpan := TLabel.Create(Self);
|
// S-метр — внутри PanelToolbar, справа
|
||||||
LblSpan.Parent := PanelSpanButtons; LblSpan.Left := 4; LblSpan.Top := 8;
|
|
||||||
LblSpan.Caption := 'SPAN:'; LblSpan.Font.Color := CLR_TEXTDIM;
|
|
||||||
LblSpan.Font.Name := 'Courier New'; LblSpan.Font.Size := 7;
|
|
||||||
|
|
||||||
BtnSpan48k := MakeBtn(PanelSpanButtons, '48k', 50, 3, 46, BTN_SM, BtnSpanClick);
|
|
||||||
BtnSpan96k := MakeBtn(PanelSpanButtons, '96k', 99, 3, 46, BTN_SM, BtnSpanClick);
|
|
||||||
BtnSpan192k := MakeBtn(PanelSpanButtons, '192k', 148, 3, 52, BTN_SM, BtnSpanClick);
|
|
||||||
BtnSpan384k := MakeBtn(PanelSpanButtons, '384k', 203, 3, 52, BTN_SM, BtnSpanClick);
|
|
||||||
BtnSpan768k := MakeBtn(PanelSpanButtons, '768k', 258, 3, 52, BTN_SM, BtnSpanClick);
|
|
||||||
BtnSpan1536k := MakeBtn(PanelSpanButtons, '1536k', 313, 3, 58, BTN_SM, BtnSpanClick);
|
|
||||||
BtnSpan48k.Tag := 48000;
|
|
||||||
BtnSpan96k.Tag := 96000;
|
|
||||||
BtnSpan192k.Tag := 192000;
|
|
||||||
BtnSpan384k.Tag := 384000;
|
|
||||||
BtnSpan768k.Tag := 768000;
|
|
||||||
BtnSpan1536k.Tag := 1536000;
|
|
||||||
StyleSpanButton(BtnSpan48k, False);
|
|
||||||
StyleSpanButton(BtnSpan96k, False);
|
|
||||||
StyleSpanButton(BtnSpan192k, True);
|
|
||||||
StyleSpanButton(BtnSpan384k, False);
|
|
||||||
StyleSpanButton(BtnSpan768k, False);
|
|
||||||
StyleSpanButton(BtnSpan1536k, False);
|
|
||||||
|
|
||||||
BtnHidePanel := MakeBtn(PanelRight, '◀', 0, 0, 28, 28, BtnHidePanelClick);
|
|
||||||
BtnHidePanel.Font.Size := 10;
|
|
||||||
BtnHidePanel.ClrNorm := TColor($00543F18);
|
|
||||||
BtnHidePanel.ClrHot := TColor($00624B1D);
|
|
||||||
BtnHidePanel.ClrActive := TColor($00624B1D);
|
|
||||||
BtnHidePanel.ClrBorder := TColor($00685624);
|
|
||||||
BtnHidePanel.ClrText := TColor($00D8E6EE);
|
|
||||||
BtnHidePanel.ClrTextAct := TColor($00F0FAFF);
|
|
||||||
BtnHidePanel.BringToFront;
|
|
||||||
|
|
||||||
// Разделитель: на уровне формы, под всеми верхними элементами
|
|
||||||
PanelSep := TPanel.Create(Self);
|
|
||||||
PanelSep.Parent := Self;
|
|
||||||
PanelSep.Align := alNone;
|
|
||||||
PanelSep.BevelOuter := bvNone;
|
|
||||||
PanelSep.ParentColor := False;
|
|
||||||
PanelSep.Color := TColor($00606060);
|
|
||||||
PanelSep.SetBounds(16, PanelToolbar.Height + 30, ClientWidth - 32, 2);
|
|
||||||
|
|
||||||
// Большой S-метр — на главной форме поверх двух панелей
|
|
||||||
// S-метр: Parent=Self, перекрывает Toolbar+SpanButtons вертикально
|
|
||||||
PanelSMeterRight := TPanel.Create(Self);
|
PanelSMeterRight := TPanel.Create(Self);
|
||||||
PanelSMeterRight.Parent := Self;
|
PanelSMeterRight.Parent := PanelToolbar;
|
||||||
PanelSMeterRight.BevelOuter := bvNone;
|
PanelSMeterRight.BevelOuter := bvNone;
|
||||||
PanelSMeterRight.Color := CLR_PANEL;
|
PanelSMeterRight.Color := CLR_PANEL;
|
||||||
PbSMeterRight := TPaintBox.Create(Self);
|
PbSMeterRight := TPaintBox.Create(Self);
|
||||||
@@ -2033,16 +1977,6 @@ begin
|
|||||||
PbWaterfall.OnMouseMove := PbWaterfallMouseMove;
|
PbWaterfall.OnMouseMove := PbWaterfallMouseMove;
|
||||||
PbWaterfall.OnMouseUp := PbWaterfallMouseUp;
|
PbWaterfall.OnMouseUp := PbWaterfallMouseUp;
|
||||||
|
|
||||||
// SPAN кнопки как оверлей на спектре (в стиле web)
|
|
||||||
BtnSpan48k.Parent := PanelRight;
|
|
||||||
BtnSpan96k.Parent := PanelRight;
|
|
||||||
BtnSpan192k.Parent := PanelRight;
|
|
||||||
BtnSpan384k.Parent := PanelRight;
|
|
||||||
BtnSpan768k.Parent := PanelRight;
|
|
||||||
BtnSpan1536k.Parent := PanelRight;
|
|
||||||
LblSpan.Visible := False;
|
|
||||||
PositionSpanOverlayButtons;
|
|
||||||
|
|
||||||
// Initial layout
|
// Initial layout
|
||||||
ResizeSpectrumPanels;
|
ResizeSpectrumPanels;
|
||||||
end;
|
end;
|
||||||
@@ -2089,7 +2023,7 @@ begin
|
|||||||
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
||||||
DeltaY := P.Y - FSplitterDragY0;
|
DeltaY := P.Y - FSplitterDragY0;
|
||||||
|
|
||||||
TopOff := PanelSpanButtons.Height;
|
TopOff := 0;
|
||||||
AvailH := PanelRight.ClientHeight - TopOff - RULER_H - SPLITTER_H;
|
AvailH := PanelRight.ClientHeight - TopOff - RULER_H - SPLITTER_H;
|
||||||
if AvailH <= 0 then Exit;
|
if AvailH <= 0 then Exit;
|
||||||
|
|
||||||
@@ -2127,7 +2061,7 @@ begin
|
|||||||
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
P := PanelRight.ScreenToClient(PanelSplitter.ClientToScreen(Point(X, Y)));
|
||||||
DeltaY := P.Y - FSplitterDragY0;
|
DeltaY := P.Y - FSplitterDragY0;
|
||||||
|
|
||||||
TopOff := PanelSpanButtons.Height;
|
TopOff := 0;
|
||||||
AvailH := PanelRight.ClientHeight - TopOff - RULER_H - SPLITTER_H;
|
AvailH := PanelRight.ClientHeight - TopOff - RULER_H - SPLITTER_H;
|
||||||
if AvailH <= 0 then Exit;
|
if AvailH <= 0 then Exit;
|
||||||
|
|
||||||
@@ -2173,7 +2107,7 @@ var
|
|||||||
TopVfoAW, TopVfoBW, NeedFreqAW, NeedFreqBW, FreqTextW, GroupW: Integer;
|
TopVfoAW, TopVfoBW, NeedFreqAW, NeedFreqBW, FreqTextW, GroupW: Integer;
|
||||||
XferX, XferY: Integer;
|
XferX, XferY: Integer;
|
||||||
begin
|
begin
|
||||||
if (PanelToolbar = nil) or (PanelSpanButtons = nil) or (PanelTopVfoGroup = nil) or
|
if (PanelToolbar = nil) or (PanelTopVfoGroup = nil) or
|
||||||
(PanelTopVfoA = nil) or (PanelTopVfoB = nil) then Exit;
|
(PanelTopVfoA = nil) or (PanelTopVfoB = nil) then Exit;
|
||||||
|
|
||||||
Canvas.Font.Name := FreqDispB.FontName;
|
Canvas.Font.Name := FreqDispB.FontName;
|
||||||
@@ -2217,16 +2151,14 @@ begin
|
|||||||
DynGap := XFER_SIDE_GAP + ExtraPerSide;
|
DynGap := XFER_SIDE_GAP + ExtraPerSide;
|
||||||
GroupW := TopVfoAW + DynGap + XFER_PANEL_W + DynGap + TopVfoBW;
|
GroupW := TopVfoAW + DynGap + XFER_PANEL_W + DynGap + TopVfoBW;
|
||||||
|
|
||||||
BlockH := PanelToolbar.Height + 30 - (MARGIN * 2); // 30 = span row content, not full PanelSpanButtons
|
BlockH := PanelToolbar.Height - (MARGIN * 2) - 8;
|
||||||
if BlockH < 56 then BlockH := 56;
|
if BlockH < 56 then BlockH := 56;
|
||||||
|
|
||||||
// Центрируем группу в доступном пространстве
|
// Центрируем группу в доступном пространстве
|
||||||
GroupLeft := SafeLeft + (AvailW - GroupW) div 2;
|
GroupLeft := SafeLeft + (AvailW - GroupW) div 2;
|
||||||
GroupTop := TOP_OFFSET;
|
GroupTop := TOP_OFFSET;
|
||||||
|
|
||||||
// Ось выравнивания: центр S-метра на форме (SMTop=3, SMBot=63) → y=33
|
CenterY := PanelToolbar.Height div 2 - GroupTop;
|
||||||
// Относительно PanelTopVfoGroup (GroupTop=2): CenterY = 33 - 2 = 31
|
|
||||||
CenterY := (PanelToolbar.Height + 30) div 2 - GroupTop;
|
|
||||||
|
|
||||||
PanelTopVfoGroup.SetBounds(GroupLeft, GroupTop, GroupW, BlockH);
|
PanelTopVfoGroup.SetBounds(GroupLeft, GroupTop, GroupW, BlockH);
|
||||||
PanelTopVfoGroup.Visible := True;
|
PanelTopVfoGroup.Visible := True;
|
||||||
@@ -2264,15 +2196,11 @@ begin
|
|||||||
FreqDispB.SetBounds(FreqDispB.Left, FreqTop,
|
FreqDispB.SetBounds(FreqDispB.Left, FreqTop,
|
||||||
FreqTextW + VFO_FREQ_LEFT_PAD + VFO_FREQ_RIGHT_PAD, TOP_VFO_FREQ_H);
|
FreqTextW + VFO_FREQ_LEFT_PAD + VFO_FREQ_RIGHT_PAD, TOP_VFO_FREQ_H);
|
||||||
|
|
||||||
if PanelSep <> nil then
|
|
||||||
PanelSep.SetBounds(16, PanelToolbar.Height + 30, ClientWidth - 32, 2);
|
|
||||||
|
|
||||||
PanelTopVfoGroup.BringToFront;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.ResizeSMeter;
|
procedure TMainForm.ResizeSMeter;
|
||||||
// PanelSMeterRight на главной форме (Parent=Self).
|
// PanelSMeterRight на главной форме (Parent=Self).
|
||||||
// По Y: от самого верха формы до низа PanelSpanButtons (Toolbar+Span = 66px).
|
// По Y: от самого верха формы до низа тулбара.
|
||||||
var
|
var
|
||||||
FW: Integer;
|
FW: Integer;
|
||||||
RightW: Integer; // ширина PanelRight
|
RightW: Integer; // ширина PanelRight
|
||||||
@@ -2281,8 +2209,7 @@ var
|
|||||||
SMTop: Integer;
|
SMTop: Integer;
|
||||||
SMBot: Integer;
|
SMBot: Integer;
|
||||||
begin
|
begin
|
||||||
if (PanelSMeterRight = nil) or (PanelToolbar = nil) or
|
if (PanelSMeterRight = nil) or (PanelToolbar = nil) or (PanelLeft = nil) then Exit;
|
||||||
(PanelSpanButtons = nil) or (PanelLeft = nil) then Exit;
|
|
||||||
|
|
||||||
LayoutTopVfoBlock;
|
LayoutTopVfoBlock;
|
||||||
|
|
||||||
@@ -2294,15 +2221,13 @@ begin
|
|||||||
// Ширина S-метра = 32% от PanelRight
|
// Ширина S-метра = 32% от PanelRight
|
||||||
SMW := Round(RightW * SMETER_WIDTH_RATIO);
|
SMW := Round(RightW * SMETER_WIDTH_RATIO);
|
||||||
|
|
||||||
// X: прижат к правому краю формы
|
// X: прижат к правому краю PanelToolbar
|
||||||
SMLeft := FW - SMW - SMETER_MARGIN;
|
SMLeft := FW - SMW - SMETER_MARGIN;
|
||||||
|
|
||||||
// Y: от верха формы+margin до низа PanelSpanButtons-margin
|
|
||||||
SMTop := SMETER_MARGIN;
|
SMTop := SMETER_MARGIN;
|
||||||
SMBot := PanelToolbar.Height + 30 - SMETER_MARGIN; // 30 = span row content, ends before separator
|
SMBot := PanelToolbar.Height - SMETER_MARGIN - 9;
|
||||||
|
|
||||||
PanelSMeterRight.SetBounds(SMLeft, SMTop, SMW, SMBot - SMTop);
|
PanelSMeterRight.SetBounds(SMLeft, SMTop, SMW, SMBot - SMTop);
|
||||||
PanelSMeterRight.BringToFront;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.ResizeSpectrumPanels;
|
procedure TMainForm.ResizeSpectrumPanels;
|
||||||
@@ -2320,7 +2245,7 @@ begin
|
|||||||
if Assigned(FSpecView) then SyncSpecViewFreq;
|
if Assigned(FSpecView) then SyncSpecViewFreq;
|
||||||
RW := PanelRight.ClientWidth;
|
RW := PanelRight.ClientWidth;
|
||||||
RH := PanelRight.ClientHeight;
|
RH := PanelRight.ClientHeight;
|
||||||
TopOff := PanelSpanButtons.Height;
|
TopOff := 0;
|
||||||
// S-метр позиционируется отдельно в ResizeSMeter
|
// S-метр позиционируется отдельно в ResizeSMeter
|
||||||
ResizeSMeter;
|
ResizeSMeter;
|
||||||
|
|
||||||
@@ -2334,7 +2259,7 @@ begin
|
|||||||
FSpectrumWidth := RW;
|
FSpectrumWidth := RW;
|
||||||
FSpectrumHeight := 0;
|
FSpectrumHeight := 0;
|
||||||
FWaterfallHeight := 0;
|
FWaterfallHeight := 0;
|
||||||
PositionSpanOverlayButtons;
|
PositionSampleRateOverlay;
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -2351,7 +2276,7 @@ begin
|
|||||||
PbRuler.Visible := True;
|
PbRuler.Visible := True;
|
||||||
PanelSplitter.Visible := False;
|
PanelSplitter.Visible := False;
|
||||||
PbWaterfall.Visible := False;
|
PbWaterfall.Visible := False;
|
||||||
PositionSpanOverlayButtons;
|
PositionSampleRateOverlay;
|
||||||
FSpectrumWidth := RW;
|
FSpectrumWidth := RW;
|
||||||
FSpectrumHeight := SH;
|
FSpectrumHeight := SH;
|
||||||
FWaterfallHeight := 0;
|
FWaterfallHeight := 0;
|
||||||
@@ -2380,7 +2305,7 @@ begin
|
|||||||
PbWaterfall.Visible := True;
|
PbWaterfall.Visible := True;
|
||||||
PbRuler.SetBounds(0, TopOff + WH, RW, RULER_H);
|
PbRuler.SetBounds(0, TopOff + WH, RW, RULER_H);
|
||||||
PbRuler.Visible := True;
|
PbRuler.Visible := True;
|
||||||
PositionSpanOverlayButtons;
|
PositionSampleRateOverlay;
|
||||||
FSpectrumWidth := RW;
|
FSpectrumWidth := RW;
|
||||||
FSpectrumHeight := 0;
|
FSpectrumHeight := 0;
|
||||||
FWaterfallHeight := WH;
|
FWaterfallHeight := WH;
|
||||||
@@ -2424,7 +2349,7 @@ begin
|
|||||||
// Водопад — под сплиттером
|
// Водопад — под сплиттером
|
||||||
PbWaterfall.SetBounds(0, TopOff + SH + RULER_H + SPLITTER_H, RW, WH);
|
PbWaterfall.SetBounds(0, TopOff + SH + RULER_H + SPLITTER_H, RW, WH);
|
||||||
|
|
||||||
PositionSpanOverlayButtons;
|
PositionSampleRateOverlay;
|
||||||
|
|
||||||
// Обновляем переменные размеров
|
// Обновляем переменные размеров
|
||||||
FSpectrumWidth := RW;
|
FSpectrumWidth := RW;
|
||||||
@@ -2471,7 +2396,7 @@ begin
|
|||||||
if PanelFMCTCSS <> nil then DP(PanelFMCTCSS);
|
if PanelFMCTCSS <> nil then DP(PanelFMCTCSS);
|
||||||
if PanelFMStep <> nil then DP(PanelFMStep);
|
if PanelFMStep <> nil then DP(PanelFMStep);
|
||||||
DP(PanelRX); DP(PanelTX);
|
DP(PanelRX); DP(PanelTX);
|
||||||
DP(PanelRight); DP(PanelSpanButtons);
|
DP(PanelRight);
|
||||||
|
|
||||||
PbSpectrum.Color := T.BG;
|
PbSpectrum.Color := T.BG;
|
||||||
PbWaterfall.Color := T.BG;
|
PbWaterfall.Color := T.BG;
|
||||||
@@ -2481,7 +2406,7 @@ begin
|
|||||||
|
|
||||||
// Метки
|
// Метки
|
||||||
DL(LblAGCTop, False);
|
DL(LblAGCTop, False);
|
||||||
DL(LblDrv); DL(LblSpan);
|
DL(LblDrv);
|
||||||
if LblFMSQ <> nil then DL(LblFMSQ, False);
|
if LblFMSQ <> nil then DL(LblFMSQ, False);
|
||||||
|
|
||||||
// Кнопки тулбара
|
// Кнопки тулбара
|
||||||
@@ -2518,17 +2443,10 @@ begin
|
|||||||
StyleButton(BtnMOX, BtnMOX.Active);
|
StyleButton(BtnMOX, BtnMOX.Active);
|
||||||
StyleButton(BtnTUN, BtnTUN.Active);
|
StyleButton(BtnTUN, BtnTUN.Active);
|
||||||
|
|
||||||
// Span / VFO-copy / HidePanel
|
// VFO-copy
|
||||||
StyleSpanButton(BtnSpan48k, BtnSpan48k.Active);
|
|
||||||
StyleSpanButton(BtnSpan96k, BtnSpan96k.Active);
|
|
||||||
StyleSpanButton(BtnSpan192k, BtnSpan192k.Active);
|
|
||||||
StyleSpanButton(BtnSpan384k, BtnSpan384k.Active);
|
|
||||||
StyleSpanButton(BtnSpan768k, BtnSpan768k.Active);
|
|
||||||
StyleSpanButton(BtnSpan1536k, BtnSpan1536k.Active);
|
|
||||||
StyleSpanButton(BtnVfoACopyB, False);
|
StyleSpanButton(BtnVfoACopyB, False);
|
||||||
StyleSpanButton(BtnVfoSwap, False);
|
StyleSpanButton(BtnVfoSwap, False);
|
||||||
StyleSpanButton(BtnVfoBCopyA, False);
|
StyleSpanButton(BtnVfoBCopyA, False);
|
||||||
if BtnHidePanel <> nil then StyleSpanButton(BtnHidePanel, False);
|
|
||||||
|
|
||||||
// Ползунки
|
// Ползунки
|
||||||
DS(TrkAGC); DS(TrkVolume); DS(TrkDrive);
|
DS(TrkAGC); DS(TrkVolume); DS(TrkDrive);
|
||||||
@@ -2618,59 +2536,17 @@ begin
|
|||||||
B.Font.Size := 7;
|
B.Font.Size := 7;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.PositionSpanOverlayButtons;
|
procedure TMainForm.PositionSampleRateOverlay;
|
||||||
const
|
const
|
||||||
BTN_TOP = 6;
|
MARGIN = 4;
|
||||||
GAP = 3;
|
|
||||||
W48 = 40;
|
|
||||||
W96 = 40;
|
|
||||||
W192 = 44;
|
|
||||||
W384 = 44;
|
|
||||||
W768 = 44;
|
|
||||||
W1536 = 50;
|
|
||||||
HBTN = 18;
|
|
||||||
var
|
|
||||||
X, NeedW, BaseX, BaseY: Integer;
|
|
||||||
begin
|
begin
|
||||||
if (PbSpectrum = nil) or (BtnSpan48k = nil) then Exit;
|
if (FSampleRateOverlay = nil) or (PbSpectrum = nil) then Exit;
|
||||||
NeedW := W48 + W96 + W192 + W384 + W768 + W1536 + GAP * 5 + 8;
|
FSampleRateOverlay.SetBounds(
|
||||||
if PbSpectrum.Width < NeedW then
|
PbSpectrum.Left + MARGIN,
|
||||||
begin
|
PbSpectrum.Top + MARGIN,
|
||||||
BtnSpan48k.Visible := False;
|
FSampleRateOverlay.Width,
|
||||||
BtnSpan96k.Visible := False;
|
FSampleRateOverlay.Height);
|
||||||
BtnSpan192k.Visible := False;
|
FSampleRateOverlay.BringToFront;
|
||||||
BtnSpan384k.Visible := False;
|
|
||||||
BtnSpan768k.Visible := False;
|
|
||||||
BtnSpan1536k.Visible := False;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
BaseX := PbSpectrum.Left;
|
|
||||||
BaseY := PbSpectrum.Top;
|
|
||||||
X := BaseX + 56;
|
|
||||||
BtnSpan48k.SetBounds(X, BaseY + BTN_TOP, W48, HBTN); Inc(X, W48 + GAP);
|
|
||||||
BtnSpan96k.SetBounds(X, BaseY + BTN_TOP, W96, HBTN); Inc(X, W96 + GAP);
|
|
||||||
BtnSpan192k.SetBounds(X, BaseY + BTN_TOP, W192, HBTN); Inc(X, W192 + GAP);
|
|
||||||
BtnSpan384k.SetBounds(X, BaseY + BTN_TOP, W384, HBTN); Inc(X, W384 + GAP);
|
|
||||||
BtnSpan768k.SetBounds(X, BaseY + BTN_TOP, W768, HBTN); Inc(X, W768 + GAP);
|
|
||||||
BtnSpan1536k.SetBounds(X, BaseY + BTN_TOP, W1536, HBTN);
|
|
||||||
if BtnHidePanel <> nil then
|
|
||||||
BtnHidePanel.SetBounds(BaseX, BaseY + BTN_TOP, 28, HBTN);
|
|
||||||
|
|
||||||
BtnSpan48k.Visible := True;
|
|
||||||
BtnSpan96k.Visible := True;
|
|
||||||
BtnSpan192k.Visible := True;
|
|
||||||
BtnSpan384k.Visible := True;
|
|
||||||
BtnSpan768k.Visible := True;
|
|
||||||
BtnSpan1536k.Visible := True;
|
|
||||||
|
|
||||||
BtnSpan48k.BringToFront;
|
|
||||||
BtnSpan96k.BringToFront;
|
|
||||||
BtnSpan192k.BringToFront;
|
|
||||||
BtnSpan384k.BringToFront;
|
|
||||||
BtnSpan768k.BringToFront;
|
|
||||||
BtnSpan1536k.BringToFront;
|
|
||||||
if BtnHidePanel <> nil then BtnHidePanel.BringToFront;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -3954,6 +3830,8 @@ begin
|
|||||||
begin
|
begin
|
||||||
FSampleRate := G_Settings.SampleRate;
|
FSampleRate := G_Settings.SampleRate;
|
||||||
FSpanHz := FSampleRate;
|
FSpanHz := FSampleRate;
|
||||||
|
if Assigned(FSampleRateOverlay) then
|
||||||
|
FSampleRateOverlay.SetCurrentRate(FSampleRate);
|
||||||
end;
|
end;
|
||||||
BtnNR.Tag := EnsureRange(G_Settings.NRMode, 0, 4); UpdateNRButton;
|
BtnNR.Tag := EnsureRange(G_Settings.NRMode, 0, 4); UpdateNRButton;
|
||||||
BtnNB.Tag := EnsureRange(G_Settings.NBMode, 0, 2); UpdateNBButton;
|
BtnNB.Tag := EnsureRange(G_Settings.NBMode, 0, 2); UpdateNBButton;
|
||||||
@@ -5390,13 +5268,12 @@ begin
|
|||||||
FSettings.SaveWebSettings(W);
|
FSettings.SaveWebSettings(W);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.BtnHidePanelClick(Sender: TObject);
|
procedure TMainForm.OnSampleRateHidePanel;
|
||||||
begin
|
begin
|
||||||
FPanelHidden := not FPanelHidden;
|
FPanelHidden := not FPanelHidden;
|
||||||
if FPanelHidden then
|
if FPanelHidden then
|
||||||
begin
|
begin
|
||||||
PanelLeft.Width := 0;
|
PanelLeft.Width := 0;
|
||||||
BtnHidePanel.Caption := '▶';
|
|
||||||
FVfoOverlay.Parent := PanelRight;
|
FVfoOverlay.Parent := PanelRight;
|
||||||
FVfoOverlay.Width := 260;
|
FVfoOverlay.Width := 260;
|
||||||
FVfoOverlay.Height := 136; // OVL_H_NORM — расширяется сам при открытии AGC-пикера
|
FVfoOverlay.Height := 136; // OVL_H_NORM — расширяется сам при открытии AGC-пикера
|
||||||
@@ -5409,9 +5286,10 @@ begin
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
PanelLeft.Width := 232;
|
PanelLeft.Width := 232;
|
||||||
BtnHidePanel.Caption := '◀';
|
|
||||||
FVfoOverlay.Visible := False;
|
FVfoOverlay.Visible := False;
|
||||||
end;
|
end;
|
||||||
|
if Assigned(FSampleRateOverlay) then
|
||||||
|
FSampleRateOverlay.SetPanelHidden(FPanelHidden);
|
||||||
ResizeSpectrumPanels;
|
ResizeSpectrumPanels;
|
||||||
ResizeSMeter;
|
ResizeSMeter;
|
||||||
end;
|
end;
|
||||||
@@ -5492,25 +5370,20 @@ begin
|
|||||||
FBandCache[FCurrentBand].AGCMode := FAGCMode;
|
FBandCache[FCurrentBand].AGCMode := FAGCMode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.BtnSpanClick(Sender: TObject);
|
procedure TMainForm.OnSampleRateSelect(SampleRate: Integer);
|
||||||
var
|
var
|
||||||
NewRate: Integer;
|
NewRate: Integer;
|
||||||
DDCRate: Word;
|
DDCRate: Word;
|
||||||
begin
|
begin
|
||||||
NewRate := (Sender as TFlatButton).Tag;
|
NewRate := SampleRate;
|
||||||
if NewRate = FSampleRate then Exit;
|
if NewRate = FSampleRate then Exit;
|
||||||
|
|
||||||
FSampleRate := NewRate;
|
FSampleRate := NewRate;
|
||||||
FSpanHz := NewRate;
|
FSpanHz := NewRate;
|
||||||
DDCRate := NewRate div 1000;
|
DDCRate := NewRate div 1000;
|
||||||
|
|
||||||
// Обновляем кнопки сразу — UI отзывчив
|
if Assigned(FSampleRateOverlay) then
|
||||||
StyleSpanButton(BtnSpan48k, FSampleRate = 48000);
|
FSampleRateOverlay.SetCurrentRate(NewRate);
|
||||||
StyleSpanButton(BtnSpan96k, FSampleRate = 96000);
|
|
||||||
StyleSpanButton(BtnSpan192k, FSampleRate = 192000);
|
|
||||||
StyleSpanButton(BtnSpan384k, FSampleRate = 384000);
|
|
||||||
StyleSpanButton(BtnSpan768k, FSampleRate = 768000);
|
|
||||||
StyleSpanButton(BtnSpan1536k, FSampleRate = 1536000);
|
|
||||||
Application.ProcessMessages;
|
Application.ProcessMessages;
|
||||||
|
|
||||||
FBandCache[FCurrentBand].SpanHz := FSpanHz; // для обратной совместимости
|
FBandCache[FCurrentBand].SpanHz := FSpanHz; // для обратной совместимости
|
||||||
@@ -5762,27 +5635,17 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.SyncWebSpan;
|
procedure TMainForm.SyncWebSpan;
|
||||||
|
const
|
||||||
|
ValidSpans: array[0..5] of Integer = (48000, 96000, 192000, 384000, 768000, 1536000);
|
||||||
var
|
var
|
||||||
ValidSpans: array[0..5] of Integer;
|
|
||||||
Found: Boolean;
|
|
||||||
i: Integer;
|
i: Integer;
|
||||||
Btn: TFlatButton;
|
|
||||||
begin
|
begin
|
||||||
ValidSpans[0]:=48000; ValidSpans[1]:=96000; ValidSpans[2]:=192000;
|
for i := 0 to High(ValidSpans) do
|
||||||
ValidSpans[3]:=384000; ValidSpans[4]:=768000; ValidSpans[5]:=1536000;
|
if ValidSpans[i] = FWebSyncInt then
|
||||||
Found := False;
|
begin
|
||||||
for i := 0 to 5 do
|
OnSampleRateSelect(FWebSyncInt);
|
||||||
if ValidSpans[i] = FWebSyncInt then begin Found := True; Break; end;
|
Exit;
|
||||||
if not Found then Exit;
|
end;
|
||||||
if FWebSyncInt = FSampleRate then Exit;
|
|
||||||
Btn := nil;
|
|
||||||
if FWebSyncInt = 48000 then Btn := BtnSpan48k
|
|
||||||
else if FWebSyncInt = 96000 then Btn := BtnSpan96k
|
|
||||||
else if FWebSyncInt = 192000 then Btn := BtnSpan192k
|
|
||||||
else if FWebSyncInt = 384000 then Btn := BtnSpan384k
|
|
||||||
else if FWebSyncInt = 768000 then Btn := BtnSpan768k
|
|
||||||
else if FWebSyncInt = 1536000 then Btn := BtnSpan1536k;
|
|
||||||
if Assigned(Btn) then BtnSpanClick(Btn);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.WebOnVolume(V: Integer);
|
procedure TMainForm.WebOnVolume(V: Integer);
|
||||||
|
|||||||
@@ -0,0 +1,241 @@
|
|||||||
|
unit SampleRateOverlay;
|
||||||
|
|
||||||
|
{
|
||||||
|
Overlay виджет для выбора sample rate (span) спектра.
|
||||||
|
Размещается в верхнем левом углу спектрограммы поверх PbSpectrum.
|
||||||
|
Содержит кнопку скрытия левой панели и ряд кнопок span.
|
||||||
|
}
|
||||||
|
|
||||||
|
{$IFDEF FPC}
|
||||||
|
{$MODE Delphi}
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Controls, Graphics, Types, Math;
|
||||||
|
|
||||||
|
type
|
||||||
|
TSpanSelectEvent = procedure(SampleRate: Integer) of object;
|
||||||
|
THidePanelEvent = procedure of object;
|
||||||
|
|
||||||
|
TSampleRateOverlay = class(TCustomControl)
|
||||||
|
private
|
||||||
|
FCurrentRate: Integer;
|
||||||
|
FPanelHidden: Boolean;
|
||||||
|
FOnSpanSelect: TSpanSelectEvent;
|
||||||
|
FOnHidePanel: THidePanelEvent;
|
||||||
|
|
||||||
|
FHitRects: array[0..6] of TRect; // [0]=hide button, [1..6]=span buttons
|
||||||
|
FHitValues: array[0..6] of Integer; // 0=hide, else sample rate
|
||||||
|
FHitCount: Integer;
|
||||||
|
FHotIdx: Integer;
|
||||||
|
|
||||||
|
procedure DrawSelf(C: TCanvas; W, H: Integer);
|
||||||
|
procedure RegisterHit(const HR: TRect; Value: Integer);
|
||||||
|
protected
|
||||||
|
procedure Paint; override;
|
||||||
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
||||||
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
||||||
|
X, Y: Integer); override;
|
||||||
|
procedure MouseLeave; override;
|
||||||
|
public
|
||||||
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
procedure SetCurrentRate(Rate: Integer);
|
||||||
|
procedure SetPanelHidden(Hidden: Boolean);
|
||||||
|
property OnSpanSelect: TSpanSelectEvent read FOnSpanSelect write FOnSpanSelect;
|
||||||
|
property OnHidePanel: THidePanelEvent read FOnHidePanel write FOnHidePanel;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
const
|
||||||
|
SPAN_RATES: array[0..5] of Integer = (48000, 96000, 192000, 384000, 768000, 1536000);
|
||||||
|
SPAN_NAMES: array[0..5] of string = ('48k', '96k', '192k', '384k', '768k', '1536k');
|
||||||
|
|
||||||
|
HIDE_W = 22;
|
||||||
|
SPAN_H = 18;
|
||||||
|
PAD_X = 4;
|
||||||
|
PAD_Y = 4;
|
||||||
|
BTN_GAP = 3;
|
||||||
|
|
||||||
|
CLR_BG = TColor($00141414);
|
||||||
|
CLR_BORDER = TColor($00505050);
|
||||||
|
CLR_TEXT = TColor($00D8E6EE);
|
||||||
|
CLR_BTN_NORM = TColor($00543F18);
|
||||||
|
CLR_BTN_HOT = TColor($00624B1D);
|
||||||
|
CLR_BTN_ACT = TColor($00785A20);
|
||||||
|
CLR_BTN_BDR = TColor($00685624);
|
||||||
|
|
||||||
|
function SpanBtnWidth(const Name: string; C: TCanvas): Integer;
|
||||||
|
begin
|
||||||
|
C.Font.Name := 'Courier New';
|
||||||
|
C.Font.Size := 7;
|
||||||
|
C.Font.Style := [];
|
||||||
|
Result := C.TextWidth(Name) + 10;
|
||||||
|
if Result < 36 then Result := 36;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TSampleRateOverlay.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
ControlStyle := ControlStyle + [csOpaque];
|
||||||
|
FCurrentRate := 192000;
|
||||||
|
FPanelHidden := False;
|
||||||
|
FHitCount := 0;
|
||||||
|
FHotIdx := -1;
|
||||||
|
Cursor := crHandPoint;
|
||||||
|
Width := 320;
|
||||||
|
Height := SPAN_H + PAD_Y * 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.RegisterHit(const HR: TRect; Value: Integer);
|
||||||
|
begin
|
||||||
|
if FHitCount > High(FHitRects) then Exit;
|
||||||
|
FHitRects[FHitCount] := HR;
|
||||||
|
FHitValues[FHitCount] := Value;
|
||||||
|
Inc(FHitCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.DrawSelf(C: TCanvas; W, H: Integer);
|
||||||
|
var
|
||||||
|
X, I, TW, TH, BtnW: Integer;
|
||||||
|
HR: TRect;
|
||||||
|
IsAct, IsHot: Boolean;
|
||||||
|
Cap: string;
|
||||||
|
begin
|
||||||
|
FHitCount := 0;
|
||||||
|
|
||||||
|
// Фон
|
||||||
|
C.Brush.Color := CLR_BG;
|
||||||
|
C.Brush.Style := bsSolid;
|
||||||
|
C.Pen.Style := psClear;
|
||||||
|
C.FillRect(Rect(0, 0, W, H));
|
||||||
|
|
||||||
|
// Рамка
|
||||||
|
C.Pen.Style := psSolid;
|
||||||
|
C.Pen.Color := CLR_BORDER;
|
||||||
|
C.Brush.Style := bsClear;
|
||||||
|
C.Rectangle(0, 0, W, H);
|
||||||
|
|
||||||
|
C.Font.Name := 'Courier New';
|
||||||
|
C.Font.Size := 7;
|
||||||
|
C.Font.Style := [];
|
||||||
|
TH := C.TextHeight('A');
|
||||||
|
X := PAD_X;
|
||||||
|
|
||||||
|
// Кнопка скрытия панели (◀ или ▶)
|
||||||
|
HR := Rect(X, PAD_Y, X + HIDE_W, PAD_Y + SPAN_H);
|
||||||
|
IsHot := (FHotIdx = 0);
|
||||||
|
if IsHot then C.Brush.Color := CLR_BTN_HOT
|
||||||
|
else C.Brush.Color := CLR_BTN_NORM;
|
||||||
|
C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
||||||
|
C.FillRect(HR);
|
||||||
|
C.Pen.Style := psSolid; C.Pen.Color := CLR_BTN_BDR;
|
||||||
|
C.Brush.Style := bsClear; C.Rectangle(HR);
|
||||||
|
C.Font.Size := 8;
|
||||||
|
if FPanelHidden then Cap := '▶' else Cap := '◀';
|
||||||
|
TW := C.TextWidth(Cap); C.Font.Size := 7;
|
||||||
|
C.Font.Color := CLR_TEXT;
|
||||||
|
C.Brush.Style := bsClear;
|
||||||
|
C.Font.Size := 8;
|
||||||
|
C.TextOut(HR.Left + (HIDE_W - TW) div 2,
|
||||||
|
HR.Top + (SPAN_H - TH) div 2, Cap);
|
||||||
|
C.Font.Size := 7;
|
||||||
|
RegisterHit(HR, 0);
|
||||||
|
Inc(X, HIDE_W + BTN_GAP);
|
||||||
|
|
||||||
|
// Кнопки span
|
||||||
|
for I := 0 to High(SPAN_RATES) do
|
||||||
|
begin
|
||||||
|
BtnW := SpanBtnWidth(SPAN_NAMES[I], C);
|
||||||
|
HR := Rect(X, PAD_Y, X + BtnW, PAD_Y + SPAN_H);
|
||||||
|
IsAct := (SPAN_RATES[I] = FCurrentRate);
|
||||||
|
IsHot := (FHotIdx = I + 1);
|
||||||
|
|
||||||
|
if IsAct then C.Brush.Color := CLR_BTN_ACT
|
||||||
|
else if IsHot then C.Brush.Color := CLR_BTN_HOT
|
||||||
|
else C.Brush.Color := CLR_BTN_NORM;
|
||||||
|
C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
||||||
|
C.FillRect(HR);
|
||||||
|
C.Pen.Style := psSolid; C.Pen.Color := CLR_BTN_BDR;
|
||||||
|
C.Brush.Style := bsClear; C.Rectangle(HR);
|
||||||
|
|
||||||
|
TW := C.TextWidth(SPAN_NAMES[I]);
|
||||||
|
C.Font.Color := CLR_TEXT;
|
||||||
|
C.Brush.Style := bsClear;
|
||||||
|
C.TextOut(HR.Left + (BtnW - TW) div 2,
|
||||||
|
HR.Top + (SPAN_H - TH) div 2, SPAN_NAMES[I]);
|
||||||
|
|
||||||
|
RegisterHit(HR, SPAN_RATES[I]);
|
||||||
|
Inc(X, BtnW + BTN_GAP);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.Paint;
|
||||||
|
begin
|
||||||
|
DrawSelf(Canvas, Width, Height);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.MouseMove(Shift: TShiftState; X, Y: Integer);
|
||||||
|
var
|
||||||
|
I, OldHot: Integer;
|
||||||
|
begin
|
||||||
|
OldHot := FHotIdx;
|
||||||
|
FHotIdx := -1;
|
||||||
|
for I := 0 to FHitCount - 1 do
|
||||||
|
if PtInRect(FHitRects[I], Point(X, Y)) then
|
||||||
|
begin
|
||||||
|
FHotIdx := I;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
if FHotIdx <> OldHot then Invalidate;
|
||||||
|
inherited MouseMove(Shift, X, Y);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.MouseDown(Button: TMouseButton;
|
||||||
|
Shift: TShiftState; X, Y: Integer);
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
if Button <> mbLeft then Exit;
|
||||||
|
for I := 0 to FHitCount - 1 do
|
||||||
|
if PtInRect(FHitRects[I], Point(X, Y)) then
|
||||||
|
begin
|
||||||
|
if FHitValues[I] = 0 then
|
||||||
|
begin
|
||||||
|
if Assigned(FOnHidePanel) then FOnHidePanel;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if Assigned(FOnSpanSelect) then FOnSpanSelect(FHitValues[I]);
|
||||||
|
end;
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.MouseLeave;
|
||||||
|
begin
|
||||||
|
if FHotIdx >= 0 then
|
||||||
|
begin
|
||||||
|
FHotIdx := -1;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
inherited MouseLeave;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.SetCurrentRate(Rate: Integer);
|
||||||
|
begin
|
||||||
|
if FCurrentRate = Rate then Exit;
|
||||||
|
FCurrentRate := Rate;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSampleRateOverlay.SetPanelHidden(Hidden: Boolean);
|
||||||
|
begin
|
||||||
|
if FPanelHidden = Hidden then Exit;
|
||||||
|
FPanelHidden := Hidden;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
@@ -95,6 +95,10 @@
|
|||||||
<Filename Value="VfoOverlay.pas"/>
|
<Filename Value="VfoOverlay.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
</Unit>
|
</Unit>
|
||||||
|
<Unit>
|
||||||
|
<Filename Value="SampleRateOverlay.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit>
|
||||||
<Unit>
|
<Unit>
|
||||||
<Filename Value="AudioOutput.pas"/>
|
<Filename Value="AudioOutput.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user