ui(main): fix DPI layout and theme switching

This commit is contained in:
2026-08-05 15:55:03 +03:00
parent 998cb3f0fe
commit b70daa9dbf
3 changed files with 185 additions and 116 deletions
+24 -12
View File
@@ -32,9 +32,11 @@ type
FItemBtns: array of TFlatButton;
FItemIndex: Integer;
FColumns: Integer;
FItemBtnH: Integer;
FItemBtnH96: Integer;
FRightInset96: Integer;
FIsOpen: Boolean;
FStyleProc: TButtonStyleProc;
FPanelColor: TColor;
FOnSelect: TDropDownSelectEvent;
procedure ItemClick(Sender: TObject);
procedure PositionPopup;
@@ -61,15 +63,17 @@ begin
inherited Create;
FAnchor := AAnchor;
FPopupParent := APopupParent;
FColumns := ACols;
FItemBtnH := ABtnH;
FColumns := Max(1, ACols);
FItemBtnH96 := Max(1, ABtnH);
FRightInset96 := Max(0, ARightInset96);
FItemIndex := 0;
FIsOpen := False;
FStyleProc := nil;
FPanelColor := TColor($00181818);
FPopup := TPanel.Create(nil);
FPopup.Parent := APopupParent;
FPopup.BevelOuter := bvNone;
FPopup.Color := TColor($00181818);
FPopup.Color := FPanelColor;
FPopup.Visible := False;
end;
@@ -81,7 +85,7 @@ end;
procedure TFlatDropDown.SetItems(const ANames: array of string);
var
I, Count, BtnW, PopW: Integer;
I, Count, BtnW, PopW, ItemBtnH, EdgePad, ItemGap: Integer;
B: TFlatButton;
begin
while FPopup.ControlCount > 0 do
@@ -93,17 +97,22 @@ begin
// при каждом наполнении: SetItems бывает и до, и после DPI-scale формы.
PopW := Max(1, FPopupParent.ClientWidth -
FPopupParent.Scale96ToForm(FRightInset96));
BtnW := (PopW - 4) div FColumns;
ItemBtnH := FPopupParent.Scale96ToForm(FItemBtnH96);
EdgePad := FPopupParent.Scale96ToForm(2);
ItemGap := FPopupParent.Scale96ToForm(2);
BtnW := Max(1, (PopW - 2 * EdgePad) div FColumns);
FPopup.SetBounds(0, 0, PopW,
((Count + FColumns - 1) div FColumns) * FItemBtnH);
((Count + FColumns - 1) div FColumns) * ItemBtnH);
for I := 0 to Count - 1 do
begin
B := MakeFlatBtn(FPopup, ANames[I],
2 + (I mod FColumns) * BtnW,
(I div FColumns) * FItemBtnH,
BtnW - 2, FItemBtnH, @ItemClick);
EdgePad + (I mod FColumns) * BtnW,
(I div FColumns) * ItemBtnH,
Max(1, BtnW - ItemGap), ItemBtnH, @ItemClick);
B.Tag := I;
B.Active := (I = FItemIndex);
if Assigned(FStyleProc) then
FStyleProc(B, B.Active);
FItemBtns[I] := B;
end;
end;
@@ -141,9 +150,10 @@ var
begin
P := FAnchor.ClientToScreen(Point(0, FAnchor.Height));
P := FPopupParent.ScreenToClient(P);
Y0 := P.Y + 2;
Y0 := P.Y + FPopupParent.Scale96ToForm(2);
if Y0 + FPopup.Height > FPopupParent.ClientHeight then
Y0 := P.Y - FAnchor.Height - FPopup.Height - 2;
Y0 := P.Y - FAnchor.Height - FPopup.Height -
FPopupParent.Scale96ToForm(2);
if Y0 < 0 then Y0 := 0;
FPopup.Top := Y0;
FPopup.Left := 0;
@@ -173,6 +183,8 @@ procedure TFlatDropDown.ApplyStyle(AStyleProc: TButtonStyleProc; APanelColor: TC
var
I: Integer;
begin
FStyleProc := AStyleProc;
FPanelColor := APanelColor;
FPopup.Color := APanelColor;
for I := 0 to High(FItemBtns) do
if FItemBtns[I] <> nil then
-1
View File
@@ -7,7 +7,6 @@ object MainForm: TMainForm
Color = clBlack
Font.Color = clSilver
Font.Height = -13
Font.Name = 'Courier New'
Position = poDesigned
LCLVersion = '4.6.0.0'
OnClose = FormClose
+161 -103
View File
@@ -106,6 +106,7 @@ const
TOP_SMETER_GAP = 8;
TOP_VFO_FONT = 25;
LEFT_SCROLL_GUTTER_W = 8;
LEFT_PANEL_CONTENT_W = 232;
LEFT_PANEL_BTN_PAD = 3;
LEFT_PANEL_BTN_GAP = 2;
@@ -825,17 +826,18 @@ const
// Высота RX-блока левой панели: с рядом ATT (openHPSDR) и без него (Pluto —
// там усиление тракта в блоке RF AGC). Переключает LayoutLeftPanel, он же
// двигает панели ниже.
RX_BLOCK_H = 96;
RX_BLOCK_H_ATT = 120;
RX_BLOCK_H = 100;
RX_BLOCK_H_ATT = 124;
function TMainForm.LeftPanelButtonWidth(PanelWidth, ColCount,
ColIndex: Integer): Integer;
var
InnerW, BaseW, Extra: Integer;
InnerW, BaseW, Extra, Pad, Gap: Integer;
begin
if ColCount <= 0 then Exit(0);
InnerW := PanelWidth - 2 * LEFT_PANEL_BTN_PAD -
(ColCount - 1) * LEFT_PANEL_BTN_GAP;
Pad := MulDiv(LEFT_PANEL_BTN_PAD, PanelWidth, LEFT_PANEL_CONTENT_W);
Gap := MulDiv(LEFT_PANEL_BTN_GAP, PanelWidth, LEFT_PANEL_CONTENT_W);
InnerW := PanelWidth - 2 * Pad - (ColCount - 1) * Gap;
BaseW := InnerW div ColCount;
Extra := InnerW mod ColCount;
Result := BaseW;
@@ -845,12 +847,14 @@ end;
function TMainForm.LeftPanelButtonLeft(PanelWidth, ColCount,
ColIndex: Integer): Integer;
var
i: Integer;
i, Pad, Gap: Integer;
begin
Result := LEFT_PANEL_BTN_PAD;
Pad := MulDiv(LEFT_PANEL_BTN_PAD, PanelWidth, LEFT_PANEL_CONTENT_W);
Gap := MulDiv(LEFT_PANEL_BTN_GAP, PanelWidth, LEFT_PANEL_CONTENT_W);
Result := Pad;
for i := 0 to ColIndex - 1 do
Inc(Result, LeftPanelButtonWidth(PanelWidth, ColCount, i) +
LEFT_PANEL_BTN_GAP);
Gap);
end;
// ===========================================================================
@@ -1864,9 +1868,9 @@ procedure TMainForm.BuildUI;
const
BTN_H = 26;
BTN_SM = 24;
LEFT_W = 232;
// Заголовок (16) + MODE_ROWS рядов с шагом 27 + нижний отступ.
MODE_PANEL_H = 16 + (MODE_ROWS - 1) * 27 + BTN_SM + 7;
LEFT_W = LEFT_PANEL_CONTENT_W;
// Заголовок с отступом (20) + MODE_ROWS рядов с шагом 27 + нижний отступ.
MODE_PANEL_H = 20 + (MODE_ROWS - 1) * 27 + BTN_SM + 3;
PLUTO_AGC_H = 64; // высота отдельного Pluto RF-AGC блока (под AGC)
TOP_VFO_W = 244;
TOP_VFO_FREQ_H = 47;
@@ -1899,8 +1903,7 @@ var
L.Left := ALeft;
L.Top := ATop;
L.Font.Color := CLR_TEXTDIM;
L.Font.Name := 'Courier New';
L.Font.Size := 7;
L.Font.Size := 8;
end;
begin
@@ -1981,8 +1984,7 @@ begin
PanelVfoA.BevelOuter := bvNone;
BtnTopVfoASelect := MakeBtn(PanelVfoA, 'A', 0, 5, 20, 18, BtnTopVfoASelectClick);
BtnTopVfoASelect.Font.Name := 'Courier New';
BtnTopVfoASelect.Font.Size := 7;
BtnTopVfoASelect.Font.Size := 8;
BtnTopVfoASelect.Font.Bold := True;
BtnTopVfoASelect.ClrNorm := TColor($00303030);
BtnTopVfoASelect.ClrHot := TColor($00404040);
@@ -1992,8 +1994,7 @@ begin
BtnTopVfoASelect.ClrTextAct := CLR_TEXT;
BtnTopVfoATX := MakeBtn(PanelVfoA, 'TX', 0, 25, 20, 18, BtnTopVfoATXClick);
BtnTopVfoATX.Font.Name := 'Courier New';
BtnTopVfoATX.Font.Size := 7;
BtnTopVfoATX.Font.Size := 8;
BtnTopVfoATX.Font.Bold := True;
BtnTopVfoATX.ClrNorm := TColor($00303030);
BtnTopVfoATX.ClrHot := TColor($00404040);
@@ -2006,7 +2007,7 @@ begin
LblVfoALabel.Parent := PanelVfoA;
LblVfoALabel.Caption := 'VFO-A';
LblVfoALabel.Left := 0; LblVfoALabel.Top := 0;
LblVfoALabel.Font.Name := 'Courier New'; LblVfoALabel.Font.Size := 7;
LblVfoALabel.Font.Size := 8;
LblVfoALabel.Font.Color := CLR_TEXTDIM;
LblVfoALabel.Visible := False;
@@ -2038,8 +2039,7 @@ begin
PanelVfoB.BevelOuter := bvNone;
BtnTopVfoBSelect := MakeBtn(PanelVfoB, 'B', 0, 5, 20, 18, BtnTopVfoBSelectClick);
BtnTopVfoBSelect.Font.Name := 'Courier New';
BtnTopVfoBSelect.Font.Size := 7;
BtnTopVfoBSelect.Font.Size := 8;
BtnTopVfoBSelect.Font.Bold := True;
BtnTopVfoBSelect.ClrNorm := TColor($00303030);
BtnTopVfoBSelect.ClrHot := TColor($00404040);
@@ -2049,8 +2049,7 @@ begin
BtnTopVfoBSelect.ClrTextAct := CLR_TEXT;
BtnTopVfoBTX := MakeBtn(PanelVfoB, 'TX', 0, 25, 20, 18, BtnTopVfoBTXClick);
BtnTopVfoBTX.Font.Name := 'Courier New';
BtnTopVfoBTX.Font.Size := 7;
BtnTopVfoBTX.Font.Size := 8;
BtnTopVfoBTX.Font.Bold := True;
BtnTopVfoBTX.ClrNorm := TColor($00303030);
BtnTopVfoBTX.ClrHot := TColor($00404040);
@@ -2063,7 +2062,7 @@ begin
LblVfoBLabel.Parent := PanelVfoB;
LblVfoBLabel.Caption := 'VFO-B';
LblVfoBLabel.Left := 0; LblVfoBLabel.Top := 0;
LblVfoBLabel.Font.Name := 'Courier New'; LblVfoBLabel.Font.Size := 7;
LblVfoBLabel.Font.Size := 8;
LblVfoBLabel.Font.Color := CLR_TEXTDIM;
LblVfoBLabel.Visible := False;
@@ -2096,9 +2095,9 @@ begin
StyleSpanButton(BtnVfoACopyB, False);
StyleSpanButton(BtnVfoSwap, False);
StyleSpanButton(BtnVfoBCopyA, False);
BtnVfoACopyB.Font.Size := 7;
BtnVfoSwap.Font.Size := 7;
BtnVfoBCopyA.Font.Size := 7;
BtnVfoACopyB.Font.Size := 8;
BtnVfoSwap.Font.Size := 8;
BtnVfoBCopyA.Font.Size := 8;
LayoutTopVfoBlock;
@@ -2110,23 +2109,23 @@ begin
MakeLbl(PanelTX, 'TX', 4, 2);
BtnMOX := MakeBtn(PanelTX, 'MOX',
LeftPanelButtonLeft(LEFT_W, 4, 0), 16,
LeftPanelButtonLeft(LEFT_W, 4, 0), 20,
LeftPanelButtonWidth(LEFT_W, 4, 0), BTN_SM, BtnMOXClick);
BtnTUN := MakeBtn(PanelTX, 'TUN',
LeftPanelButtonLeft(LEFT_W, 4, 1), 16,
LeftPanelButtonLeft(LEFT_W, 4, 1), 20,
LeftPanelButtonWidth(LEFT_W, 4, 1), BTN_SM, BtnTUNClick);
// PureSignal: ЛКМ = вкл/выкл, ПКМ = поповер настроек/управления.
BtnPS := MakeBtn(PanelTX, 'PS',
LeftPanelButtonLeft(LEFT_W, 4, 2), 16,
LeftPanelButtonLeft(LEFT_W, 4, 2), 20,
LeftPanelButtonWidth(LEFT_W, 4, 2), BTN_SM, BtnPSClick);
BtnPS.OnMouseDown := BtnPSMouseDown;
Btn2Ton := MakeBtn(PanelTX, '2TON',
LeftPanelButtonLeft(LEFT_W, 4, 3), 16,
LeftPanelButtonLeft(LEFT_W, 4, 3), 20,
LeftPanelButtonWidth(LEFT_W, 4, 3), BTN_SM, Btn2TonClick);
UpdateTXControlAvailability;
BtnDUP := MakeBtn(PanelTX, 'DUP',
LeftPanelButtonLeft(LEFT_W, 4, 0), 44,
LeftPanelButtonLeft(LEFT_W, 4, 0), 48,
LeftPanelButtonWidth(LEFT_W, 4, 0), BTN_SM, BtnDUPClick);
BtnDUP.Tag := 0;
StyleButton(BtnDUP, FController.FDisplayDuplex);
@@ -2135,7 +2134,7 @@ begin
// активна только в DUP (см. UpdateRxMuteButton). ON (подсвечена, умолч.) =
// RX-аудио глушится на TX; OFF = слышим свой downlink во время передачи.
BtnRxMute := MakeBtn(PanelTX, 'RX MUTE',
LeftPanelButtonLeft(LEFT_W, 4, 1), 44,
LeftPanelButtonLeft(LEFT_W, 4, 1), 48,
LeftPanelButtonWidth(LEFT_W, 4, 1), BTN_SM, BtnRxMuteClick);
StyleButton(BtnRxMute, FController.FRxMuteOnTx);
UpdateRxMuteButton; // видимость/активность по DUP
@@ -2143,7 +2142,7 @@ begin
// TX-профиль — свободные колонки 2..3 того же ряда (панель не растёт по
// высоте). Подпись = имя активного профиля, ЛКМ — список, ПКМ — настройки.
BtnTXProfile := MakeBtn(PanelTX, 'Default',
LeftPanelButtonLeft(LEFT_W, 4, 2), 44,
LeftPanelButtonLeft(LEFT_W, 4, 2), 48,
LeftPanelButtonLeft(LEFT_W, 4, 3)
+ LeftPanelButtonWidth(LEFT_W, 4, 3)
- LeftPanelButtonLeft(LEFT_W, 4, 2),
@@ -2159,10 +2158,10 @@ begin
LblDrv := TLabel.Create(Self);
LblDrv.Parent := PanelTX; LblDrv.Left := 4; LblDrv.Top := 77;
LblDrv.Caption := 'DRV'; LblDrv.Font.Color := CLR_TEXTDIM;
LblDrv.Font.Name := 'Courier New'; LblDrv.Font.Size := 7;
LblDrv.Font.Size := 8;
TrkDrive := TFlatSlider.Create(Self);
TrkDrive.Parent := PanelTX; TrkDrive.Left := 34; TrkDrive.Top := 74;
TrkDrive.Parent := PanelTX; TrkDrive.Left := 34; TrkDrive.Top := 78;
TrkDrive.Width := 120; TrkDrive.Height := 16;
TrkDrive.Min := 0; TrkDrive.Max := 100; TrkDrive.Position := 50;
TrkDrive.OnChange := TrkDriveChange;
@@ -2170,8 +2169,8 @@ begin
LblDrvVal := TLabel.Create(Self);
LblDrvVal.Parent := PanelTX;
LblDrvVal.Left := 158; LblDrvVal.Top := 77;
LblDrvVal.Font.Color := CLR_TEXT; LblDrvVal.Font.Name := 'Courier New';
LblDrvVal.Font.Size := 7;
LblDrvVal.Font.Color := CLR_TEXT;
LblDrvVal.Font.Size := 8;
UpdateDriveLabel;
Inc(Y, 100);
@@ -2184,14 +2183,14 @@ begin
MakeLbl(PanelRXBlock, 'RX', 4, 2);
BtnCTun := MakeBtn(PanelRXBlock, 'CTUN',
LeftPanelButtonLeft(LEFT_W, 3, 0), 16,
LeftPanelButtonLeft(LEFT_W, 3, 0), 20,
LeftPanelButtonWidth(LEFT_W, 3, 0),
BTN_H, BtnCTunClick);
BtnCTun.Tag := 0;
StyleButton(BtnCTun, FController.FCTun);
BtnChannels := MakeBtn(PanelRXBlock, 'Channel',
LeftPanelButtonLeft(LEFT_W, 3, 1), 16,
LeftPanelButtonLeft(LEFT_W, 3, 1), 20,
LeftPanelButtonWidth(LEFT_W, 3, 1),
BTN_H, BtnChannelsClick);
BtnChannels.OnMouseDown := BtnChannelsMouseDown;
@@ -2205,7 +2204,7 @@ begin
// QO-100 beacon lock — 3-я колонка ряда. Видима только в XVTR-режиме
// (см. рендер rfXvtr ниже). Подпись/подсветка обновляются по rfBeaconLock.
BtnBeacon := MakeBtn(PanelRXBlock, 'BEACON',
LeftPanelButtonLeft(LEFT_W, 3, 2), 16,
LeftPanelButtonLeft(LEFT_W, 3, 2), 20,
LeftPanelButtonWidth(LEFT_W, 3, 2),
BTN_H, BtnBeaconClick);
BtnBeacon.Visible := False;
@@ -2214,26 +2213,26 @@ begin
MakeLbl(PanelRXBlock, 'VOL', 4, 50);
TrkVolume := TFlatSlider.Create(Self);
TrkVolume.Parent := PanelRXBlock; TrkVolume.Left := 34; TrkVolume.Top := 46;
TrkVolume.Parent := PanelRXBlock; TrkVolume.Left := 34; TrkVolume.Top := 50;
TrkVolume.Width := LEFT_W - 38; TrkVolume.Height := 16;
TrkVolume.Min := 0; TrkVolume.Max := 100;
TrkVolume.Position := FController.FVolume;
TrkVolume.OnChange := TrkVolumeChange;
BtnNR := MakeBtn(PanelRXBlock, 'NR',
LeftPanelButtonLeft(LEFT_W, 5, 0), 70,
LeftPanelButtonLeft(LEFT_W, 5, 0), 74,
LeftPanelButtonWidth(LEFT_W, 5, 0), BTN_SM, BtnNRClick);
BtnNB := MakeBtn(PanelRXBlock, 'NB',
LeftPanelButtonLeft(LEFT_W, 5, 1), 70,
LeftPanelButtonLeft(LEFT_W, 5, 1), 74,
LeftPanelButtonWidth(LEFT_W, 5, 1), BTN_SM, BtnNBClick);
BtnSNB := MakeBtn(PanelRXBlock, 'SNB',
LeftPanelButtonLeft(LEFT_W, 5, 2), 70,
LeftPanelButtonLeft(LEFT_W, 5, 2), 74,
LeftPanelButtonWidth(LEFT_W, 5, 2), BTN_SM, BtnSNBClick);
BtnANF := MakeBtn(PanelRXBlock, 'ANF',
LeftPanelButtonLeft(LEFT_W, 5, 3), 70,
LeftPanelButtonLeft(LEFT_W, 5, 3), 74,
LeftPanelButtonWidth(LEFT_W, 5, 3), BTN_SM, BtnANFClick);
BtnMute := MakeBtn(PanelRXBlock, 'MUTE',
LeftPanelButtonLeft(LEFT_W, 5, 4), 70,
LeftPanelButtonLeft(LEFT_W, 5, 4), 74,
LeftPanelButtonWidth(LEFT_W, 5, 4), BTN_SM, BtnMuteClick);
// Шаговый аттенюатор ADC — плавный 0..31 дБ (железо openHPSDR так и умеет,
@@ -2242,10 +2241,10 @@ begin
LblAtt := TLabel.Create(Self);
LblAtt.Parent := PanelRXBlock; LblAtt.Left := 4; LblAtt.Top := 106;
LblAtt.Caption := 'ATT'; LblAtt.Font.Color := CLR_TEXTDIM;
LblAtt.Font.Name := 'Courier New'; LblAtt.Font.Size := 7;
LblAtt.Font.Size := 8;
TrkAtt := TFlatSlider.Create(Self);
TrkAtt.Parent := PanelRXBlock; TrkAtt.Left := 34; TrkAtt.Top := 102;
TrkAtt.Parent := PanelRXBlock; TrkAtt.Left := 34; TrkAtt.Top := 106;
TrkAtt.Width := LEFT_W - 76; TrkAtt.Height := 16;
TrkAtt.Min := 0; TrkAtt.Max := 31; // ADC step attenuator, дБ
TrkAtt.Position := FController.FAtten;
@@ -2254,8 +2253,8 @@ begin
LblAttVal := TLabel.Create(Self);
LblAttVal.Parent := PanelRXBlock;
LblAttVal.Left := LEFT_W - 38; LblAttVal.Top := 106;
LblAttVal.Font.Color := CLR_TEXT; LblAttVal.Font.Name := 'Courier New';
LblAttVal.Font.Size := 7;
LblAttVal.Font.Color := CLR_TEXT;
LblAttVal.Font.Size := 8;
UpdateAttLabel;
Inc(Y, RX_BLOCK_H_ATT + 4);
@@ -2269,27 +2268,27 @@ begin
// AGC mode — 5 кнопок в ряд
MakeLbl(PanelAGC, 'AGC', 4, 2);
BtnAGCMode[0] := MakeBtn(PanelAGC, 'FAST',
LeftPanelButtonLeft(LEFT_W, 5, 0), 16,
LeftPanelButtonLeft(LEFT_W, 5, 0), 20,
LeftPanelButtonWidth(LEFT_W, 5, 0),
BTN_SM, BtnAGCModeClick);
BtnAGCMode[0].Tag := 0;
BtnAGCMode[1] := MakeBtn(PanelAGC, 'MED',
LeftPanelButtonLeft(LEFT_W, 5, 1), 16,
LeftPanelButtonLeft(LEFT_W, 5, 1), 20,
LeftPanelButtonWidth(LEFT_W, 5, 1),
BTN_SM, BtnAGCModeClick);
BtnAGCMode[1].Tag := 1;
BtnAGCMode[2] := MakeBtn(PanelAGC, 'SLOW',
LeftPanelButtonLeft(LEFT_W, 5, 2), 16,
LeftPanelButtonLeft(LEFT_W, 5, 2), 20,
LeftPanelButtonWidth(LEFT_W, 5, 2),
BTN_SM, BtnAGCModeClick);
BtnAGCMode[2].Tag := 2;
BtnAGCMode[3] := MakeBtn(PanelAGC, 'LONG',
LeftPanelButtonLeft(LEFT_W, 5, 3), 16,
LeftPanelButtonLeft(LEFT_W, 5, 3), 20,
LeftPanelButtonWidth(LEFT_W, 5, 3),
BTN_SM, BtnAGCModeClick);
BtnAGCMode[3].Tag := 3;
BtnAGCMode[4] := MakeBtn(PanelAGC, 'OFF',
LeftPanelButtonLeft(LEFT_W, 5, 4), 16,
LeftPanelButtonLeft(LEFT_W, 5, 4), 20,
LeftPanelButtonWidth(LEFT_W, 5, 4),
BTN_SM, BtnAGCModeClick);
BtnAGCMode[4].Tag := 4;
@@ -2298,7 +2297,7 @@ begin
// AGC level slider
MakeLbl(PanelAGC, 'THRESH', 4, 44);
TrkAGC := TFlatSlider.Create(Self);
TrkAGC.Parent := PanelAGC; TrkAGC.Left := 56; TrkAGC.Top := 40;
TrkAGC.Parent := PanelAGC; TrkAGC.Left := 56; TrkAGC.Top := 44;
TrkAGC.Width := LEFT_W - 96; TrkAGC.Height := 16;
TrkAGC.Min := 20; TrkAGC.Max := 120; // 20..120 → 20..-120 dBm
TrkAGC.Position := FController.FAGCTop;
@@ -2309,8 +2308,8 @@ begin
LblAGCTop.Parent := PanelAGC;
LblAGCTop.Left := LEFT_W - 38; LblAGCTop.Top := 44;
LblAGCTop.Caption := Format('-%ddB', [FController.FAGCTop]);
LblAGCTop.Font.Color := CLR_TEXT; LblAGCTop.Font.Name := 'Courier New';
LblAGCTop.Font.Size := 7;
LblAGCTop.Font.Color := CLR_TEXT;
LblAGCTop.Font.Size := 8;
Inc(Y, 74);
@@ -2324,25 +2323,25 @@ begin
MakeLbl(PanelPlutoAGC, 'RF AGC', 4, 2);
// Режимы AD936x: FAST/SLOW/HYB/MAN. Tag = индекс режима (1/2/3/0).
BtnPlutoGain[0] := MakeBtn(PanelPlutoAGC, 'FAST',
LeftPanelButtonLeft(LEFT_W, 4, 0), 16, LeftPanelButtonWidth(LEFT_W, 4, 0),
LeftPanelButtonLeft(LEFT_W, 4, 0), 20, LeftPanelButtonWidth(LEFT_W, 4, 0),
BTN_SM, BtnPlutoGainClick);
BtnPlutoGain[0].Tag := 1;
BtnPlutoGain[1] := MakeBtn(PanelPlutoAGC, 'SLOW',
LeftPanelButtonLeft(LEFT_W, 4, 1), 16, LeftPanelButtonWidth(LEFT_W, 4, 1),
LeftPanelButtonLeft(LEFT_W, 4, 1), 20, LeftPanelButtonWidth(LEFT_W, 4, 1),
BTN_SM, BtnPlutoGainClick);
BtnPlutoGain[1].Tag := 2;
BtnPlutoGain[2] := MakeBtn(PanelPlutoAGC, 'HYB',
LeftPanelButtonLeft(LEFT_W, 4, 2), 16, LeftPanelButtonWidth(LEFT_W, 4, 2),
LeftPanelButtonLeft(LEFT_W, 4, 2), 20, LeftPanelButtonWidth(LEFT_W, 4, 2),
BTN_SM, BtnPlutoGainClick);
BtnPlutoGain[2].Tag := 3;
BtnPlutoGain[3] := MakeBtn(PanelPlutoAGC, 'MAN',
LeftPanelButtonLeft(LEFT_W, 4, 3), 16, LeftPanelButtonWidth(LEFT_W, 4, 3),
LeftPanelButtonLeft(LEFT_W, 4, 3), 20, LeftPanelButtonWidth(LEFT_W, 4, 3),
BTN_SM, BtnPlutoGainClick);
BtnPlutoGain[3].Tag := 0;
// Manual gain slider.
MakeLbl(PanelPlutoAGC, 'GAIN', 4, 44);
TrkRxGain := TFlatSlider.Create(Self);
TrkRxGain.Parent := PanelPlutoAGC; TrkRxGain.Left := 56; TrkRxGain.Top := 40;
TrkRxGain.Parent := PanelPlutoAGC; TrkRxGain.Left := 56; TrkRxGain.Top := 44;
TrkRxGain.Width := LEFT_W - 96; TrkRxGain.Height := 16;
TrkRxGain.Min := 0; TrkRxGain.Max := 73; // AD936x hardwaregain dB
TrkRxGain.Position := FController.FRxGainDb;
@@ -2351,8 +2350,8 @@ begin
LblRxGain.Parent := PanelPlutoAGC;
LblRxGain.Left := LEFT_W - 38; LblRxGain.Top := 44;
LblRxGain.Caption := Format('%ddB', [FController.FRxGainDb]);
LblRxGain.Font.Color := CLR_TEXT; LblRxGain.Font.Name := 'Courier New';
LblRxGain.Font.Size := 7;
LblRxGain.Font.Color := CLR_TEXT;
LblRxGain.Font.Size := 8;
// НЕ Inc(Y): панель скрыта и наложена на позицию Bands; LayoutLeftPanel сдвинет.
// Band selector. Высота резервирует 2 дополнительных ряда под XVTR-кнопки
@@ -2367,7 +2366,7 @@ begin
begin
B := MakeBtn(PanelBands, BAND_NAMES[i],
LeftPanelButtonLeft(LEFT_W, 6, i mod 6),
16 + (i div 6) * 27,
20 + (i div 6) * 27,
LeftPanelButtonWidth(LEFT_W, 6, i mod 6),
BTN_SM, BtnBandClick);
B.Tag := i;
@@ -2391,7 +2390,7 @@ begin
begin
B := MakeBtn(PanelMode, MODE_NAMES[i],
LeftPanelButtonLeft(LEFT_W, 4, i mod 4),
16 + (i div 4) * 27,
20 + (i div 4) * 27,
LeftPanelButtonWidth(LEFT_W, 4, i mod 4),
BTN_SM, BtnModeClick);
B.Tag := i;
@@ -2412,7 +2411,7 @@ begin
begin
B := MakeBtn(PanelFilter, '---',
LeftPanelButtonLeft(LEFT_W, FILT_GRID_COLS, i mod FILT_GRID_COLS),
16 + (i div FILT_GRID_COLS) * 27,
20 + (i div FILT_GRID_COLS) * 27,
LeftPanelButtonWidth(LEFT_W, FILT_GRID_COLS, i mod FILT_GRID_COLS),
BTN_SM, BtnFilterClick);
B.Tag := i;
@@ -2448,7 +2447,6 @@ begin
LblRawDev.Alignment := taRightJustify;
LblRawDev.Caption := Format('%.2f k', [FController.FRawFMDeviation / 1000.0]);
LblRawDev.Font.Color := CLR_TEXT;
LblRawDev.Font.Name := 'Courier New';
LblRawDev.Font.Size := 8;
// FM Squelch panel (visible only in FM mode, above CTCSS)
@@ -2460,15 +2458,15 @@ begin
MakeLbl(PanelFMSQ, 'SQL', 4, 2);
W := LeftPanelButtonWidth(LEFT_W, 4, 0);
BtnFMSQ := MakeBtn(PanelFMSQ, 'SQL',
LeftPanelButtonLeft(LEFT_W, 4, 0), 16,
LeftPanelButtonLeft(LEFT_W, 4, 0), 20,
W, BTN_SM, BtnFMSQClick);
StyleButton(BtnFMSQ, False);
// Slider: vertically centred with button text (button top=16, h=24 → center=28)
// Slider vertically centred with the button row.
// Reserve 28px on the right for the numeric label
TrkFMSQ := TFlatSlider.Create(Self);
TrkFMSQ.Parent := PanelFMSQ;
TrkFMSQ.Left := BtnFMSQ.Left + BtnFMSQ.Width + 3;
TrkFMSQ.Top := 21; // 28 - 14/2 = 21
TrkFMSQ.Top := 25;
TrkFMSQ.Width := LEFT_W - TrkFMSQ.Left - 30 - 4; // leave 30px for label + margins
TrkFMSQ.Height := 14;
TrkFMSQ.Min := 0; TrkFMSQ.Max := 100;
@@ -2478,11 +2476,10 @@ begin
LblFMSQ := TLabel.Create(Self);
LblFMSQ.Parent := PanelFMSQ;
LblFMSQ.Left := TrkFMSQ.Left + TrkFMSQ.Width + 3;
LblFMSQ.Top := 21;
LblFMSQ.Top := 23;
LblFMSQ.Width := 26;
LblFMSQ.Caption := IntToStr(FController.FFMSQLevel);
LblFMSQ.Font.Color := CLR_TEXT;
LblFMSQ.Font.Name := 'Courier New';
LblFMSQ.Font.Size := 8;
// FM CTCSS panel (visible only when FM mode is active)
@@ -2493,12 +2490,12 @@ begin
PanelFMCTCSS.Visible := False;
MakeLbl(PanelFMCTCSS, 'CTCSS', 4, 2);
BtnFMCTCSS := MakeBtn(PanelFMCTCSS, 'CTCSS',
LeftPanelButtonLeft(LEFT_W, 3, 0), 16,
LeftPanelButtonLeft(LEFT_W, 3, 0), 20,
LeftPanelButtonWidth(LEFT_W, 3, 0),
BTN_H, BtnFMCTCSSClick);
StyleButton(BtnFMCTCSS, False);
BtnFMCTCSSTone := MakeBtn(PanelFMCTCSS, CTCSS_NAMES[0],
LeftPanelButtonLeft(LEFT_W, 3, 1), 16,
LeftPanelButtonLeft(LEFT_W, 3, 1), 20,
LEFT_W - LEFT_PANEL_BTN_PAD -
LeftPanelButtonLeft(LEFT_W, 3, 1),
BTN_H, BtnFMCTCSSToneClick);
@@ -2518,12 +2515,12 @@ begin
PanelFMStep.Visible := False;
MakeLbl(PanelFMStep, 'STEP', 4, 2);
BtnFMStep := MakeBtn(PanelFMStep, 'STEP',
LeftPanelButtonLeft(LEFT_W, 3, 0), 16,
LeftPanelButtonLeft(LEFT_W, 3, 0), 20,
LeftPanelButtonWidth(LEFT_W, 3, 0),
BTN_H, BtnFMStepClick);
StyleButton(BtnFMStep, FController.FFMStepOn);
BtnFMStepSel := MakeBtn(PanelFMStep, FM_STEP_NAMES[FController.FFMStepIdx],
LeftPanelButtonLeft(LEFT_W, 3, 1), 16,
LeftPanelButtonLeft(LEFT_W, 3, 1), 20,
LEFT_W - LEFT_PANEL_BTN_PAD -
LeftPanelButtonLeft(LEFT_W, 3, 1),
BTN_H, BtnFMStepSelClick);
@@ -2543,18 +2540,18 @@ begin
PanelFMRpt.Visible := False;
MakeLbl(PanelFMRpt, 'RPT', 4, 2);
BtnFMRptMinus := MakeBtn(PanelFMRpt, '-',
LeftPanelButtonLeft(LEFT_W, 5, 0), 16,
LeftPanelButtonLeft(LEFT_W, 5, 0), 20,
LeftPanelButtonWidth(LEFT_W, 5, 0), BTN_H, BtnFMRptMinusClick);
StyleButton(BtnFMRptMinus, False);
BtnFMRptPlus := MakeBtn(PanelFMRpt, '+',
LeftPanelButtonLeft(LEFT_W, 5, 4), 16,
LeftPanelButtonLeft(LEFT_W, 5, 4), 20,
LeftPanelButtonWidth(LEFT_W, 5, 4), BTN_H, BtnFMRptPlusClick);
StyleButton(BtnFMRptPlus, False);
W := LeftPanelButtonLeft(LEFT_W, 5, 1);
EdFMRptOffset := TFlatEdit.Create(Self);
EdFMRptOffset.Parent := PanelFMRpt;
EdFMRptOffset.Left := W;
EdFMRptOffset.Top := 18;
EdFMRptOffset.Top := 22;
EdFMRptOffset.Width := LeftPanelButtonLeft(LEFT_W, 5, 4) - W - LEFT_PANEL_BTN_GAP;
EdFMRptOffset.Height := BTN_H - 4;
EdFMRptOffset.Text := RptFormatOffset(FController.FFMRptOffsetHz);
@@ -3159,6 +3156,15 @@ procedure TMainForm.ApplyDarkTheme;
var T: TAppTheme; i: Integer;
procedure DP(P: TPanel);
begin P.Color := T.Panel; P.Font.Color := T.Text; end;
procedure DPL(P: TPanel);
var
J: Integer;
begin
if P = nil then Exit;
for J := 0 to P.ControlCount - 1 do
if P.Controls[J] is TLabel then
TLabel(P.Controls[J]).Font.Color := T.TextDim;
end;
procedure DL(L: TLabel; Dim: Boolean = True);
begin if Dim then L.Font.Color := T.TextDim else L.Font.Color := T.Text; end;
procedure DS(S: TFlatSlider);
@@ -3177,6 +3183,7 @@ begin
DP(PanelTopVfoGroup); DP(PanelTopVfoA); DP(PanelTopVfoB);
DP(PanelVfoA); DP(PanelVfoB); DP(PanelVfoButtons);
DP(PanelBands); DP(PanelMode); DP(PanelFilter);
if PanelPlutoAGC <> nil then DP(PanelPlutoAGC);
if PanelFMSQ <> nil then DP(PanelFMSQ);
if PanelRawDev <> nil then DP(PanelRawDev);
if PanelFMCTCSS <> nil then DP(PanelFMCTCSS);
@@ -3186,17 +3193,30 @@ begin
DP(PanelRXBlock); DP(PanelAGC); DP(PanelTX);
DP(PanelRight);
if PbSpectrum is TPaintBox then
TPaintBox(PbSpectrum).Color := T.BG;
if PbWaterfall is TPaintBox then
TPaintBox(PbWaterfall).Color := T.BG;
if PanelSMeterRight <> nil then PanelSMeterRight.Color := T.Panel;
if PbSMeterRight <> nil then PbSMeterRight.Color := T.Panel;
ApplyStatusTheme(T);
// Метки
// Заголовки групп и подписи строк.
DPL(PanelTX);
DPL(PanelRXBlock);
DPL(PanelAGC);
DPL(PanelPlutoAGC);
DPL(PanelBands);
DPL(PanelMode);
DPL(PanelFilter);
DPL(PanelRawDev);
DPL(PanelFMStep);
DPL(PanelFMSQ);
DPL(PanelFMCTCSS);
DPL(PanelFMRpt);
// Значения справа от ползунков ярче обычных подписей.
DL(LblAGCTop, False);
DL(LblDrv);
DL(LblDrvVal, False);
DL(LblAttVal, False);
DL(LblRxGain, False);
DL(LblRawDev, False);
if LblFMSQ <> nil then DL(LblFMSQ, False);
// Кнопки тулбара
@@ -3208,23 +3228,39 @@ begin
BtnDiscover.ClrTextAct := T.TbDiscoverText;
BtnDiscover.Invalidate;
BtnStartStop.ClrNorm := T.TbStartNorm;
BtnStartStop.ClrActive := T.TbStartNorm;
BtnStartStop.ClrHot := T.TbStartNorm;
BtnStartStop.ClrBorder := T.TbStartBorder;
BtnStartStop.ClrText := T.TbStartText;
BtnStartStop.ClrTextAct:= T.TbStartText;
BtnStartStop.Invalidate;
StyleButton(BtnSettings, False);
// Обычные кнопки — все массивы
for i := 0 to BAND_COUNT-1 do StyleButton(BtnBand[i], BtnBand[i].Active);
for i := 0 to CFG_XVTR_COUNT - 1 do
if BtnXvtrBand[i] <> nil then
StyleButton(BtnXvtrBand[i], BtnXvtrBand[i].Active);
for i := 0 to MODE_COUNT-1 do StyleButton(BtnMode[i], BtnMode[i].Active);
for i := 0 to FILT_SLOTS-1 do StyleButton(BtnFilter[i], BtnFilter[i].Active);
for i := 0 to 4 do StyleButton(BtnAGCMode[i],BtnAGCMode[i].Active);
StyleButton(BtnCTun, BtnCTun.Active);
StyleButton(BtnDUP, BtnDUP.Active);
StyleButton(BtnPS, BtnPS.Active);
StyleButton(Btn2Ton, Btn2Ton.Active);
StyleButton(BtnRxMute, BtnRxMute.Active);
StyleButton(BtnBeacon, BtnBeacon.Active);
if BtnFMSQ <> nil then StyleButton(BtnFMSQ, BtnFMSQ.Active);
if TrkFMSQ <> nil then DS(TrkFMSQ);
if BtnFMCTCSS <> nil then StyleButton(BtnFMCTCSS, BtnFMCTCSS.Active);
if BtnFMCTCSSTone <> nil then StyleButton(BtnFMCTCSSTone, False);
if BtnFMStep <> nil then StyleButton(BtnFMStep, BtnFMStep.Active);
if BtnFMStepSel <> nil then StyleButton(BtnFMStepSel, False);
if BtnFMRptMinus <> nil then StyleButton(BtnFMRptMinus, BtnFMRptMinus.Active);
if BtnFMRptPlus <> nil then StyleButton(BtnFMRptPlus, BtnFMRptPlus.Active);
for i := 0 to 3 do
if BtnPlutoGain[i] <> nil then
StyleButton(BtnPlutoGain[i], BtnPlutoGain[i].Active);
if FCTCSSDropDown <> nil then FCTCSSDropDown.ApplyStyle(StyleButton, T.Panel);
if FStepDropDown <> nil then FStepDropDown.ApplyStyle(StyleButton, T.Panel);
if BtnZoomIn <> nil then StyleButton(BtnZoomIn, False);
@@ -3234,6 +3270,15 @@ begin
for i := 0 to MAX_PANS - 1 do
if FPans[i] <> nil then
begin
FPans[i].View.SetTheme(T);
if FPans[i].PbSpectrum is TPaintBox then
TPaintBox(FPans[i].PbSpectrum).Color := T.BG;
if FPans[i].PbWaterfall is TPaintBox then
TPaintBox(FPans[i].PbWaterfall).Color := T.BG;
if FPans[i].Splitter <> nil then FPans[i].Splitter.Color := T.Border;
if FPans[i].BtnZoomIn <> nil then StyleButton(FPans[i].BtnZoomIn, False);
if FPans[i].BtnZoomDef <> nil then StyleButton(FPans[i].BtnZoomDef, False);
if FPans[i].BtnZoomOut <> nil then StyleButton(FPans[i].BtnZoomOut, False);
if FPans[i].BtnAddPan <> nil then StyleButton(FPans[i].BtnAddPan, False);
if FPans[i].BtnGrid <> nil then StyleButton(FPans[i].BtnGrid, False);
if FPans[i].BtnPopPan <> nil then StyleButton(FPans[i].BtnPopPan, False);
@@ -3250,6 +3295,8 @@ begin
if FPans[i].ZoomBar <> nil then FPans[i].ZoomBar.SetTheme(T);
if FPans[i].PbPanZoom <> nil then FPans[i].PbPanZoom.Color := T.SliderBG;
end;
// Тема инвалидирует кэши и GL-текстуры сама; историю водопада сохраняем.
MarkPanDisplayDirty(FPans[i], False);
end;
if FPanZoomBar <> nil then
begin
@@ -3275,9 +3322,9 @@ begin
// Ползунки
DS(TrkAGC); DS(TrkVolume); DS(TrkDrive);
DS(TrkAtt); DS(TrkRxGain); DS(TrkRawDev);
// Спектр
FSpecView.SetTheme(T);
// Wideband не входит в стек обычных панов.
if Assigned(FWidebandView) then FWidebandView.SetTheme(T);
// Флаги слайсов (оверлеи) — цвета кнопок из темы, как левая панель.
@@ -3325,11 +3372,17 @@ begin
end;
procedure TMainForm.SetLightTheme(V: Boolean);
var
T: TAppTheme;
begin
if FLightTheme = V then Exit;
FLightTheme := V;
FController.FLoadedGlobal.LightTheme := V; // зеркало в persist-буфер контроллера
ApplyDarkTheme;
T := CurrentAppTheme;
if FDeviceDialog <> nil then FDeviceDialog.SetTheme(T);
if FChannelsForm <> nil then TChannelsForm(FChannelsForm).ApplyTheme(T);
if FBeaconScopeForm <> nil then FBeaconScopeForm.ApplyTheme(T);
FController.FSettings.SaveTheme(V);
FController.FSettings.Save;
if (FSettingsForm <> nil) and TSettingsForm(FSettingsForm).Visible then
@@ -3348,7 +3401,6 @@ begin
else B.ClrBorder := T.BtnBorderNorm;
B.ClrText := T.BtnText;
B.ClrTextAct := T.BtnTextActive;
B.Font.Name := 'Courier New';
B.Font.Size := 8;
end;
@@ -3363,8 +3415,7 @@ begin
B.ClrBorder := T.SpanBorder;
B.ClrText := T.SpanText;
B.ClrTextAct := T.SpanText;
B.Font.Name := 'Courier New';
B.Font.Size := 7;
B.Font.Size := 8;
end;
procedure TMainForm.PositionSampleRateOverlay;
@@ -4568,11 +4619,15 @@ end;
procedure TMainForm.LayoutFilterButtons(PresetCount: Integer);
var
i, Total, Cols, Rows, RowOf, ColOf, InRow: Integer;
HeaderH, RowStep, BottomPad: Integer;
begin
Total := PresetCount + 2; // + VAR1/VAR2
if Total <= FILT_GRID_COLS then Cols := Total // FM/WFM: всё в один ряд
else Cols := FILT_GRID_COLS;
Rows := (Total + Cols - 1) div Cols;
HeaderH := PanelFilter.Scale96ToForm(20);
RowStep := PanelFilter.Scale96ToForm(27);
BottomPad := PanelFilter.Scale96ToForm(4);
for i := 0 to FILT_SLOTS - 1 do
begin
if i < PresetCount then InRow := i // пресет на своём месте
@@ -4583,12 +4638,12 @@ begin
ColOf := InRow mod Cols;
BtnFilter[i].Left := LeftPanelButtonLeft(PanelFilter.Width, Cols, ColOf);
BtnFilter[i].Width := LeftPanelButtonWidth(PanelFilter.Width, Cols, ColOf);
BtnFilter[i].Top := 16 + RowOf * 27;
BtnFilter[i].Top := HeaderH + RowOf * RowStep;
BtnFilter[i].Caption := FController.FilterSlot(FController.FMode, i).Name;
BtnFilter[i].Visible := True;
StyleButton(BtnFilter[i], i = FController.FFilter);
end;
PanelFilter.Height := 16 + Rows * 27 + 4;
PanelFilter.Height := HeaderH + Rows * RowStep + BottomPad;
end;
procedure TMainForm.UpdateFilterButtons;
@@ -4634,7 +4689,7 @@ begin
// Non-FM: restore full 2-row height and 5-column layout, hide FM panels.
// DMR reuses only the tuning STEP panel; SQL/CTCSS/repeater stay FM-only.
PanelFilter.Height := 74;
PanelFilter.Height := PanelFilter.Scale96ToForm(74);
if PanelFMSQ <> nil then PanelFMSQ.Visible := False;
if PanelFMCTCSS <> nil then PanelFMCTCSS.Visible := False;
if PanelFMStep <> nil then
@@ -4691,7 +4746,7 @@ begin
// Прочие режимы: смена режима возвращает заводской индекс фильтра (как было
// до таблицы), кромки и подписи приезжают из таблицы контроллера.
PanelFilter.Height := 74;
PanelFilter.Height := PanelFilter.Scale96ToForm(74);
DefIdx := FilterDefIdx(FController.FMode);
FController.SelectFilterSlotState(DefIdx);
LayoutFilterButtons(FILT_COUNT);
@@ -4740,7 +4795,7 @@ begin
begin
if FBeaconScopeForm = nil then
FBeaconScopeForm := TBeaconScopeForm.CreateWith(Self, FController);
FBeaconScopeForm.ApplyTheme(DarkTheme);
FBeaconScopeForm.ApplyTheme(CurrentAppTheme);
FBeaconScopeForm.Show;
end;
UpdateBeaconButton;
@@ -4755,7 +4810,7 @@ begin
if not FController.BeaconLockEnabled then Exit;
if FBeaconScopeForm = nil then
FBeaconScopeForm := TBeaconScopeForm.CreateWith(Self, FController);
FBeaconScopeForm.ApplyTheme(DarkTheme);
FBeaconScopeForm.ApplyTheme(CurrentAppTheme);
if FBeaconScopeForm.Visible then FBeaconScopeForm.Hide
else FBeaconScopeForm.Show;
end;
@@ -5712,7 +5767,7 @@ begin
Def.Power := 100;
Def.Name := '';
TChannelsForm(FChannelsForm).SetCurrentDefaults(Def);
TChannelsForm(FChannelsForm).ApplyTheme(DarkTheme);
TChannelsForm(FChannelsForm).ApplyTheme(CurrentAppTheme);
TChannelsForm(FChannelsForm).Show;
end;
@@ -8239,7 +8294,7 @@ end;
procedure TMainForm.RebuildXvtrButtons;
var
i, Pos, XvtrRows: Integer;
BtnH, RowH, MaxBottom: Integer;
BtnH, RowH, MaxBottom, RowGap, TopGap, BottomPad: Integer;
B: TFlatButton;
Cap: string;
begin
@@ -8264,7 +8319,10 @@ begin
BtnH := BtnBand[i].Height;
end;
if BtnH = 0 then BtnH := DpiScale(24);
RowH := BtnH + 3; // шаг ряда: высота кнопки + 3px зазор (как 27=24+3 при 1x)
RowGap := PanelBands.Scale96ToForm(3);
TopGap := PanelBands.Scale96ToForm(4);
BottomPad := PanelBands.Scale96ToForm(6);
RowH := BtnH + RowGap;
Pos := 0; // позиция среди enabled слотов
for i := 0 to CFG_XVTR_COUNT - 1 do
@@ -8277,7 +8335,7 @@ begin
B.Parent := PanelBands;
B.Caption := Cap;
B.Left := LeftPanelButtonLeft(PanelBands.Width, 6, Pos mod 6);
B.Top := MaxBottom + 4 + (Pos div 6) * RowH;
B.Top := MaxBottom + TopGap + (Pos div 6) * RowH;
B.Width := LeftPanelButtonWidth(PanelBands.Width, 6, Pos mod 6);
B.Height := BtnH;
B.OnClick := BtnXvtrBandClick;
@@ -8291,9 +8349,9 @@ begin
else if Pos <= 6 then XvtrRows := 1
else XvtrRows := 2;
if XvtrRows = 0 then
PanelBands.Height := MaxBottom + 6
PanelBands.Height := MaxBottom + BottomPad
else
PanelBands.Height := MaxBottom + 4 + XvtrRows * RowH + 6;
PanelBands.Height := MaxBottom + TopGap + XvtrRows * RowH + BottomPad;
RelayoutBelowBands;
end;