diff --git a/MainForm.pas b/MainForm.pas index 348b28e..0037c7e 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -150,6 +150,7 @@ type FVfoOverlay: TVfoOverlay; // накладка SmartSDR-стиль на спектре FSampleRateOverlay: TSampleRateOverlay; // оверлей span/hide слева вверху спектра FPanelHidden: Boolean; // True = левая панель скрыта + FLeftPanelW: Integer; // ширина панели до скрытия (DPI-safe restore) FPendingBoardType: Integer; // BoardType устройства для подключения // ---- DSP + Audio ---- @@ -373,7 +374,7 @@ type BtnFMStepSel: TFlatButton; FStepDropDown: TFlatDropDown; - PanelRX: TPanel; + PanelAGC: TPanel; BtnAGCMode: array[0..4] of TFlatButton; // FAST MED SLOW LONG OFF LblAGCTop: TLabel; // показывает значение уровня TrkAGC: TFlatSlider; @@ -393,6 +394,8 @@ type BtnMOX: TFlatButton; BtnTUN: TFlatButton; + PanelRXBlock: TPanel; + // ---- Right panel ---- PanelRight: TPanel; PbSpectrum: TControl; @@ -1645,7 +1648,7 @@ begin // TX controls PanelTX := TPanel.Create(Self); PanelTX.Parent := PanelLeft; - PanelTX.SetBounds(0, Y, LEFT_W, 72); + PanelTX.SetBounds(0, Y, LEFT_W, 96); PanelTX.BevelOuter := bvNone; MakeLbl(PanelTX, 'TX', 4, 2); @@ -1656,18 +1659,118 @@ begin LeftPanelButtonLeft(LEFT_W, 4, 1), 16, LeftPanelButtonWidth(LEFT_W, 4, 1), BTN_SM, BtnTUNClick); + BtnDUP := MakeBtn(PanelTX, 'DUP', + LeftPanelButtonLeft(LEFT_W, 4, 0), 44, + LeftPanelButtonWidth(LEFT_W, 4, 0), BTN_SM, BtnDUPClick); + BtnDUP.Tag := 0; + StyleButton(BtnDUP, FDisplayDuplex); + LblDrv := TLabel.Create(Self); - LblDrv.Parent := PanelTX; LblDrv.Left := 4; LblDrv.Top := 53; + 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; TrkDrive := TFlatSlider.Create(Self); - TrkDrive.Parent := PanelTX; TrkDrive.Left := 34; TrkDrive.Top := 50; + TrkDrive.Parent := PanelTX; TrkDrive.Left := 34; TrkDrive.Top := 74; TrkDrive.Width := 150; TrkDrive.Height := 16; TrkDrive.Min := 0; TrkDrive.Max := 100; TrkDrive.Position := 50; TrkDrive.OnChange := TrkDriveChange; - Inc(Y, 76); + Inc(Y, 100); + + // RX block: CTUN + VOL + NR/NB/SNB/ANF/MUTE + PanelRXBlock := TPanel.Create(Self); + PanelRXBlock.Parent := PanelLeft; + PanelRXBlock.SetBounds(0, Y, LEFT_W, 96); + PanelRXBlock.BevelOuter := bvNone; + MakeLbl(PanelRXBlock, 'RX', 4, 2); + + BtnCTun := MakeBtn(PanelRXBlock, 'CTUN', + LeftPanelButtonLeft(LEFT_W, 3, 0), 16, + LeftPanelButtonWidth(LEFT_W, 3, 0), + BTN_H, BtnCTunClick); + BtnCTun.Tag := 0; + StyleButton(BtnCTun, FCTun); + + MakeLbl(PanelRXBlock, 'VOL', 4, 50); + TrkVolume := TFlatSlider.Create(Self); + TrkVolume.Parent := PanelRXBlock; TrkVolume.Left := 34; TrkVolume.Top := 46; + TrkVolume.Width := LEFT_W - 38; TrkVolume.Height := 16; + TrkVolume.Min := 0; TrkVolume.Max := 100; + TrkVolume.Position := FVolume; + TrkVolume.OnChange := TrkVolumeChange; + + BtnNR := MakeBtn(PanelRXBlock, 'NR', + LeftPanelButtonLeft(LEFT_W, 5, 0), 70, + LeftPanelButtonWidth(LEFT_W, 5, 0), BTN_SM, BtnNRClick); + BtnNB := MakeBtn(PanelRXBlock, 'NB', + LeftPanelButtonLeft(LEFT_W, 5, 1), 70, + LeftPanelButtonWidth(LEFT_W, 5, 1), BTN_SM, BtnNBClick); + BtnSNB := MakeBtn(PanelRXBlock, 'SNB', + LeftPanelButtonLeft(LEFT_W, 5, 2), 70, + LeftPanelButtonWidth(LEFT_W, 5, 2), BTN_SM, BtnSNBClick); + BtnANF := MakeBtn(PanelRXBlock, 'ANF', + LeftPanelButtonLeft(LEFT_W, 5, 3), 70, + LeftPanelButtonWidth(LEFT_W, 5, 3), BTN_SM, BtnANFClick); + BtnMute := MakeBtn(PanelRXBlock, 'MUTE', + LeftPanelButtonLeft(LEFT_W, 5, 4), 70, + LeftPanelButtonWidth(LEFT_W, 5, 4), BTN_SM, BtnMuteClick); + + Inc(Y, 100); + + // AGC controls + PanelAGC := TPanel.Create(Self); + PanelAGC.Parent := PanelLeft; + PanelAGC.SetBounds(0, Y, LEFT_W, 70); + PanelAGC.BevelOuter := bvNone; + + // AGC mode — 5 кнопок в ряд + MakeLbl(PanelAGC, 'AGC', 4, 2); + BtnAGCMode[0] := MakeBtn(PanelAGC, 'FAST', + LeftPanelButtonLeft(LEFT_W, 5, 0), 16, + LeftPanelButtonWidth(LEFT_W, 5, 0), + BTN_SM, BtnAGCModeClick); + BtnAGCMode[0].Tag := 0; + BtnAGCMode[1] := MakeBtn(PanelAGC, 'MED', + LeftPanelButtonLeft(LEFT_W, 5, 1), 16, + LeftPanelButtonWidth(LEFT_W, 5, 1), + BTN_SM, BtnAGCModeClick); + BtnAGCMode[1].Tag := 1; + BtnAGCMode[2] := MakeBtn(PanelAGC, 'SLOW', + LeftPanelButtonLeft(LEFT_W, 5, 2), 16, + LeftPanelButtonWidth(LEFT_W, 5, 2), + BTN_SM, BtnAGCModeClick); + BtnAGCMode[2].Tag := 2; + BtnAGCMode[3] := MakeBtn(PanelAGC, 'LONG', + LeftPanelButtonLeft(LEFT_W, 5, 3), 16, + LeftPanelButtonWidth(LEFT_W, 5, 3), + BTN_SM, BtnAGCModeClick); + BtnAGCMode[3].Tag := 3; + BtnAGCMode[4] := MakeBtn(PanelAGC, 'OFF', + LeftPanelButtonLeft(LEFT_W, 5, 4), 16, + LeftPanelButtonWidth(LEFT_W, 5, 4), + BTN_SM, BtnAGCModeClick); + BtnAGCMode[4].Tag := 4; + for i := 0 to 4 do StyleButton(BtnAGCMode[i], i = FAGCMode); + + // AGC level slider + MakeLbl(PanelAGC, 'THRESH', 4, 44); + TrkAGC := TFlatSlider.Create(Self); + TrkAGC.Parent := PanelAGC; TrkAGC.Left := 56; TrkAGC.Top := 40; + TrkAGC.Width := LEFT_W - 96; TrkAGC.Height := 16; + TrkAGC.Min := 20; TrkAGC.Max := 120; // 20..120 → −20..-120 dBm + TrkAGC.Position := FAGCTop; + TrkAGC.Reversed := True; + TrkAGC.OnChange := TrkAGCChange; + + LblAGCTop := TLabel.Create(Self); + LblAGCTop.Parent := PanelAGC; + LblAGCTop.Left := LEFT_W - 38; LblAGCTop.Top := 44; + LblAGCTop.Caption := Format('-%ddB', [FAGCTop]); + LblAGCTop.Font.Color := CLR_TEXT; LblAGCTop.Font.Name := 'Courier New'; + LblAGCTop.Font.Size := 7; + + Inc(Y, 74); // Band selector. Высота резервирует 2 дополнительных ряда под XVTR-кнопки // (создаются динамически в RebuildXvtrButtons). В каждом ряду до 6 кнопок, @@ -1738,18 +1841,18 @@ begin PanelFMSQ.SetBounds(0, Y, LEFT_W, 50); PanelFMSQ.BevelOuter := bvNone; PanelFMSQ.Visible := False; - MakeLbl(PanelFMSQ, 'SQL', 4, 4); + MakeLbl(PanelFMSQ, 'SQL', 4, 2); W := LeftPanelButtonWidth(LEFT_W, 4, 0); BtnFMSQ := MakeBtn(PanelFMSQ, 'SQL', - LeftPanelButtonLeft(LEFT_W, 4, 0), 20, + LeftPanelButtonLeft(LEFT_W, 4, 0), 16, W, BTN_SM, BtnFMSQClick); StyleButton(BtnFMSQ, False); - // Slider: vertically centred with button text (button top=20, h=24 → center=32) + // Slider: vertically centred with button text (button top=16, h=24 → center=28) // 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 := 25; // 32 - 14/2 = 25 + TrkFMSQ.Top := 21; // 28 - 14/2 = 21 TrkFMSQ.Width := LEFT_W - TrkFMSQ.Left - 30 - 4; // leave 30px for label + margins TrkFMSQ.Height := 14; TrkFMSQ.Min := 0; TrkFMSQ.Max := 100; @@ -1759,7 +1862,7 @@ begin LblFMSQ := TLabel.Create(Self); LblFMSQ.Parent := PanelFMSQ; LblFMSQ.Left := TrkFMSQ.Left + TrkFMSQ.Width + 3; - LblFMSQ.Top := 25; + LblFMSQ.Top := 21; LblFMSQ.Width := 26; LblFMSQ.Caption := IntToStr(FFMSQLevel); LblFMSQ.Font.Color := CLR_TEXT; @@ -1772,14 +1875,14 @@ begin PanelFMCTCSS.SetBounds(0, Y, LEFT_W, 50); PanelFMCTCSS.BevelOuter := bvNone; PanelFMCTCSS.Visible := False; - MakeLbl(PanelFMCTCSS, 'CTCSS', 4, 4); + MakeLbl(PanelFMCTCSS, 'CTCSS', 4, 2); BtnFMCTCSS := MakeBtn(PanelFMCTCSS, 'CTCSS', - LeftPanelButtonLeft(LEFT_W, 3, 0), 20, + LeftPanelButtonLeft(LEFT_W, 3, 0), 16, LeftPanelButtonWidth(LEFT_W, 3, 0), BTN_H, BtnFMCTCSSClick); StyleButton(BtnFMCTCSS, False); BtnFMCTCSSTone := MakeBtn(PanelFMCTCSS, CTCSS_NAMES[0], - LeftPanelButtonLeft(LEFT_W, 3, 1), 20, + LeftPanelButtonLeft(LEFT_W, 3, 1), 16, LEFT_W - LEFT_PANEL_BTN_PAD - LeftPanelButtonLeft(LEFT_W, 3, 1), BTN_H, BtnFMCTCSSToneClick); @@ -1796,14 +1899,14 @@ begin PanelFMStep.SetBounds(0, Y, LEFT_W, 50); PanelFMStep.BevelOuter := bvNone; PanelFMStep.Visible := False; - MakeLbl(PanelFMStep, 'STEP', 4, 4); + MakeLbl(PanelFMStep, 'STEP', 4, 2); BtnFMStep := MakeBtn(PanelFMStep, 'STEP', - LeftPanelButtonLeft(LEFT_W, 3, 0), 20, + LeftPanelButtonLeft(LEFT_W, 3, 0), 16, LeftPanelButtonWidth(LEFT_W, 3, 0), BTN_H, BtnFMStepClick); StyleButton(BtnFMStep, FFMStepOn); BtnFMStepSel := MakeBtn(PanelFMStep, FM_STEP_NAMES[FFMStepIdx], - LeftPanelButtonLeft(LEFT_W, 3, 1), 20, + LeftPanelButtonLeft(LEFT_W, 3, 1), 16, LEFT_W - LEFT_PANEL_BTN_PAD - LeftPanelButtonLeft(LEFT_W, 3, 1), BTN_H, BtnFMStepSelClick); @@ -1814,103 +1917,6 @@ begin FStepDropDown.SetItemIndex(FFMStepIdx); FStepDropDown.OnSelect := OnStepDropDownSelect; - // CTUN / DUP buttons (display-related) - BtnCTun := MakeBtn(PanelLeft, 'CTUN', - LeftPanelButtonLeft(LEFT_W, 3, 0), Y, - LeftPanelButtonWidth(LEFT_W, 3, 0), - BTN_H, BtnCTunClick); - BtnCTun.Tag := 0; - StyleButton(BtnCTun, FCTun); - - BtnDUP := MakeBtn(PanelLeft, 'DUP', - LeftPanelButtonLeft(LEFT_W, 3, 1), Y, - LeftPanelButtonWidth(LEFT_W, 3, 1), - BTN_H, BtnDUPClick); - BtnDUP.Tag := 0; - StyleButton(BtnDUP, FDisplayDuplex); - - Inc(Y, BTN_H + 4); - - // RX controls - PanelRX := TPanel.Create(Self); - PanelRX.Parent := PanelLeft; - PanelRX.SetBounds(0, Y, LEFT_W, 122); - PanelRX.BevelOuter := bvNone; - - // AGC mode — 5 кнопок в ряд - MakeLbl(PanelRX, 'AGC', 4, 4); - BtnAGCMode[0] := MakeBtn(PanelRX, 'FAST', - LeftPanelButtonLeft(LEFT_W, 5, 0), 22, - LeftPanelButtonWidth(LEFT_W, 5, 0), - BTN_SM, BtnAGCModeClick); - BtnAGCMode[0].Tag := 0; - BtnAGCMode[1] := MakeBtn(PanelRX, 'MED', - LeftPanelButtonLeft(LEFT_W, 5, 1), 22, - LeftPanelButtonWidth(LEFT_W, 5, 1), - BTN_SM, BtnAGCModeClick); - BtnAGCMode[1].Tag := 1; - BtnAGCMode[2] := MakeBtn(PanelRX, 'SLOW', - LeftPanelButtonLeft(LEFT_W, 5, 2), 22, - LeftPanelButtonWidth(LEFT_W, 5, 2), - BTN_SM, BtnAGCModeClick); - BtnAGCMode[2].Tag := 2; - BtnAGCMode[3] := MakeBtn(PanelRX, 'LONG', - LeftPanelButtonLeft(LEFT_W, 5, 3), 22, - LeftPanelButtonWidth(LEFT_W, 5, 3), - BTN_SM, BtnAGCModeClick); - BtnAGCMode[3].Tag := 3; - BtnAGCMode[4] := MakeBtn(PanelRX, 'OFF', - LeftPanelButtonLeft(LEFT_W, 5, 4), 22, - LeftPanelButtonWidth(LEFT_W, 5, 4), - BTN_SM, BtnAGCModeClick); - BtnAGCMode[4].Tag := 4; - for i := 0 to 4 do StyleButton(BtnAGCMode[i], i = FAGCMode); - - // AGC level slider - MakeLbl(PanelRX, 'THRESH', 4, 50); - TrkAGC := TFlatSlider.Create(Self); - TrkAGC.Parent := PanelRX; TrkAGC.Left := 56; TrkAGC.Top := 46; - TrkAGC.Width := LEFT_W - 96; TrkAGC.Height := 16; - TrkAGC.Min := 20; TrkAGC.Max := 120; // 20..120 → −20..-120 dBm - TrkAGC.Position := FAGCTop; - TrkAGC.Reversed := True; - TrkAGC.OnChange := TrkAGCChange; - - LblAGCTop := TLabel.Create(Self); - LblAGCTop.Parent := PanelRX; - LblAGCTop.Left := LEFT_W - 38; LblAGCTop.Top := 50; - LblAGCTop.Caption := Format('-%ddB', [FAGCTop]); - LblAGCTop.Font.Color := CLR_TEXT; LblAGCTop.Font.Name := 'Courier New'; - LblAGCTop.Font.Size := 7; - - // VOL - MakeLbl(PanelRX, 'VOL', 4, 74); - TrkVolume := TFlatSlider.Create(Self); - TrkVolume.Parent := PanelRX; TrkVolume.Left := 34; TrkVolume.Top := 70; - TrkVolume.Width := LEFT_W - 38; TrkVolume.Height := 16; - TrkVolume.Min := 0; TrkVolume.Max := 100; - TrkVolume.Position := FVolume; - TrkVolume.OnChange := TrkVolumeChange; - - // NR NB SNB ANF MUTE - BtnNR := MakeBtn(PanelRX, 'NR', - LeftPanelButtonLeft(LEFT_W, 5, 0), 96, - LeftPanelButtonWidth(LEFT_W, 5, 0), BTN_SM, BtnNRClick); - BtnNB := MakeBtn(PanelRX, 'NB', - LeftPanelButtonLeft(LEFT_W, 5, 1), 96, - LeftPanelButtonWidth(LEFT_W, 5, 1), BTN_SM, BtnNBClick); - BtnSNB := MakeBtn(PanelRX, 'SNB', - LeftPanelButtonLeft(LEFT_W, 5, 2), 96, - LeftPanelButtonWidth(LEFT_W, 5, 2), BTN_SM, BtnSNBClick); - BtnANF := MakeBtn(PanelRX, 'ANF', - LeftPanelButtonLeft(LEFT_W, 5, 3), 96, - LeftPanelButtonWidth(LEFT_W, 5, 3), BTN_SM, BtnANFClick); - BtnMute := MakeBtn(PanelRX, 'MUTE', - LeftPanelButtonLeft(LEFT_W, 5, 4), 96, - LeftPanelButtonWidth(LEFT_W, 5, 4), BTN_SM, BtnMuteClick); - - Inc(Y, 126); - // ---- Right panel ---- PanelRight := TPanel.Create(Self); PanelRight.Parent := Self; @@ -2495,7 +2501,7 @@ begin if PanelFMSQ <> nil then DP(PanelFMSQ); if PanelFMCTCSS <> nil then DP(PanelFMCTCSS); if PanelFMStep <> nil then DP(PanelFMStep); - DP(PanelRX); DP(PanelTX); + DP(PanelRXBlock); DP(PanelAGC); DP(PanelTX); DP(PanelRight); if PbSpectrum is TPaintBox then @@ -5519,6 +5525,7 @@ begin FPanelHidden := not FPanelHidden; if FPanelHidden then begin + FLeftPanelW := PanelLeft.Width; // сохраняем реальную ширину (учитывает DPI на Win32) PanelLeft.Width := 0; FVfoOverlay.Width := 260; FVfoOverlay.Height := 136; // OVL_H_NORM — расширяется сам при открытии AGC-пикера @@ -5529,7 +5536,7 @@ begin end else begin - PanelLeft.Width := 232; + PanelLeft.Width := FLeftPanelW; // восстанавливаем сохранённую ширину FVfoOverlay.HandleMouseLeave; FVfoOverlay.Visible := False; end; @@ -6520,8 +6527,6 @@ begin begin PanelFMCTCSS.Top := Y; Y := Y + PanelFMCTCSS.Height + 2; end; - BtnCTun.Top := Y; BtnDUP.Top := Y; Y := Y + BtnCTun.Height + 4; - PanelRX.Top := Y; end; procedure TMainForm.RebuildXvtrButtons;