diff --git a/SettingsForm.pas b/SettingsForm.pas index 16b5b01..96efc89 100644 --- a/SettingsForm.pas +++ b/SettingsForm.pas @@ -244,6 +244,7 @@ type FAntXvtrTx: array[0..CFG_XVTR_COUNT-1, 0..1] of TFlatRadioButton; FAntXvtrRow: array[0..CFG_XVTR_COUNT-1] of TPanel; // строка слота (скрыта, если выкл.) FAntXvtrLbl: array[0..CFG_XVTR_COUNT-1] of TLabel; + FAntXvtrHdr: TLabel; // «Transverters» — виден при хотя бы одном включённом FAnt936x: TAD936xAnt; // Current Alex config state FAlexConfig: TAlexSettings; @@ -3001,12 +3002,14 @@ const TX3_X = PAD + 360; DNTX_X = PAD + 398; GRP_W = DNTX_X + 80; - // Таблица разъёмов AD936x (Pluto/LibreSDR) — та же сетка, свои колонки. - ANT_RX1_X = PAD + 90; - ANT_RX2_X = PAD + 116; - ANT_TX1_X = PAD + 160; - ANT_TX2_X = PAD + 186; - ANT_GRP_W = ANT_TX2_X + 60; + // Таблица разъёмов AD936x (Pluto/LibreSDR): диапазон | RX 1/2 | TX 1/2. + ANT_ROW_H = 26; + ANT_HDR_H = 34; // строка «RX / TX» + подстрока «1 2» под ней + ANT_RX1_X = PAD + 96; + ANT_RX2_X = ANT_RX1_X + 34; + ANT_TX1_X = ANT_RX2_X + 52; + ANT_TX2_X = ANT_TX1_X + 34; + ANT_GRP_W = ANT_TX2_X + 42; GRP_H = GRP_TITLE_H + HDR1_H + HDR2_H + BANDS * ROW_H + PAD; DATA_Y0 = GRP_TITLE_H + HDR1_H + HDR2_H + 4; TXGRP_H = GRP_TITLE_H + 4 * 28 + PAD; @@ -3202,52 +3205,56 @@ begin // показывается вместо них (SetAntennaBackend). FPlutoAntGrp := MakeGroupPanel(FPageAlex, 'Antenna Ports', MARGIN, 86, ANT_GRP_W, - GRP_TITLE_H + HDR2_H + (CFG_BAND_COUNT + CFG_XVTR_COUNT) * ROW_H + PAD); + GRP_TITLE_H + ANT_HDR_H + (CFG_BAND_COUNT + 1 + CFG_XVTR_COUNT) * ANT_ROW_H + PAD); FPlutoAntGrp.Visible := False; - MkAntHdr(FPlutoAntGrp, 'RX', ANT_RX1_X - 4, GRP_TITLE_H - 2); - MkAntHdr(FPlutoAntGrp, 'TX', ANT_TX1_X - 4, GRP_TITLE_H - 2); - MkAntHdr(FPlutoAntGrp, '1', ANT_RX1_X + 4, GRP_TITLE_H + 14); - MkAntHdr(FPlutoAntGrp, '2', ANT_RX2_X + 4, GRP_TITLE_H + 14); - MkAntHdr(FPlutoAntGrp, '1', ANT_TX1_X + 4, GRP_TITLE_H + 14); - MkAntHdr(FPlutoAntGrp, '2', ANT_TX2_X + 4, GRP_TITLE_H + 14); + // Шапка колонок: «RX»/«TX» над своей парой, под ними номера разъёмов. + Y := GRP_TITLE_H + 4; + MkAntHdr(FPlutoAntGrp, 'RX', (ANT_RX1_X + ANT_RX2_X) div 2 - 2, Y); + MkAntHdr(FPlutoAntGrp, 'TX', (ANT_TX1_X + ANT_TX2_X) div 2 - 2, Y); + MkAntHdr(FPlutoAntGrp, '1', ANT_RX1_X + 5, Y + 16); + MkAntHdr(FPlutoAntGrp, '2', ANT_RX2_X + 5, Y + 16); + MkAntHdr(FPlutoAntGrp, '1', ANT_TX1_X + 5, Y + 16); + MkAntHdr(FPlutoAntGrp, '2', ANT_TX2_X + 5, Y + 16); - Y := GRP_TITLE_H + HDR2_H + 4; + Y := GRP_TITLE_H + ANT_HDR_H; for b := 0 to CFG_BAND_COUNT - 1 do begin - // Пустой слот VU-плана (12-й у HF) не рисуем — строка остаётся пустой. - if BandName(b, True) <> '' then - begin - MkAntLbl(FPlutoAntGrp, BandName(b, True), BAND_X, Y + 2); - RxGrp := MkRbGroup(FPlutoAntGrp, ANT_RX1_X, Y, 60); - FAntRx[b, 0] := MkAntRb(RxGrp, 0); - FAntRx[b, 1] := MkAntRb(RxGrp, ANT_RX2_X - ANT_RX1_X); - TxGrp := MkRbGroup(FPlutoAntGrp, ANT_TX1_X, Y, 60); - FAntTx[b, 0] := MkAntRb(TxGrp, 0); - FAntTx[b, 1] := MkAntRb(TxGrp, ANT_TX2_X - ANT_TX1_X); - end; - Inc(Y, ROW_H); + if BandName(b, True) = '' then Continue; // пустой слот плана — не строка + MkAntLbl(FPlutoAntGrp, BandName(b, True), BAND_X, Y + 3); + RxGrp := MkRbGroup(FPlutoAntGrp, ANT_RX1_X, Y, ANT_RX2_X - ANT_RX1_X + 24); + FAntRx[b, 0] := MkAntRb(RxGrp, 0); + FAntRx[b, 1] := MkAntRb(RxGrp, ANT_RX2_X - ANT_RX1_X); + TxGrp := MkRbGroup(FPlutoAntGrp, ANT_TX1_X, Y, ANT_TX2_X - ANT_TX1_X + 24); + FAntTx[b, 0] := MkAntRb(TxGrp, 0); + FAntTx[b, 1] := MkAntRb(TxGrp, ANT_TX2_X - ANT_TX1_X); + Inc(Y, ANT_ROW_H); end; - // Слоты трансвертеров: строка на слот, показываем только включённые - // (LoadAnt936x подставит имя и видимость). + // Секция трансвертеров: заголовок + строка на слот. Видимость и вертикальную + // упаковку (только включённые слоты, без дыр) делает LoadAnt936x. + FAntXvtrHdr := MkAntLbl(FPlutoAntGrp, 'Transverters', BAND_X, Y + 6); + FAntXvtrHdr.Font.Color := CLR_TEXTDIM; + FAntXvtrHdr.Visible := False; + Inc(Y, ANT_ROW_H); + for b := 0 to CFG_XVTR_COUNT - 1 do begin FAntXvtrRow[b] := TPanel.Create(Self); FAntXvtrRow[b].Parent := FPlutoAntGrp; - FAntXvtrRow[b].SetBounds(0, Y, ANT_GRP_W, ROW_H); + FAntXvtrRow[b].SetBounds(0, Y, ANT_GRP_W, ANT_ROW_H); FAntXvtrRow[b].BevelOuter := bvNone; FAntXvtrRow[b].Color := CLR_PANEL; FAntXvtrRow[b].Caption := ''; FAntXvtrRow[b].Visible := False; - FAntXvtrLbl[b] := MkAntLbl(FAntXvtrRow[b], '', BAND_X, 2); - RxGrp := MkRbGroup(FAntXvtrRow[b], ANT_RX1_X, 0, 60); + FAntXvtrLbl[b] := MkAntLbl(FAntXvtrRow[b], '', BAND_X, 3); + RxGrp := MkRbGroup(FAntXvtrRow[b], ANT_RX1_X, 0, ANT_RX2_X - ANT_RX1_X + 24); FAntXvtrRx[b, 0] := MkAntRb(RxGrp, 0); FAntXvtrRx[b, 1] := MkAntRb(RxGrp, ANT_RX2_X - ANT_RX1_X); - TxGrp := MkRbGroup(FAntXvtrRow[b], ANT_TX1_X, 0, 60); + TxGrp := MkRbGroup(FAntXvtrRow[b], ANT_TX1_X, 0, ANT_TX2_X - ANT_TX1_X + 24); FAntXvtrTx[b, 0] := MkAntRb(TxGrp, 0); FAntXvtrTx[b, 1] := MkAntRb(TxGrp, ANT_TX2_X - ANT_TX1_X); - Inc(Y, ROW_H); + Inc(Y, ANT_ROW_H); end; finally FLoading := False; @@ -3281,8 +3288,14 @@ begin end; procedure TSettingsForm.LoadAnt936x(const A: TAD936xAnt; const X: TXvtrSettings); -// Таблица разъёмов + строки трансвертеров (видимы только включённые слоты). -var b: Integer; +// Таблица разъёмов + секция трансвертеров. Строки выключенных слотов не просто +// прячутся, а исключаются из раскладки (иначе между диапазонами и QO-100 зияла +// дыра в 8 строк); высота группы считается по фактическому числу строк. +const + ANT_ROW_H = 26; + PAD = 12; +var + b, Y, NVis, Bands: Integer; begin FLoading := True; try @@ -3295,10 +3308,16 @@ begin FAntTx[b, 0].Checked := A.TxAnt[b] = 0; FAntTx[b, 1].Checked := A.TxAnt[b] = 1; end; + + // Первая строка трансвертеров — сразу под заголовком секции. + if FAntXvtrHdr <> nil then Y := FAntXvtrHdr.Top + ANT_ROW_H - 6 + else Y := 0; + NVis := 0; for b := 0 to CFG_XVTR_COUNT - 1 do begin if FAntXvtrRow[b] = nil then Continue; FAntXvtrRow[b].Visible := X.Entries[b].Enabled; + if not X.Entries[b].Enabled then Continue; if X.Entries[b].ButtonText <> '' then FAntXvtrLbl[b].Caption := string(X.Entries[b].ButtonText) else @@ -3307,6 +3326,24 @@ begin FAntXvtrRx[b, 1].Checked := A.XvtrRxAnt[b] = 1; FAntXvtrTx[b, 0].Checked := A.XvtrTxAnt[b] = 0; FAntXvtrTx[b, 1].Checked := A.XvtrTxAnt[b] = 1; + FAntXvtrRow[b].Top := Y; // упаковка подряд, без дыр от выключенных слотов + Inc(Y, ANT_ROW_H); + Inc(NVis); + end; + if FAntXvtrHdr <> nil then FAntXvtrHdr.Visible := NVis > 0; + + // Высота группы — по последней видимой строке (иначе внизу пустое поле). + if FPlutoAntGrp <> nil then + begin + if NVis = 0 then + begin + Bands := 0; + for b := 0 to CFG_BAND_COUNT - 1 do + if FAntRx[b, 0] <> nil then Inc(Bands); + Y := FPlutoAntGrp.Height - PAD; // fallback, если заголовка нет + if (FAntXvtrHdr <> nil) and (Bands > 0) then Y := FAntXvtrHdr.Top - 6; + end; + FPlutoAntGrp.Height := Y + PAD; end; finally FLoading := False;