From 0396eeed49b9cd525a9f2f63227e4ef48a45f2ab Mon Sep 17 00:00:00 2001 From: Vladimir Date: Wed, 5 Aug 2026 14:50:15 +0300 Subject: [PATCH] ui(channels): redesign editor and fix DPI scaling --- ChannelsForm.pas | 339 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 247 insertions(+), 92 deletions(-) diff --git a/ChannelsForm.pas b/ChannelsForm.pas index 5d84547..7368c5c 100644 --- a/ChannelsForm.pas +++ b/ChannelsForm.pas @@ -14,7 +14,7 @@ uses Forms, Controls, Graphics, StdCtrls, ExtCtrls, FlatButton, FlatCheckBox, FlatComboBox, FlatEdit, FlatSpinEdit, FlatFloatSpinEdit, FlatListBox, - AppTheme, ChannelStore, RadioModes; + AppTheme, ChannelStore, RadioModes, DpiUtils; const // Копии из MainForm: нужны для выпадающих списков @@ -39,10 +39,19 @@ type FBtnDelete: TFlatButton; FBtnUp: TFlatButton; FBtnDown: TFlatButton; + FBtnClose: TFlatButton; FList: TFlatListBox; // --- Правая панель (поля редактирования) --- FPanelRight: TPanel; + FFooterPanel: TPanel; + FCardIdentity: TPanel; + FCardRadio: TPanel; + FCardRepeater: TPanel; + FLeftTitle: TLabel; + FLeftHint: TLabel; + FRightTitle: TLabel; + FRightHint: TLabel; // Labels (для перекраски темой) FLbls: array of TLabel; @@ -66,11 +75,13 @@ type FUpdating: Boolean; FOnChanged: TNotifyEvent; FCurrentDefaults: TChannel; // значения по умолчанию для новых каналов + FTheme: TAppTheme; procedure BuildUI; procedure StyleBtn(B: TFlatButton; AActive: Boolean = False); function MakeLabel(AParent: TWinControl; const Cap: string; X, Y, W, H: Integer): TLabel; + function MakeGroupPanel(const Cap: string; Y, H: Integer): TPanel; procedure LoadChannelToFields(Idx: Integer); procedure SaveFieldsToChannel; procedure RefreshList(KeepIdx: Integer = -1); @@ -90,6 +101,7 @@ type procedure OnCTCSSChkChange(Sender: TObject); procedure OnCTCSSCmbChange(Sender: TObject); // Handlers — форма + procedure OnCloseClick(Sender: TObject); procedure OnFormClose(Sender: TObject; var CloseAction: TCloseAction); public constructor Create(AOwner: TComponent; AStore: TChannelStore; @@ -103,31 +115,54 @@ implementation const // Геометрия - LPANEL_W = 185; // ширина левой панели - TOOLBAR_H = 32; // высота тулбара с кнопками Add/Del/Up/Down - BTN_H = 24; + LPANEL_W = 240; + TOOLBAR_Y = 66; + TOOLBAR_H = 30; + BTN_H = 26; + FORM_W = 820; + FORM_H = 540; + PAGE_MARGIN = 18; // Правая панель - LBL_X = 8; - LBL_W = 95; - CTRL_X = 106; - ROW_H = 30; // высота строки - CTRL_H = 24; // высота контрола + LBL_X = 14; + LBL_W = 106; + CTRL_X = 126; + ROW_H = 28; + CTRL_H = 24; constructor TChannelsForm.Create(AOwner: TComponent; AStore: TChannelStore; AOnChanged: TNotifyEvent); +var + WorkArea: TRect; + MaxW, MaxH: Integer; begin inherited CreateNew(AOwner); FStore := AStore; FOnChanged := AOnChanged; FUpdating := False; + FTheme := DarkTheme; TChannelStore.DefaultChannel(FCurrentDefaults); + Scaled := False; Caption := 'Channels'; BorderStyle := bsSizeable; - Width := 720; - Height := 480; - Position := poScreenCenter; + if AOwner is TCustomForm then + begin + WorkArea := TCustomForm(AOwner).BoundsRect; + WorkArea := Screen.MonitorFromRect(WorkArea).WorkareaRect; + Position := poOwnerFormCenter; + end + else + begin + WorkArea := Screen.PrimaryMonitor.WorkareaRect; + Position := poScreenCenter; + end; + MaxW := WorkArea.Right - WorkArea.Left - DpiScale(48); + MaxH := WorkArea.Bottom - WorkArea.Top - DpiScale(48); + Width := Min(DpiScale(FORM_W), MaxW); + Height := Min(DpiScale(FORM_H), MaxH); + Constraints.MinWidth := Min(DpiScale(680), Width); + Constraints.MinHeight := Min(DpiScale(530), Height); KeyPreview := True; OnClose := @OnFormClose; @@ -138,46 +173,72 @@ end; procedure TChannelsForm.BuildUI; var - i: Integer; - BtnW: Integer; - RW: Integer; // ширина правой панели - Y: Integer; + i, BtnW, CardW, Y: Integer; + L: TLabel; + + procedure PlaceRightUnit(AParent: TWinControl; const Cap: string; + ATop: Integer); + begin + L := MakeLabel(AParent, Cap, 0, ATop + 1, 42, CTRL_H); + L.SetBounds(AParent.ClientWidth - DpiScale(50), DpiScale(ATop + 1), + DpiScale(42), DpiScale(CTRL_H)); + L.Anchors := [akTop, akRight]; + end; + begin + SetLength(FLbls, 0); + // ----- Левая панель ----- FPanelLeft := TPanel.Create(Self); FPanelLeft.Parent := Self; FPanelLeft.Align := alLeft; - FPanelLeft.Width := LPANEL_W; + FPanelLeft.Width := DpiScale(LPANEL_W); FPanelLeft.BevelOuter := bvNone; - BtnW := (LPANEL_W - 4 - 3 * 2) div 4; // 4 кнопки с зазорами + FLeftTitle := MakeLabel(FPanelLeft, 'CHANNEL MEMORY', + 14, 12, LPANEL_W - 28, 24); + FLeftTitle.Font.Size := 9; + FLeftTitle.Font.Style := [fsBold]; + FLeftTitle.Font.Color := FTheme.Text; + + FLeftHint := MakeLabel(FPanelLeft, 'Saved frequencies and modes', + 14, 37, LPANEL_W - 28, 18); + FLeftHint.Font.Size := 8; + + BtnW := (DpiScale(LPANEL_W - 24) - 3 * DpiScale(6)) div 4; FBtnAdd := TFlatButton.Create(Self); FBtnAdd.Parent := FPanelLeft; - FBtnAdd.SetBounds(2, 4, BtnW, BTN_H); + FBtnAdd.SetBounds(DpiScale(12), DpiScale(TOOLBAR_Y), + BtnW, DpiScale(BTN_H)); FBtnAdd.Caption := 'ADD'; FBtnAdd.OnClick := @OnAddClick; FBtnDelete := TFlatButton.Create(Self); FBtnDelete.Parent := FPanelLeft; - FBtnDelete.SetBounds(2 + (BtnW + 2), 4, BtnW, BTN_H); + FBtnDelete.SetBounds(FBtnAdd.Left + BtnW + DpiScale(6), + FBtnAdd.Top, BtnW, FBtnAdd.Height); FBtnDelete.Caption := 'DEL'; FBtnDelete.OnClick := @OnDeleteClick; FBtnUp := TFlatButton.Create(Self); FBtnUp.Parent := FPanelLeft; - FBtnUp.SetBounds(2 + 2 * (BtnW + 2), 4, BtnW, BTN_H); + FBtnUp.SetBounds(FBtnDelete.Left + BtnW + DpiScale(6), + FBtnAdd.Top, BtnW, FBtnAdd.Height); FBtnUp.Caption := '↑'; FBtnUp.OnClick := @OnUpClick; FBtnDown := TFlatButton.Create(Self); FBtnDown.Parent := FPanelLeft; - FBtnDown.SetBounds(2 + 3 * (BtnW + 2), 4, BtnW, BTN_H); + FBtnDown.SetBounds(FBtnUp.Left + BtnW + DpiScale(6), + FBtnAdd.Top, BtnW, FBtnAdd.Height); FBtnDown.Caption := '↓'; FBtnDown.OnClick := @OnDownClick; FList := TFlatListBox.Create(Self); FList.Parent := FPanelLeft; - FList.SetBounds(0, TOOLBAR_H, LPANEL_W, FPanelLeft.Height - TOOLBAR_H); + FList.SetBounds(DpiScale(12), DpiScale(TOOLBAR_Y + TOOLBAR_H + 10), + FPanelLeft.ClientWidth - DpiScale(24), + FPanelLeft.ClientHeight - DpiScale(TOOLBAR_Y + TOOLBAR_H + 22)); FList.Anchors := [akLeft, akTop, akRight, akBottom]; FList.OnClick := @OnListClick; FList.OnDblClick := @OnListDblClick; @@ -188,34 +249,62 @@ begin FPanelRight.Align := alClient; FPanelRight.BevelOuter := bvNone; - SetLength(FLbls, 0); - RW := Width - LPANEL_W; + FFooterPanel := TPanel.Create(Self); + FFooterPanel.Parent := FPanelRight; + FFooterPanel.Align := alBottom; + FFooterPanel.Height := DpiScale(50); + FFooterPanel.BevelOuter := bvNone; - Y := 8; + FBtnClose := TFlatButton.Create(Self); + FBtnClose.Parent := FFooterPanel; + FBtnClose.Caption := 'Close'; + FBtnClose.SetBounds(FFooterPanel.ClientWidth - DpiScale(110), + DpiScale(10), DpiScale(92), DpiScale(30)); + FBtnClose.Anchors := [akTop, akRight]; + FBtnClose.OnClick := @OnCloseClick; - // Group - MakeLabel(FPanelRight, 'Group', LBL_X, Y + 1, LBL_W, CTRL_H); + FRightTitle := MakeLabel(FPanelRight, 'CHANNEL DETAILS', + PAGE_MARGIN, 10, 420, 22); + FRightTitle.Font.Size := 9; + FRightTitle.Font.Style := [fsBold]; + FRightTitle.Font.Color := FTheme.Text; + FRightTitle.Anchors := [akLeft, akTop, akRight]; + + FRightHint := MakeLabel(FPanelRight, + 'Changes are saved automatically', PAGE_MARGIN, 31, 420, 18); + FRightHint.Font.Size := 8; + FRightHint.Anchors := [akLeft, akTop, akRight]; + + FCardIdentity := MakeGroupPanel('IDENTITY', 56, 90); + CardW := FCardIdentity.ClientWidth; + Y := 34; + + MakeLabel(FCardIdentity, 'Group', LBL_X, Y + 1, LBL_W, CTRL_H); FEdGroup := TFlatEdit.Create(Self); - FEdGroup.Parent := FPanelRight; - FEdGroup.SetBounds(CTRL_X, Y, RW - CTRL_X - 8, CTRL_H); + FEdGroup.Parent := FCardIdentity; + FEdGroup.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + CardW - DpiScale(CTRL_X + 14), DpiScale(CTRL_H)); FEdGroup.Anchors := [akLeft, akTop, akRight]; FEdGroup.OnChange := @OnFieldChange; Inc(Y, ROW_H); - // Name - MakeLabel(FPanelRight, 'Name', LBL_X, Y + 1, LBL_W, CTRL_H); + MakeLabel(FCardIdentity, 'Name', LBL_X, Y + 1, LBL_W, CTRL_H); FEdName := TFlatEdit.Create(Self); - FEdName.Parent := FPanelRight; - FEdName.SetBounds(CTRL_X, Y, RW - CTRL_X - 8, CTRL_H); + FEdName.Parent := FCardIdentity; + FEdName.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + CardW - DpiScale(CTRL_X + 14), DpiScale(CTRL_H)); FEdName.Anchors := [akLeft, akTop, akRight]; FEdName.OnChange := @OnFieldChange; - Inc(Y, ROW_H); - // RX Freq - MakeLabel(FPanelRight, 'RX Freq', LBL_X, Y + 1, LBL_W, CTRL_H); + FCardRadio := MakeGroupPanel('RADIO', 156, 120); + CardW := FCardRadio.ClientWidth; + Y := 34; + + MakeLabel(FCardRadio, 'RX frequency', LBL_X, Y + 1, LBL_W, CTRL_H); FSpinRXFreq := TFlatFloatSpinEdit.Create(Self); - FSpinRXFreq.Parent := FPanelRight; - FSpinRXFreq.SetBounds(CTRL_X, Y, RW - CTRL_X - 50, CTRL_H); + FSpinRXFreq.Parent := FCardRadio; + FSpinRXFreq.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + CardW - DpiScale(CTRL_X + 56), DpiScale(CTRL_H)); FSpinRXFreq.Anchors := [akLeft, akTop, akRight]; FSpinRXFreq.MinValue := 0.001; FSpinRXFreq.MaxValue := 2000.0; @@ -223,14 +312,14 @@ begin FSpinRXFreq.DecimalPlaces := 6; FSpinRXFreq.Value := 145.5; FSpinRXFreq.OnChange := @OnFieldChange; - MakeLabel(FPanelRight, 'MHz', RW - 46, Y + 1, 40, CTRL_H); + PlaceRightUnit(FCardRadio, 'MHz', Y); Inc(Y, ROW_H); - // TX Freq - MakeLabel(FPanelRight, 'TX Freq', LBL_X, Y + 1, LBL_W, CTRL_H); + MakeLabel(FCardRadio, 'TX frequency', LBL_X, Y + 1, LBL_W, CTRL_H); FSpinTXFreq := TFlatFloatSpinEdit.Create(Self); - FSpinTXFreq.Parent := FPanelRight; - FSpinTXFreq.SetBounds(CTRL_X, Y, RW - CTRL_X - 50, CTRL_H); + FSpinTXFreq.Parent := FCardRadio; + FSpinTXFreq.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + CardW - DpiScale(CTRL_X + 56), DpiScale(CTRL_H)); FSpinTXFreq.Anchors := [akLeft, akTop, akRight]; FSpinTXFreq.MinValue := 0.001; FSpinTXFreq.MaxValue := 2000.0; @@ -238,48 +327,53 @@ begin FSpinTXFreq.DecimalPlaces := 6; FSpinTXFreq.Value := 145.5; FSpinTXFreq.OnChange := @OnFieldChange; - MakeLabel(FPanelRight, 'MHz', RW - 46, Y + 1, 40, CTRL_H); + PlaceRightUnit(FCardRadio, 'MHz', Y); Inc(Y, ROW_H); - // Mode - MakeLabel(FPanelRight, 'Mode', LBL_X, Y + 1, LBL_W, CTRL_H); + MakeLabel(FCardRadio, 'Mode', LBL_X, Y + 1, LBL_W, CTRL_H); FCmbMode := TFlatComboBox.Create(Self); - FCmbMode.Parent := FPanelRight; - FCmbMode.SetBounds(CTRL_X, Y, 160, CTRL_H); + FCmbMode.Parent := FCardRadio; + FCmbMode.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + DpiScale(180), DpiScale(CTRL_H)); for i := 0 to CH_MODE_COUNT - 1 do FCmbMode.Items.Add(CH_MODE_NAMES[i]); FCmbMode.ItemIndex := 5; // FM default FCmbMode.OnChange := @OnFieldChange; - Inc(Y, ROW_H); - // RPTR direction - MakeLabel(FPanelRight, 'RPTR', LBL_X, Y + 1, LBL_W, CTRL_H); + FCardRepeater := MakeGroupPanel('REPEATER / TRANSMIT', 286, 148); + CardW := FCardRepeater.ClientWidth; + Y := 34; + + MakeLabel(FCardRepeater, 'Direction', LBL_X, Y + 1, LBL_W, CTRL_H); FBtnRptNone := TFlatButton.Create(Self); - FBtnRptNone.Parent := FPanelRight; - FBtnRptNone.SetBounds(CTRL_X, Y, 55, CTRL_H); + FBtnRptNone.Parent := FCardRepeater; + FBtnRptNone.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + DpiScale(72), DpiScale(CTRL_H)); FBtnRptNone.Caption := 'NONE'; FBtnRptNone.Tag := 0; FBtnRptNone.OnClick := @OnRptBtnClick; FBtnRptMinus := TFlatButton.Create(Self); - FBtnRptMinus.Parent := FPanelRight; - FBtnRptMinus.SetBounds(CTRL_X + 58, Y, 38, CTRL_H); + FBtnRptMinus.Parent := FCardRepeater; + FBtnRptMinus.SetBounds(DpiScale(CTRL_X + 78), DpiScale(Y), + DpiScale(46), DpiScale(CTRL_H)); FBtnRptMinus.Caption := '−'; FBtnRptMinus.Tag := 1; FBtnRptMinus.OnClick := @OnRptBtnClick; FBtnRptPlus := TFlatButton.Create(Self); - FBtnRptPlus.Parent := FPanelRight; - FBtnRptPlus.SetBounds(CTRL_X + 99, Y, 38, CTRL_H); + FBtnRptPlus.Parent := FCardRepeater; + FBtnRptPlus.SetBounds(DpiScale(CTRL_X + 130), DpiScale(Y), + DpiScale(46), DpiScale(CTRL_H)); FBtnRptPlus.Caption := '+'; FBtnRptPlus.Tag := 2; FBtnRptPlus.OnClick := @OnRptBtnClick; Inc(Y, ROW_H); - // RPTR Offset - MakeLabel(FPanelRight, 'RPT Offset', LBL_X, Y + 1, LBL_W, CTRL_H); + MakeLabel(FCardRepeater, 'Offset', LBL_X, Y + 1, LBL_W, CTRL_H); FSpinRptOffset := TFlatFloatSpinEdit.Create(Self); - FSpinRptOffset.Parent := FPanelRight; - FSpinRptOffset.SetBounds(CTRL_X, Y, RW - CTRL_X - 50, CTRL_H); + FSpinRptOffset.Parent := FCardRepeater; + FSpinRptOffset.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + CardW - DpiScale(CTRL_X + 56), DpiScale(CTRL_H)); FSpinRptOffset.Anchors := [akLeft, akTop, akRight]; FSpinRptOffset.MinValue := 0.0; FSpinRptOffset.MaxValue := 100.0; @@ -287,37 +381,38 @@ begin FSpinRptOffset.DecimalPlaces := 3; FSpinRptOffset.Value := 0.6; FSpinRptOffset.OnChange := @OnFieldChange; - MakeLabel(FPanelRight, 'MHz', RW - 46, Y + 1, 40, CTRL_H); + PlaceRightUnit(FCardRepeater, 'MHz', Y); Inc(Y, ROW_H); - // CTCSS - MakeLabel(FPanelRight, 'CTCSS', LBL_X, Y + 1, LBL_W, CTRL_H); + MakeLabel(FCardRepeater, 'CTCSS tone', LBL_X, Y + 1, LBL_W, CTRL_H); FChkCTCSS := TFlatCheckBox.Create(Self); - FChkCTCSS.Parent := FPanelRight; - FChkCTCSS.SetBounds(CTRL_X, Y, 26, CTRL_H); + FChkCTCSS.Parent := FCardRepeater; + FChkCTCSS.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + DpiScale(28), DpiScale(CTRL_H)); FChkCTCSS.Caption := ''; FChkCTCSS.Checked := False; FChkCTCSS.OnChange := @OnCTCSSChkChange; FCmbCTCSS := TFlatComboBox.Create(Self); - FCmbCTCSS.Parent := FPanelRight; - FCmbCTCSS.SetBounds(CTRL_X + 30, Y, RW - CTRL_X - 38, CTRL_H); + FCmbCTCSS.Parent := FCardRepeater; + FCmbCTCSS.SetBounds(DpiScale(CTRL_X + 34), DpiScale(Y), + CardW - DpiScale(CTRL_X + 48), DpiScale(CTRL_H)); FCmbCTCSS.Anchors := [akLeft, akTop, akRight]; for i := 0 to CH_CTCSS_COUNT - 1 do FCmbCTCSS.Items.Add(CH_CTCSS_NAMES[i]); FCmbCTCSS.ItemIndex := 0; FCmbCTCSS.OnChange := @OnCTCSSCmbChange; Inc(Y, ROW_H); - // Power - MakeLabel(FPanelRight, 'Power', LBL_X, Y + 1, LBL_W, CTRL_H); + MakeLabel(FCardRepeater, 'Power', LBL_X, Y + 1, LBL_W, CTRL_H); FSpinPower := TFlatSpinEdit.Create(Self); - FSpinPower.Parent := FPanelRight; - FSpinPower.SetBounds(CTRL_X, Y, 80, CTRL_H); + FSpinPower.Parent := FCardRepeater; + FSpinPower.SetBounds(DpiScale(CTRL_X), DpiScale(Y), + DpiScale(92), DpiScale(CTRL_H)); FSpinPower.MinValue := 0; FSpinPower.MaxValue := 100; FSpinPower.Value := 100; FSpinPower.OnChange := @OnFieldChange; - MakeLabel(FPanelRight, '%', CTRL_X + 84, Y + 1, 20, CTRL_H); + MakeLabel(FCardRepeater, '%', CTRL_X + 98, Y + 1, 24, CTRL_H); end; function TChannelsForm.MakeLabel(AParent: TWinControl; const Cap: string; @@ -327,37 +422,86 @@ begin L := TLabel.Create(Self); L.Parent := AParent; L.Caption := Cap; - L.SetBounds(X, Y, W, H); - L.Font.Name := 'Courier New'; + L.AutoSize := False; + L.SetBounds(DpiScale(X), DpiScale(Y), DpiScale(W), DpiScale(H)); + L.Layout := tlCenter; L.Font.Size := 8; - L.Font.Color := DarkTheme.TextDim; + L.Font.Color := FTheme.TextDim; // Сохраняем для последующей перекраски темой SetLength(FLbls, Length(FLbls) + 1); FLbls[High(FLbls)] := L; Result := L; end; -procedure TChannelsForm.StyleBtn(B: TFlatButton; AActive: Boolean); -var T: TAppTheme; +function TChannelsForm.MakeGroupPanel(const Cap: string; Y, H: Integer): TPanel; +var + Title: TLabel; + Divider: TPanel; begin - T := DarkTheme; + Result := TPanel.Create(Self); + Result.Parent := FPanelRight; + Result.SetBounds(DpiScale(PAGE_MARGIN), DpiScale(Y), + FPanelRight.ClientWidth - DpiScale(2 * PAGE_MARGIN), DpiScale(H)); + Result.Anchors := [akLeft, akTop, akRight]; + Result.BevelOuter := bvNone; + Result.Color := FTheme.Panel; + + Title := MakeLabel(Result, Cap, 12, 2, 300, 24); + Title.Font.Size := 8; + Title.Font.Style := [fsBold]; + Title.Font.Color := FTheme.FreqActive; + + Divider := TPanel.Create(Self); + Divider.Parent := Result; + Divider.SetBounds(0, DpiScale(28), Result.ClientWidth, 1); + Divider.Anchors := [akLeft, akTop, akRight]; + Divider.BevelOuter := bvNone; + Divider.Color := FTheme.Border; +end; + +procedure TChannelsForm.StyleBtn(B: TFlatButton; AActive: Boolean); +begin + // Прямо созданные TFlatButton не проходят через MakeFlatBtn, поэтому + // явно даём им тот же системный шрифт, что и остальному интерфейсу. + B.Font.Assign(Font); + B.Font.Size := 8; + B.Font.Style := []; B.Active := AActive; - B.ClrNorm := T.BtnNorm; - B.ClrActive := T.BtnActive; - B.ClrHot := T.BtnHot; - B.ClrBorder := IfThen(AActive, T.BtnBorderActive, T.BtnBorderNorm); - B.ClrText := T.BtnText; - B.ClrTextAct := T.BtnTextActive; + B.ClrNorm := FTheme.BtnNorm; + B.ClrActive := FTheme.BtnActive; + B.ClrHot := FTheme.BtnHot; + B.ClrBorder := IfThen(AActive, + FTheme.BtnBorderActive, FTheme.BtnBorderNorm); + B.ClrText := FTheme.BtnText; + B.ClrTextAct := FTheme.BtnTextActive; + B.Invalidate; end; procedure TChannelsForm.ApplyTheme(const T: TAppTheme); var i: Integer; Ch: TChannel; + + procedure ThemeCard(P: TPanel); + var + n: Integer; + begin + if P = nil then Exit; + P.Color := T.Panel; + for n := 0 to P.ControlCount - 1 do + if (P.Controls[n] is TPanel) and (P.Controls[n].Height = 1) then + TPanel(P.Controls[n]).Color := T.Border; + end; + begin - Color := T.Panel; + FTheme := T; + Color := T.BG; FPanelLeft.Color := T.Panel; - FPanelRight.Color := T.Panel; + FPanelRight.Color := T.BG; + FFooterPanel.Color := T.BG; + ThemeCard(FCardIdentity); + ThemeCard(FCardRadio); + ThemeCard(FCardRepeater); FList.SetAppTheme(T); @@ -365,6 +509,7 @@ begin StyleBtn(FBtnDelete); StyleBtn(FBtnUp); StyleBtn(FBtnDown); + StyleBtn(FBtnClose); // RPT buttons — пересчитываем Active из текущего состояния if SelectedIdx >= 0 then @@ -393,9 +538,15 @@ begin for i := 0 to High(FLbls) do begin - FLbls[i].Font.Color := T.TextDim; - FLbls[i].Color := T.Panel; - FLbls[i].ParentColor := False; + if FLbls[i] = FLeftTitle then + FLbls[i].Font.Color := T.Text + else if FLbls[i] = FRightTitle then + FLbls[i].Font.Color := T.Text + else if fsBold in FLbls[i].Font.Style then + FLbls[i].Font.Color := T.FreqActive + else + FLbls[i].Font.Color := T.TextDim; + FLbls[i].Transparent := True; end; end; @@ -476,7 +627,6 @@ procedure TChannelsForm.SaveFieldsToChannel; var Idx: Integer; Ch: TChannel; - i: Integer; begin if FUpdating then Exit; Idx := SelectedIdx; @@ -607,6 +757,11 @@ begin SaveFieldsToChannel; end; +procedure TChannelsForm.OnCloseClick(Sender: TObject); +begin + Close; +end; + procedure TChannelsForm.OnFormClose(Sender: TObject; var CloseAction: TCloseAction); begin CloseAction := caHide; // скрываем, не уничтожаем — указатель в MainForm остаётся валидным