mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
add light/dark theme with global persistence
- AppTheme.pas: новый файл, TAppTheme record + DarkTheme()/LightTheme() - FlatSlider: цвета через SetThemeColors вместо хардкода - SpectrumView: все цвета из TAppTheme (SetTheme) - SettingsForm: ApplyTheme(T) с рекурсивным обходом контролов - DeviceForm: SetTheme(T) — перекраска всех элементов включая TEdit - Settings: SaveTheme/LoadTheme в корневой секции preferences (не привязано к устройству) - MainForm: тема загружается при старте, сохраняется при изменении Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+303
@@ -0,0 +1,303 @@
|
|||||||
|
unit AppTheme;
|
||||||
|
|
||||||
|
{ Цветовые темы приложения EWSDR.
|
||||||
|
Определяет TAppTheme — запись со всеми цветами интерфейса.
|
||||||
|
Два конструктора: DarkTheme() и LightTheme(). }
|
||||||
|
|
||||||
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses Graphics;
|
||||||
|
|
||||||
|
type
|
||||||
|
TAppTheme = record
|
||||||
|
// Форма / панели
|
||||||
|
BG, Panel, Border: TColor;
|
||||||
|
// Текст
|
||||||
|
Text, TextDim: TColor;
|
||||||
|
// Обычные кнопки (StyleButton)
|
||||||
|
BtnNorm, BtnActive, BtnHot: TColor;
|
||||||
|
BtnBorderNorm, BtnBorderActive: TColor;
|
||||||
|
BtnText, BtnTextActive: TColor;
|
||||||
|
// Кнопки SPAN / VFO-copy / HidePanel (StyleSpanButton)
|
||||||
|
SpanNorm, SpanActive: TColor;
|
||||||
|
SpanBorder: TColor;
|
||||||
|
SpanText: TColor;
|
||||||
|
// Кнопки тулбара (Discover / StartStop)
|
||||||
|
TbDiscoverNorm, TbDiscoverHot, TbDiscoverBorder: TColor;
|
||||||
|
TbDiscoverText: TColor;
|
||||||
|
TbStartNorm, TbStartBorder, TbStartText: TColor;
|
||||||
|
// VFO-select кнопка — активный VFO
|
||||||
|
VfoSelActNorm, VfoSelActBorder: TColor;
|
||||||
|
VfoSelActText, VfoSelActTextAct: TColor;
|
||||||
|
// VFO-select кнопка — неактивный VFO
|
||||||
|
VfoSelInaNorm, VfoSelInaBorder: TColor;
|
||||||
|
VfoSelInaText, VfoSelInaTextAct: TColor;
|
||||||
|
// VFO-TX кнопка — активна (TX на этом VFO)
|
||||||
|
VfoTxActNorm, VfoTxActBorder: TColor;
|
||||||
|
VfoTxActText: TColor;
|
||||||
|
// VFO-TX кнопка — неактивна
|
||||||
|
VfoTxInaNorm, VfoTxInaBorder: TColor;
|
||||||
|
VfoTxInaText: TColor;
|
||||||
|
// Дисплей частоты
|
||||||
|
FreqActive, FreqDim: TColor;
|
||||||
|
// Индикаторы (S-meter, мощность)
|
||||||
|
MeterOn, MeterOvr: TColor;
|
||||||
|
Amber: TColor;
|
||||||
|
// Спектр — фон и сетка
|
||||||
|
SpecGradTop, SpecGradBot: TColor;
|
||||||
|
SpecLabelBand: TColor;
|
||||||
|
SpecLabelText: TColor;
|
||||||
|
SpecGrid: TColor;
|
||||||
|
// Спектр — сигнал и маркеры
|
||||||
|
SpecLine: TColor;
|
||||||
|
SpecFilter: TColor;
|
||||||
|
SpecFilterEdge: TColor;
|
||||||
|
SpecAgcColor: TColor;
|
||||||
|
SpecAgcHangColor: TColor;
|
||||||
|
SpecVfoCursor: TColor;
|
||||||
|
// Спектр — градиент заливки (каналы Blue/Green/Red в сыром пикселе)
|
||||||
|
SpecGradB, SpecGradG, SpecGradR: Byte; // при Alpha=200
|
||||||
|
// Линейка частот
|
||||||
|
RulerGradTop, RulerGradBot: TColor;
|
||||||
|
RulerBorder: TColor;
|
||||||
|
RulerText: TColor;
|
||||||
|
RulerVfo: TColor;
|
||||||
|
// Ползунки
|
||||||
|
SliderBG: TColor;
|
||||||
|
SliderTrackEmpty: TColor;
|
||||||
|
SliderTrackFill: TColor;
|
||||||
|
SliderThumbNorm: TColor;
|
||||||
|
SliderThumbHot: TColor;
|
||||||
|
SliderThumbDrag: TColor;
|
||||||
|
SliderThumbBdr: TColor;
|
||||||
|
// S-метр (широкий)
|
||||||
|
SMeterBG: TColor;
|
||||||
|
SMeterBarGreen: TColor;
|
||||||
|
SMeterBarOver: TColor;
|
||||||
|
SMeterPeakMarker: TColor;
|
||||||
|
SMeterTickGreen: TColor;
|
||||||
|
SMeterTickWhite: TColor;
|
||||||
|
SMeterTickBlue: TColor;
|
||||||
|
SMeterLabelDbm: TColor;
|
||||||
|
SMeterLabelS: TColor;
|
||||||
|
SMeterScaleDbm: TColor;
|
||||||
|
SMeterScaleSGreen: TColor;
|
||||||
|
SMeterScaleSBlue: TColor;
|
||||||
|
SMeterBdr: TColor;
|
||||||
|
SMeterDivider: TColor;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function DarkTheme: TAppTheme;
|
||||||
|
function LightTheme: TAppTheme;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function DarkTheme: TAppTheme;
|
||||||
|
begin
|
||||||
|
FillChar(Result, SizeOf(Result), 0);
|
||||||
|
Result.BG := TColor($00101010);
|
||||||
|
Result.Panel := TColor($00181818);
|
||||||
|
Result.Border := TColor($00303030);
|
||||||
|
Result.Text := TColor($00CCCCCC);
|
||||||
|
Result.TextDim := TColor($00666666);
|
||||||
|
|
||||||
|
Result.BtnNorm := TColor($001A1A1A);
|
||||||
|
Result.BtnActive := TColor($000C3010);
|
||||||
|
Result.BtnHot := TColor($00282828);
|
||||||
|
Result.BtnBorderNorm := TColor($00444444);
|
||||||
|
Result.BtnBorderActive := TColor($00387838);
|
||||||
|
Result.BtnText := TColor($00CCCCCC);
|
||||||
|
Result.BtnTextActive := TColor($0000FF88);
|
||||||
|
|
||||||
|
Result.SpanNorm := TColor($00543F18);
|
||||||
|
Result.SpanActive := TColor($00624B1D);
|
||||||
|
Result.SpanBorder := TColor($00685624);
|
||||||
|
Result.SpanText := TColor($00D8E6EE);
|
||||||
|
|
||||||
|
Result.TbDiscoverNorm := TColor($00101828);
|
||||||
|
Result.TbDiscoverHot := TColor($00182038);
|
||||||
|
Result.TbDiscoverBorder := TColor($00304860);
|
||||||
|
Result.TbDiscoverText := TColor($0090B8D0);
|
||||||
|
Result.TbStartNorm := TColor($00101810);
|
||||||
|
Result.TbStartBorder := TColor($00304830);
|
||||||
|
Result.TbStartText := TColor($0090C090);
|
||||||
|
|
||||||
|
Result.VfoSelActNorm := TColor($00101C10);
|
||||||
|
Result.VfoSelActBorder := TColor($004A7A4A);
|
||||||
|
Result.VfoSelActText := TColor($0060B860);
|
||||||
|
Result.VfoSelActTextAct := TColor($0040FF60);
|
||||||
|
Result.VfoSelInaNorm := TColor($001A1A1A);
|
||||||
|
Result.VfoSelInaBorder := TColor($00404040);
|
||||||
|
Result.VfoSelInaText := TColor($00666666);
|
||||||
|
Result.VfoSelInaTextAct := TColor($00CCCCCC);
|
||||||
|
|
||||||
|
Result.VfoTxActNorm := TColor($00000060);
|
||||||
|
Result.VfoTxActBorder := TColor($001010B0);
|
||||||
|
Result.VfoTxActText := TColor($00C8D8FF);
|
||||||
|
Result.VfoTxInaNorm := TColor($00303030);
|
||||||
|
Result.VfoTxInaBorder := TColor($00404040);
|
||||||
|
Result.VfoTxInaText := TColor($00808080);
|
||||||
|
|
||||||
|
Result.FreqActive := TColor($0000FF00);
|
||||||
|
Result.FreqDim := TColor($00007800);
|
||||||
|
|
||||||
|
Result.MeterOn := TColor($0000CC44);
|
||||||
|
Result.MeterOvr := TColor($000000CC);
|
||||||
|
Result.Amber := TColor($0000AAFF);
|
||||||
|
|
||||||
|
Result.SpecGradTop := TColor($0020160B);
|
||||||
|
Result.SpecGradBot := TColor($006C4F1F);
|
||||||
|
Result.SpecLabelBand := TColor($00543F18);
|
||||||
|
Result.SpecLabelText := TColor($00A8C9D9);
|
||||||
|
Result.SpecGrid := TColor($00685624);
|
||||||
|
Result.SpecLine := TColor($0040FF80);
|
||||||
|
Result.SpecFilter := TColor($006A4E22);
|
||||||
|
Result.SpecFilterEdge := TColor($0040FFCC);
|
||||||
|
Result.SpecAgcColor := TColor($0000AAFF);
|
||||||
|
Result.SpecAgcHangColor := TColor($00FFCC00);
|
||||||
|
Result.SpecVfoCursor := TColor($0000AAFF);
|
||||||
|
Result.SpecGradB := 100; Result.SpecGradG := 200; Result.SpecGradR := 0;
|
||||||
|
|
||||||
|
Result.RulerGradTop := TColor($00372A12);
|
||||||
|
Result.RulerGradBot := TColor($00705A2A);
|
||||||
|
Result.RulerBorder := TColor($00685624);
|
||||||
|
Result.RulerText := TColor($00C8D8E2);
|
||||||
|
Result.RulerVfo := TColor($0000FF80);
|
||||||
|
|
||||||
|
Result.SliderBG := TColor($00181818);
|
||||||
|
Result.SliderTrackEmpty := TColor($00323232);
|
||||||
|
Result.SliderTrackFill := TColor($00205018);
|
||||||
|
Result.SliderThumbNorm := TColor($00407840);
|
||||||
|
Result.SliderThumbHot := TColor($0066BB66);
|
||||||
|
Result.SliderThumbDrag := TColor($0099EE99);
|
||||||
|
Result.SliderThumbBdr := TColor($00122012);
|
||||||
|
|
||||||
|
Result.SMeterBG := TColor($00181818);
|
||||||
|
Result.SMeterBarGreen := TColor($00091F00);
|
||||||
|
Result.SMeterBarOver := TColor($00091528);
|
||||||
|
Result.SMeterPeakMarker := TColor($00F8F8FF);
|
||||||
|
Result.SMeterTickGreen := TColor($00708070);
|
||||||
|
Result.SMeterTickWhite := TColor($00E0E0DC);
|
||||||
|
Result.SMeterTickBlue := TColor($0070A090);
|
||||||
|
Result.SMeterLabelDbm := TColor($0096D8DC);
|
||||||
|
Result.SMeterLabelS := TColor($00F0F0F0);
|
||||||
|
Result.SMeterScaleDbm := TColor($00D0DCDC);
|
||||||
|
Result.SMeterScaleSGreen:= TColor($00E0E0E0);
|
||||||
|
Result.SMeterScaleSBlue := TColor($0090D090);
|
||||||
|
Result.SMeterBdr := TColor($00303028);
|
||||||
|
Result.SMeterDivider := TColor($00404040);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LightTheme: TAppTheme;
|
||||||
|
begin
|
||||||
|
FillChar(Result, SizeOf(Result), 0);
|
||||||
|
// Фон — тёплый белый, панели — тёплый светло-серый
|
||||||
|
Result.BG := TColor($00F0EEE8);
|
||||||
|
Result.Panel := TColor($00E8E6E0);
|
||||||
|
Result.Border := TColor($00B8B4AC);
|
||||||
|
Result.Text := TColor($00181410);
|
||||||
|
Result.TextDim := TColor($00706860);
|
||||||
|
|
||||||
|
// Обычные кнопки — светло-серые, активная — светло-зелёная
|
||||||
|
Result.BtnNorm := TColor($00DCDAD4);
|
||||||
|
Result.BtnActive := TColor($00B8D8B8);
|
||||||
|
Result.BtnHot := TColor($00CFCDC6);
|
||||||
|
Result.BtnBorderNorm := TColor($00A8A4A0);
|
||||||
|
Result.BtnBorderActive := TColor($00407840);
|
||||||
|
Result.BtnText := TColor($00181410);
|
||||||
|
Result.BtnTextActive := TColor($00004800);
|
||||||
|
|
||||||
|
// Span/VFO-copy — тёплый тан/пергамент
|
||||||
|
Result.SpanNorm := TColor($00D4C8A0);
|
||||||
|
Result.SpanActive := TColor($00C0B488);
|
||||||
|
Result.SpanBorder := TColor($00A09070);
|
||||||
|
Result.SpanText := TColor($00302010);
|
||||||
|
|
||||||
|
// Тулбар — более насыщенные оттенки
|
||||||
|
Result.TbDiscoverNorm := TColor($00C8D8E8);
|
||||||
|
Result.TbDiscoverHot := TColor($00B8CCE0);
|
||||||
|
Result.TbDiscoverBorder := TColor($00789CB8);
|
||||||
|
Result.TbDiscoverText := TColor($00284860);
|
||||||
|
Result.TbStartNorm := TColor($00C8E0C8);
|
||||||
|
Result.TbStartBorder := TColor($00609860);
|
||||||
|
Result.TbStartText := TColor($00204820);
|
||||||
|
|
||||||
|
// VFO-select активный — зелёная подсветка
|
||||||
|
Result.VfoSelActNorm := TColor($00C0E0C0);
|
||||||
|
Result.VfoSelActBorder := TColor($00508050);
|
||||||
|
Result.VfoSelActText := TColor($00205020);
|
||||||
|
Result.VfoSelActTextAct := TColor($00006600);
|
||||||
|
// VFO-select неактивный — нейтральный
|
||||||
|
Result.VfoSelInaNorm := TColor($00DCDAD4);
|
||||||
|
Result.VfoSelInaBorder := TColor($00A8A4A0);
|
||||||
|
Result.VfoSelInaText := TColor($00706860);
|
||||||
|
Result.VfoSelInaTextAct := TColor($00181410);
|
||||||
|
|
||||||
|
// VFO-TX — синеватый акцент
|
||||||
|
Result.VfoTxActNorm := TColor($00C0CCEC);
|
||||||
|
Result.VfoTxActBorder := TColor($006070C0);
|
||||||
|
Result.VfoTxActText := TColor($00102060);
|
||||||
|
Result.VfoTxInaNorm := TColor($00DCDAD4);
|
||||||
|
Result.VfoTxInaBorder := TColor($00A8A4A0);
|
||||||
|
Result.VfoTxInaText := TColor($00706860);
|
||||||
|
|
||||||
|
// Дисплей частоты — насыщенный зелёный
|
||||||
|
Result.FreqActive := TColor($00005500);
|
||||||
|
Result.FreqDim := TColor($00447044);
|
||||||
|
|
||||||
|
// Индикаторы
|
||||||
|
Result.MeterOn := TColor($00006820);
|
||||||
|
Result.MeterOvr := TColor($00AA1010);
|
||||||
|
Result.Amber := TColor($00904000);
|
||||||
|
|
||||||
|
// Спектр — светлый пергаментный фон, тёмно-зелёный сигнал
|
||||||
|
Result.SpecGradTop := TColor($00E8E4D8);
|
||||||
|
Result.SpecGradBot := TColor($00D0CCBE);
|
||||||
|
Result.SpecLabelBand := TColor($00D8D4C8);
|
||||||
|
Result.SpecLabelText := TColor($00404038);
|
||||||
|
Result.SpecGrid := TColor($00B8B4A4);
|
||||||
|
Result.SpecLine := TColor($00006400); // тёмно-зелёная линия
|
||||||
|
Result.SpecFilter := TColor($00C8DCC8); // светло-зелёная полоса фильтра
|
||||||
|
Result.SpecFilterEdge := TColor($00407840);
|
||||||
|
Result.SpecAgcColor := TColor($00904000); // тёмно-оранжевый AGC
|
||||||
|
Result.SpecAgcHangColor := TColor($00802000);
|
||||||
|
Result.SpecVfoCursor := TColor($00004800);
|
||||||
|
// Пиксели градиента: тёмно-зелёный (B=0, G=80, R=10 при Alpha=200)
|
||||||
|
Result.SpecGradB := 0; Result.SpecGradG := 80; Result.SpecGradR := 10;
|
||||||
|
|
||||||
|
// Линейка — тёплый пергамент
|
||||||
|
Result.RulerGradTop := TColor($00DDD8CC);
|
||||||
|
Result.RulerGradBot := TColor($00C8C2B4);
|
||||||
|
Result.RulerBorder := TColor($00A09878);
|
||||||
|
Result.RulerText := TColor($00302820);
|
||||||
|
Result.RulerVfo := TColor($00006800);
|
||||||
|
|
||||||
|
// Ползунки — светлые с зелёным акцентом
|
||||||
|
Result.SliderBG := TColor($00E8E6E0);
|
||||||
|
Result.SliderTrackEmpty := TColor($00CCCAC4);
|
||||||
|
Result.SliderTrackFill := TColor($0080AA80);
|
||||||
|
Result.SliderThumbNorm := TColor($00508050);
|
||||||
|
Result.SliderThumbHot := TColor($003D9040);
|
||||||
|
Result.SliderThumbDrag := TColor($0028A830);
|
||||||
|
Result.SliderThumbBdr := TColor($00183018);
|
||||||
|
|
||||||
|
// S-метр — светлый
|
||||||
|
Result.SMeterBG := TColor($00ECE8E0);
|
||||||
|
Result.SMeterBarGreen := TColor($00C0EAC0);
|
||||||
|
Result.SMeterBarOver := TColor($00EAC0C0);
|
||||||
|
Result.SMeterPeakMarker := TColor($00181010);
|
||||||
|
Result.SMeterTickGreen := TColor($00508050);
|
||||||
|
Result.SMeterTickWhite := TColor($00282018);
|
||||||
|
Result.SMeterTickBlue := TColor($00406880);
|
||||||
|
Result.SMeterLabelDbm := TColor($00204860);
|
||||||
|
Result.SMeterLabelS := TColor($00201810);
|
||||||
|
Result.SMeterScaleDbm := TColor($00304848);
|
||||||
|
Result.SMeterScaleSGreen:= TColor($00204020);
|
||||||
|
Result.SMeterScaleSBlue := TColor($00204050);
|
||||||
|
Result.SMeterBdr := TColor($00A0A090);
|
||||||
|
Result.SMeterDivider := TColor($00B0ACA0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
+66
-2
@@ -5,7 +5,7 @@ unit DeviceForm;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, FlatButton, Forms, Controls, Graphics, Dialogs,
|
Classes, SysUtils, FlatButton, AppTheme, Forms, Controls, Graphics, Dialogs,
|
||||||
StdCtrls, ExtCtrls, ComCtrls, IniFiles;
|
StdCtrls, ExtCtrls, ComCtrls, IniFiles;
|
||||||
|
|
||||||
// Декодирование типа платы (совпадает с MainForm.BoardTypeName)
|
// Декодирование типа платы (совпадает с MainForm.BoardTypeName)
|
||||||
@@ -94,6 +94,8 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(AOwner: TComponent); override;
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
|
||||||
|
procedure SetTheme(const T: TAppTheme);
|
||||||
|
|
||||||
// Добавить найденное устройство (вызывается из MainForm при discovery)
|
// Добавить найденное устройство (вызывается из MainForm при discovery)
|
||||||
procedure AddDiscovered(const IP, DisplayName: string; BoardType: Integer = 0);
|
procedure AddDiscovered(const IP, DisplayName: string; BoardType: Integer = 0);
|
||||||
procedure ClearDiscovered;
|
procedure ClearDiscovered;
|
||||||
@@ -271,7 +273,69 @@ end;
|
|||||||
|
|
||||||
procedure TDeviceDialog.ApplyTheme;
|
procedure TDeviceDialog.ApplyTheme;
|
||||||
begin
|
begin
|
||||||
// уже задано в BuildUI
|
end;
|
||||||
|
|
||||||
|
procedure TDeviceDialog.SetTheme(const T: TAppTheme);
|
||||||
|
|
||||||
|
procedure StyleBtn(B: TFlatButton; Accent: Boolean);
|
||||||
|
begin
|
||||||
|
B.ClrNorm := T.Panel;
|
||||||
|
B.ClrBorder := T.Border;
|
||||||
|
B.ClrHot := T.BG;
|
||||||
|
B.ClrActive := T.Panel;
|
||||||
|
B.ClrText := T.Text;
|
||||||
|
if Accent then B.ClrTextAct := T.FreqActive
|
||||||
|
else B.ClrTextAct := T.Text;
|
||||||
|
B.Font.Color := T.Text;
|
||||||
|
B.Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure WalkLabels(C: TWinControl);
|
||||||
|
var i: Integer; Ctrl: TControl;
|
||||||
|
begin
|
||||||
|
for i := 0 to C.ControlCount - 1 do
|
||||||
|
begin
|
||||||
|
Ctrl := C.Controls[i];
|
||||||
|
if Ctrl is TLabel then
|
||||||
|
TLabel(Ctrl).Font.Color := T.TextDim
|
||||||
|
else if Ctrl is TWinControl then
|
||||||
|
WalkLabels(TWinControl(Ctrl));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
Color := T.BG;
|
||||||
|
Font.Color := T.Text;
|
||||||
|
if PanelLeft <> nil then PanelLeft.Color := T.Panel;
|
||||||
|
if PanelRight <> nil then PanelRight.Color := T.Panel;
|
||||||
|
if LstSaved <> nil then begin
|
||||||
|
LstSaved.Color := T.BG;
|
||||||
|
LstSaved.Font.Color := T.Text;
|
||||||
|
end;
|
||||||
|
if LstFound <> nil then begin
|
||||||
|
LstFound.Color := T.BG;
|
||||||
|
LstFound.Font.Color := T.Text;
|
||||||
|
end;
|
||||||
|
if BtnAdd <> nil then StyleBtn(BtnAdd, False);
|
||||||
|
if BtnRemove <> nil then StyleBtn(BtnRemove, False);
|
||||||
|
if BtnSetAuto <> nil then StyleBtn(BtnSetAuto, False);
|
||||||
|
if BtnDiscover <> nil then StyleBtn(BtnDiscover, False);
|
||||||
|
if BtnAddFound <> nil then StyleBtn(BtnAddFound, False);
|
||||||
|
if BtnCancel <> nil then StyleBtn(BtnCancel, False);
|
||||||
|
if BtnConnect <> nil then StyleBtn(BtnConnect, True);
|
||||||
|
// Edit fields: white bg for light theme, dark bg for dark theme
|
||||||
|
if Integer(T.BG) > Integer(TColor($00808080)) then
|
||||||
|
begin
|
||||||
|
if EdName <> nil then begin EdName.Color := TColor($00FFFFFF); EdName.Font.Color := TColor($00202020); end;
|
||||||
|
if EdIP <> nil then begin EdIP.Color := TColor($00FFFFFF); EdIP.Font.Color := TColor($00202020); end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if EdName <> nil then begin EdName.Color := TColor($00121212); EdName.Font.Color := TColor($00E0E0E0); end;
|
||||||
|
if EdIP <> nil then begin EdIP.Color := TColor($00121212); EdIP.Font.Color := TColor($00E0E0E0); end;
|
||||||
|
end;
|
||||||
|
WalkLabels(Self);
|
||||||
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDeviceDialog.LoadSaved;
|
procedure TDeviceDialog.LoadSaved;
|
||||||
|
|||||||
+51
-31
@@ -1,7 +1,8 @@
|
|||||||
unit FlatSlider;
|
unit FlatSlider;
|
||||||
|
|
||||||
{ Кастомный горизонтальный ползунок с тёмной темой — замена TTrackBar.
|
{ Кастомный горизонтальный ползунок — замена TTrackBar.
|
||||||
Полностью отрисован через Canvas, одинаково выглядит на Windows и Linux. }
|
Полностью отрисован через Canvas, одинаково выглядит на Windows и Linux.
|
||||||
|
Цвета настраиваемые: применяй SetThemeColors(T: TAppTheme) для смены темы. }
|
||||||
|
|
||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
@@ -20,6 +21,14 @@ type
|
|||||||
FDragging: Boolean;
|
FDragging: Boolean;
|
||||||
FHot: Boolean;
|
FHot: Boolean;
|
||||||
FOnChange: TNotifyEvent;
|
FOnChange: TNotifyEvent;
|
||||||
|
// Цвета (настраиваются через SetThemeColors или напрямую)
|
||||||
|
FClrBG: TColor;
|
||||||
|
FClrTrackEmpty: TColor;
|
||||||
|
FClrTrackFill: TColor;
|
||||||
|
FClrThumbNorm: TColor;
|
||||||
|
FClrThumbHot: TColor;
|
||||||
|
FClrThumbDrag: TColor;
|
||||||
|
FClrThumbBdr: TColor;
|
||||||
procedure SetPosition(V: Integer);
|
procedure SetPosition(V: Integer);
|
||||||
procedure SetMin(V: Integer);
|
procedure SetMin(V: Integer);
|
||||||
procedure SetMax(V: Integer);
|
procedure SetMax(V: Integer);
|
||||||
@@ -39,6 +48,11 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(AOwner: TComponent); override;
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
|
||||||
|
// Применить набор цветов из темы
|
||||||
|
procedure SetThemeColors(
|
||||||
|
ABG, ATrackEmpty, ATrackFill,
|
||||||
|
AThumbNorm, AThumbHot, AThumbDrag, AThumbBdr: TColor);
|
||||||
|
|
||||||
property Min: Integer read FMin write SetMin;
|
property Min: Integer read FMin write SetMin;
|
||||||
property Max: Integer read FMax write SetMax;
|
property Max: Integer read FMax write SetMax;
|
||||||
property Position: Integer read FPosition write SetPosition;
|
property Position: Integer read FPosition write SetPosition;
|
||||||
@@ -51,17 +65,9 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
const
|
const
|
||||||
THUMB_R = 6; // радиус ручки (px)
|
THUMB_R = 6;
|
||||||
TRACK_H = 4; // высота рельса (px)
|
TRACK_H = 4;
|
||||||
PAD = THUMB_R + 2; // боковой отступ чтобы ручка не вылезала
|
PAD = THUMB_R + 2;
|
||||||
|
|
||||||
CLR_BG = TColor($00181818); // совпадает с CLR_PANEL
|
|
||||||
CLR_TRACK_EMPTY = TColor($00323232);
|
|
||||||
CLR_TRACK_FILL = TColor($00205018); // тёмно-зелёный, как тема
|
|
||||||
CLR_THUMB_NORM = TColor($00407840);
|
|
||||||
CLR_THUMB_HOT = TColor($0066BB66);
|
|
||||||
CLR_THUMB_DRAG = TColor($0099EE99);
|
|
||||||
CLR_THUMB_BDR = TColor($00122012);
|
|
||||||
|
|
||||||
constructor TFlatSlider.Create(AOwner: TComponent);
|
constructor TFlatSlider.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
@@ -73,11 +79,32 @@ begin
|
|||||||
FDragging := False;
|
FDragging := False;
|
||||||
FHot := False;
|
FHot := False;
|
||||||
Cursor := crHandPoint;
|
Cursor := crHandPoint;
|
||||||
|
// Тёмная тема по умолчанию
|
||||||
|
FClrBG := TColor($00181818);
|
||||||
|
FClrTrackEmpty := TColor($00323232);
|
||||||
|
FClrTrackFill := TColor($00205018);
|
||||||
|
FClrThumbNorm := TColor($00407840);
|
||||||
|
FClrThumbHot := TColor($0066BB66);
|
||||||
|
FClrThumbDrag := TColor($0099EE99);
|
||||||
|
FClrThumbBdr := TColor($00122012);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFlatSlider.SetThemeColors(
|
||||||
|
ABG, ATrackEmpty, ATrackFill,
|
||||||
|
AThumbNorm, AThumbHot, AThumbDrag, AThumbBdr: TColor);
|
||||||
|
begin
|
||||||
|
FClrBG := ABG;
|
||||||
|
FClrTrackEmpty := ATrackEmpty;
|
||||||
|
FClrTrackFill := ATrackFill;
|
||||||
|
FClrThumbNorm := AThumbNorm;
|
||||||
|
FClrThumbHot := AThumbHot;
|
||||||
|
FClrThumbDrag := AThumbDrag;
|
||||||
|
FClrThumbBdr := AThumbBdr;
|
||||||
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFlatSlider.SetPosition(V: Integer);
|
procedure TFlatSlider.SetPosition(V: Integer);
|
||||||
var
|
var C: Integer;
|
||||||
C: Integer;
|
|
||||||
begin
|
begin
|
||||||
C := EnsureRange(V, FMin, FMax);
|
C := EnsureRange(V, FMin, FMax);
|
||||||
if FPosition = C then Exit;
|
if FPosition = C then Exit;
|
||||||
@@ -102,10 +129,8 @@ begin
|
|||||||
Invalidate;
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Позиция значения → пиксельная X-координата ручки
|
|
||||||
function TFlatSlider.PosToX(APos: Integer): Integer;
|
function TFlatSlider.PosToX(APos: Integer): Integer;
|
||||||
var
|
var Range, TrackW: Integer;
|
||||||
Range, TrackW: Integer;
|
|
||||||
begin
|
begin
|
||||||
Range := FMax - FMin;
|
Range := FMax - FMin;
|
||||||
TrackW := Width - PAD * 2;
|
TrackW := Width - PAD * 2;
|
||||||
@@ -116,10 +141,8 @@ begin
|
|||||||
Result := PAD + Round((APos - FMin) / Range * TrackW);
|
Result := PAD + Round((APos - FMin) / Range * TrackW);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Пиксельная X-координата → значение позиции
|
|
||||||
function TFlatSlider.XToPos(AX: Integer): Integer;
|
function TFlatSlider.XToPos(AX: Integer): Integer;
|
||||||
var
|
var Range, TrackW, RawX: Integer;
|
||||||
Range, TrackW, RawX: Integer;
|
|
||||||
begin
|
begin
|
||||||
Range := FMax - FMin;
|
Range := FMax - FMin;
|
||||||
TrackW := Width - PAD * 2;
|
TrackW := Width - PAD * 2;
|
||||||
@@ -141,32 +164,29 @@ begin
|
|||||||
CY := Height div 2;
|
CY := Height div 2;
|
||||||
TX := PosToX(FPosition);
|
TX := PosToX(FPosition);
|
||||||
|
|
||||||
Canvas.Brush.Color := CLR_BG;
|
Canvas.Brush.Color := FClrBG;
|
||||||
Canvas.Brush.Style := bsSolid;
|
Canvas.Brush.Style := bsSolid;
|
||||||
Canvas.Pen.Style := psClear;
|
Canvas.Pen.Style := psClear;
|
||||||
Canvas.FillRect(ClientRect);
|
Canvas.FillRect(ClientRect);
|
||||||
|
|
||||||
// Рельс — весь
|
|
||||||
TR := Rect(PAD, CY - TRACK_H div 2,
|
TR := Rect(PAD, CY - TRACK_H div 2,
|
||||||
Width - PAD, CY + (TRACK_H + 1) div 2);
|
Width - PAD, CY + (TRACK_H + 1) div 2);
|
||||||
Canvas.Brush.Color := CLR_TRACK_EMPTY;
|
Canvas.Brush.Color := FClrTrackEmpty;
|
||||||
Canvas.RoundRect(TR.Left, TR.Top, TR.Right, TR.Bottom, TRACK_H, TRACK_H);
|
Canvas.RoundRect(TR.Left, TR.Top, TR.Right, TR.Bottom, TRACK_H, TRACK_H);
|
||||||
|
|
||||||
// Рельс — заполненная часть
|
|
||||||
if not FReversed then begin FL := PAD; FR := TX; end
|
if not FReversed then begin FL := PAD; FR := TX; end
|
||||||
else begin FL := TX; FR := Width - PAD; end;
|
else begin FL := TX; FR := Width - PAD; end;
|
||||||
if FR > FL then
|
if FR > FL then
|
||||||
begin
|
begin
|
||||||
Canvas.Brush.Color := CLR_TRACK_FILL;
|
Canvas.Brush.Color := FClrTrackFill;
|
||||||
Canvas.RoundRect(FL, TR.Top, FR, TR.Bottom, TRACK_H, TRACK_H);
|
Canvas.RoundRect(FL, TR.Top, FR, TR.Bottom, TRACK_H, TRACK_H);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Ручка — круг
|
if FDragging then ThC := FClrThumbDrag
|
||||||
if FDragging then ThC := CLR_THUMB_DRAG
|
else if FHot then ThC := FClrThumbHot
|
||||||
else if FHot then ThC := CLR_THUMB_HOT
|
else ThC := FClrThumbNorm;
|
||||||
else ThC := CLR_THUMB_NORM;
|
|
||||||
Canvas.Brush.Color := ThC;
|
Canvas.Brush.Color := ThC;
|
||||||
Canvas.Pen.Color := CLR_THUMB_BDR;
|
Canvas.Pen.Color := FClrThumbBdr;
|
||||||
Canvas.Pen.Style := psSolid;
|
Canvas.Pen.Style := psSolid;
|
||||||
Canvas.Pen.Width := 1;
|
Canvas.Pen.Width := 1;
|
||||||
Canvas.Ellipse(TX - THUMB_R, CY - THUMB_R,
|
Canvas.Ellipse(TX - THUMB_R, CY - THUMB_R,
|
||||||
|
|||||||
+168
-82
@@ -22,7 +22,7 @@ unit MainForm;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, StrUtils, FreqDisplay, DeviceForm, VfoOverlay, FlatButton, FlatSlider, Forms, Controls, Graphics, Dialogs,
|
Classes, SysUtils, StrUtils, FreqDisplay, DeviceForm, VfoOverlay, FlatButton, FlatSlider, 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,
|
||||||
@@ -249,6 +249,7 @@ type
|
|||||||
FPendingDev: THPSDRDevice; // устройство ожидающее открытия WDSP
|
FPendingDev: THPSDRDevice; // устройство ожидающее открытия WDSP
|
||||||
FBandCache: array[0..CFG_BAND_COUNT-1] of TBandSettings; // кэш диапазонов
|
FBandCache: array[0..CFG_BAND_COUNT-1] of TBandSettings; // кэш диапазонов
|
||||||
FDevConnected: Boolean; // True после первого подключения
|
FDevConnected: Boolean; // True после первого подключения
|
||||||
|
FLightTheme: Boolean; // True = светлая тема
|
||||||
FCenterFreq: Double; // центр спектра = LO (DDC). При CTUN ON не меняется при кручении VFO
|
FCenterFreq: Double; // центр спектра = LO (DDC). При CTUN ON не меняется при кручении VFO
|
||||||
FSpanHz: Double;
|
FSpanHz: Double;
|
||||||
FSampleRate: Integer; // текущий DDC sample rate (Hz)
|
FSampleRate: Integer; // текущий DDC sample rate (Hz)
|
||||||
@@ -345,6 +346,7 @@ type
|
|||||||
// ---- Helpers ----
|
// ---- Helpers ----
|
||||||
procedure BuildUI;
|
procedure BuildUI;
|
||||||
procedure ApplyDarkTheme;
|
procedure ApplyDarkTheme;
|
||||||
|
procedure SetLightTheme(V: Boolean);
|
||||||
procedure StyleButton(B: TFlatButton; Active: Boolean = False);
|
procedure StyleButton(B: TFlatButton; Active: Boolean = False);
|
||||||
procedure StyleSpanButton(B: TFlatButton; Active: Boolean = False);
|
procedure StyleSpanButton(B: TFlatButton; Active: Boolean = False);
|
||||||
procedure PositionSpanOverlayButtons;
|
procedure PositionSpanOverlayButtons;
|
||||||
@@ -845,6 +847,7 @@ begin
|
|||||||
Result.ShowSpectrum := FShowSpectrum;
|
Result.ShowSpectrum := FShowSpectrum;
|
||||||
Result.ShowWaterfall := FShowWaterfall;
|
Result.ShowWaterfall := FShowWaterfall;
|
||||||
Result.DisplayFPS := FDisplayFPS;
|
Result.DisplayFPS := FDisplayFPS;
|
||||||
|
Result.LightTheme := FLightTheme;
|
||||||
// Audio device names
|
// Audio device names
|
||||||
Result.AudioOutDevice := FAudioOutDevName;
|
Result.AudioOutDevice := FAudioOutDevName;
|
||||||
Result.AudioInDevice := FAudioInDevName;
|
Result.AudioInDevice := FAudioInDevName;
|
||||||
@@ -1053,6 +1056,7 @@ begin
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
FSettings.LoadCATSettings(FCATLastGlobal);
|
FSettings.LoadCATSettings(FCATLastGlobal);
|
||||||
|
FLightTheme := FSettings.LoadTheme;
|
||||||
InitCATEngine;
|
InitCATEngine;
|
||||||
CATApplySettings(FCATLastGlobal);
|
CATApplySettings(FCATLastGlobal);
|
||||||
FSMeterPeak := -130;
|
FSMeterPeak := -130;
|
||||||
@@ -2125,12 +2129,20 @@ end;
|
|||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
procedure TMainForm.ApplyDarkTheme;
|
procedure TMainForm.ApplyDarkTheme;
|
||||||
|
var T: TAppTheme; i: Integer;
|
||||||
procedure DP(P: TPanel);
|
procedure DP(P: TPanel);
|
||||||
|
begin P.Color := T.Panel; P.Font.Color := T.Text; 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);
|
||||||
begin
|
begin
|
||||||
P.Color := CLR_PANEL; P.Font.Color := CLR_TEXT;
|
S.SetThemeColors(T.SliderBG, T.SliderTrackEmpty, T.SliderTrackFill,
|
||||||
|
T.SliderThumbNorm, T.SliderThumbHot, T.SliderThumbDrag, T.SliderThumbBdr);
|
||||||
end;
|
end;
|
||||||
begin
|
begin
|
||||||
Color := CLR_BG; Font.Color := CLR_TEXT;
|
if FLightTheme then T := LightTheme else T := DarkTheme;
|
||||||
|
|
||||||
|
Color := T.BG; Font.Color := T.Text;
|
||||||
DP(PanelToolbar); DP(PanelLeft);
|
DP(PanelToolbar); DP(PanelLeft);
|
||||||
DP(PanelTopVfoGroup); DP(PanelTopVfoA); DP(PanelTopVfoB);
|
DP(PanelTopVfoGroup); DP(PanelTopVfoA); DP(PanelTopVfoB);
|
||||||
DP(PanelVfoA); DP(PanelVfoB); DP(PanelVfoButtons);
|
DP(PanelVfoA); DP(PanelVfoB); DP(PanelVfoButtons);
|
||||||
@@ -2138,38 +2150,107 @@ begin
|
|||||||
DP(PanelRX); DP(PanelTX);
|
DP(PanelRX); DP(PanelTX);
|
||||||
DP(PanelRight); DP(PanelSpanButtons);
|
DP(PanelRight); DP(PanelSpanButtons);
|
||||||
|
|
||||||
|
PbSpectrum.Color := T.BG;
|
||||||
|
PbWaterfall.Color := T.BG;
|
||||||
|
if PanelSMeterRight <> nil then PanelSMeterRight.Color := T.Panel;
|
||||||
|
if PbSMeterRight <> nil then PbSMeterRight.Color := T.Panel;
|
||||||
|
PbFwdPower.Color := T.BG;
|
||||||
|
PbSWR.Color := T.BG;
|
||||||
|
|
||||||
PbSpectrum.Color := CLR_BG;
|
// Метки
|
||||||
PbWaterfall.Color := CLR_BG;
|
DL(LblAGCTop, False);
|
||||||
if PanelSMeterRight <> nil then PanelSMeterRight.Color := CLR_PANEL;
|
DL(LblDrv); DL(LblSpan);
|
||||||
if PbSMeterRight <> nil then PbSMeterRight.Color := CLR_PANEL;
|
LblFwdPwr.Font.Color := T.MeterOn;
|
||||||
PbFwdPower.Color := CLR_BG;
|
LblSWRVal.Font.Color := T.TextDim;
|
||||||
PbSWR.Color := CLR_BG;
|
|
||||||
|
// Кнопки тулбара
|
||||||
|
BtnDiscover.ClrNorm := T.TbDiscoverNorm;
|
||||||
|
BtnDiscover.ClrHot := T.TbDiscoverHot;
|
||||||
|
BtnDiscover.ClrActive := T.TbDiscoverHot;
|
||||||
|
BtnDiscover.ClrBorder := T.TbDiscoverBorder;
|
||||||
|
BtnDiscover.ClrText := T.TbDiscoverText;
|
||||||
|
BtnDiscover.ClrTextAct := T.TbDiscoverText;
|
||||||
|
BtnDiscover.Invalidate;
|
||||||
|
BtnStartStop.ClrNorm := T.TbStartNorm;
|
||||||
|
BtnStartStop.ClrBorder := T.TbStartBorder;
|
||||||
|
BtnStartStop.ClrText := T.TbStartText;
|
||||||
|
BtnStartStop.Invalidate;
|
||||||
|
|
||||||
|
// Обычные кнопки — все массивы
|
||||||
|
for i := 0 to BAND_COUNT-1 do StyleButton(BtnBand[i], BtnBand[i].Active);
|
||||||
|
for i := 0 to MODE_COUNT-1 do StyleButton(BtnMode[i], BtnMode[i].Active);
|
||||||
|
for i := 0 to FILT_COUNT-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(BtnNR, BtnNR.Active);
|
||||||
|
StyleButton(BtnNB, BtnNB.Active);
|
||||||
|
StyleButton(BtnSNB, BtnSNB.Active);
|
||||||
|
StyleButton(BtnANF, BtnANF.Active);
|
||||||
|
StyleButton(BtnMute, BtnMute.Active);
|
||||||
|
StyleButton(BtnWfAGC, BtnWfAGC.Active);
|
||||||
|
StyleButton(BtnWfNF, BtnWfNF.Active);
|
||||||
|
StyleButton(BtnMOX, BtnMOX.Active);
|
||||||
|
|
||||||
|
// Span / VFO-copy / HidePanel
|
||||||
|
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(BtnVfoSwap, False);
|
||||||
|
StyleSpanButton(BtnVfoBCopyA, False);
|
||||||
|
if BtnHidePanel <> nil then StyleSpanButton(BtnHidePanel, False);
|
||||||
|
|
||||||
|
// Ползунки
|
||||||
|
DS(TrkAGC); DS(TrkVolume); DS(TrkDrive);
|
||||||
|
|
||||||
|
// Спектр
|
||||||
|
FSpecView.SetTheme(T);
|
||||||
|
|
||||||
|
// VFO display — вызывает UpdateVfoDisplay, который использует тему
|
||||||
|
UpdateVfoDisplay;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.SetLightTheme(V: Boolean);
|
||||||
|
begin
|
||||||
|
if FLightTheme = V then Exit;
|
||||||
|
FLightTheme := V;
|
||||||
|
ApplyDarkTheme;
|
||||||
|
FSettings.SaveTheme(V);
|
||||||
|
FSettings.Save;
|
||||||
|
if (FSettingsForm <> nil) and TSettingsForm(FSettingsForm).Visible then
|
||||||
|
TSettingsForm(FSettingsForm).LoadLightTheme(V);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.StyleButton(B: TFlatButton; Active: Boolean);
|
procedure TMainForm.StyleButton(B: TFlatButton; Active: Boolean);
|
||||||
|
var T: TAppTheme;
|
||||||
begin
|
begin
|
||||||
|
if FLightTheme then T := LightTheme else T := DarkTheme;
|
||||||
B.Active := Active;
|
B.Active := Active;
|
||||||
B.ClrNorm := CLR_INACTIVE;
|
B.ClrNorm := T.BtnNorm;
|
||||||
B.ClrActive := CLR_ACTIVE;
|
B.ClrActive := T.BtnActive;
|
||||||
B.ClrHot := TColor($00282828);
|
B.ClrHot := T.BtnHot;
|
||||||
if Active then B.ClrBorder := CLR_ACTIVE_BDR
|
if Active then B.ClrBorder := T.BtnBorderActive
|
||||||
else B.ClrBorder := TColor($00444444);
|
else B.ClrBorder := T.BtnBorderNorm;
|
||||||
B.ClrText := CLR_TEXT;
|
B.ClrText := T.BtnText;
|
||||||
B.ClrTextAct := TColor($0000FF88);
|
B.ClrTextAct := T.BtnTextActive;
|
||||||
B.Font.Name := 'Courier New';
|
B.Font.Name := 'Courier New';
|
||||||
B.Font.Size := 8;
|
B.Font.Size := 8;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.StyleSpanButton(B: TFlatButton; Active: Boolean);
|
procedure TMainForm.StyleSpanButton(B: TFlatButton; Active: Boolean);
|
||||||
|
var T: TAppTheme;
|
||||||
begin
|
begin
|
||||||
|
if FLightTheme then T := LightTheme else T := DarkTheme;
|
||||||
B.Active := Active;
|
B.Active := Active;
|
||||||
B.ClrNorm := TColor($00543F18);
|
B.ClrNorm := T.SpanNorm;
|
||||||
B.ClrActive := TColor($00624B1D);
|
B.ClrActive := T.SpanActive;
|
||||||
B.ClrHot := TColor($00624B1D);
|
B.ClrHot := T.SpanActive;
|
||||||
B.ClrBorder := TColor($00685624);
|
B.ClrBorder := T.SpanBorder;
|
||||||
B.ClrText := TColor($00D8E6EE);
|
B.ClrText := T.SpanText;
|
||||||
B.ClrTextAct := TColor($00F0FAFF);
|
B.ClrTextAct := T.SpanText;
|
||||||
B.Font.Name := 'Courier New';
|
B.Font.Name := 'Courier New';
|
||||||
B.Font.Size := 7;
|
B.Font.Size := 7;
|
||||||
end;
|
end;
|
||||||
@@ -2246,7 +2327,10 @@ end;
|
|||||||
procedure TMainForm.UpdateVfoDisplay;
|
procedure TMainForm.UpdateVfoDisplay;
|
||||||
const
|
const
|
||||||
TOP_VFO_FREQ_H = 47;
|
TOP_VFO_FREQ_H = 47;
|
||||||
|
var T: TAppTheme;
|
||||||
begin
|
begin
|
||||||
|
if FLightTheme then T := LightTheme else T := DarkTheme;
|
||||||
|
|
||||||
FreqDispA.Frequency := Round(FVfoA);
|
FreqDispA.Frequency := Round(FVfoA);
|
||||||
FreqDispB.Frequency := Round(FVfoB);
|
FreqDispB.Frequency := Round(FVfoB);
|
||||||
FreqDispA.FontSize := TOP_VFO_FONT;
|
FreqDispA.FontSize := TOP_VFO_FONT;
|
||||||
@@ -2256,56 +2340,52 @@ begin
|
|||||||
|
|
||||||
if FActiveVfo = 0 then
|
if FActiveVfo = 0 then
|
||||||
begin
|
begin
|
||||||
FreqDispA.ColorNormal := CLR_FREQ;
|
FreqDispA.ColorNormal := T.FreqActive;
|
||||||
FreqDispB.ColorNormal := CLR_FREQ_DIM;
|
FreqDispB.ColorNormal := T.FreqDim;
|
||||||
LblVfoALabel.Font.Color := CLR_FREQ;
|
LblVfoALabel.Font.Color := T.FreqActive;
|
||||||
LblVfoBLabel.Font.Color := CLR_TEXTDIM;
|
LblVfoBLabel.Font.Color := T.TextDim;
|
||||||
// Активный VFO-A: зелёный акцент
|
|
||||||
if BtnTopVfoASelect <> nil then begin
|
if BtnTopVfoASelect <> nil then begin
|
||||||
BtnTopVfoASelect.ClrNorm := TColor($00101C10);
|
BtnTopVfoASelect.ClrNorm := T.VfoSelActNorm;
|
||||||
BtnTopVfoASelect.ClrActive := TColor($00182818);
|
BtnTopVfoASelect.ClrActive := T.VfoSelActNorm;
|
||||||
BtnTopVfoASelect.ClrHot := TColor($00182818);
|
BtnTopVfoASelect.ClrHot := T.VfoSelActNorm;
|
||||||
BtnTopVfoASelect.ClrBorder := TColor($004A7A4A);
|
BtnTopVfoASelect.ClrBorder := T.VfoSelActBorder;
|
||||||
BtnTopVfoASelect.ClrText := TColor($0060B860);
|
BtnTopVfoASelect.ClrText := T.VfoSelActText;
|
||||||
BtnTopVfoASelect.ClrTextAct := TColor($0040FF60);
|
BtnTopVfoASelect.ClrTextAct := T.VfoSelActTextAct;
|
||||||
BtnTopVfoASelect.Active := True;
|
BtnTopVfoASelect.Active := True;
|
||||||
BtnTopVfoASelect.Invalidate;
|
BtnTopVfoASelect.Invalidate;
|
||||||
end;
|
end;
|
||||||
// Неактивный VFO-B: приглушённый
|
|
||||||
if BtnTopVfoBSelect <> nil then begin
|
if BtnTopVfoBSelect <> nil then begin
|
||||||
BtnTopVfoBSelect.ClrNorm := TColor($001A1A1A);
|
BtnTopVfoBSelect.ClrNorm := T.VfoSelInaNorm;
|
||||||
BtnTopVfoBSelect.ClrActive := TColor($00282828);
|
BtnTopVfoBSelect.ClrActive := T.VfoSelInaNorm;
|
||||||
BtnTopVfoBSelect.ClrHot := TColor($00252525);
|
BtnTopVfoBSelect.ClrHot := T.VfoSelInaNorm;
|
||||||
BtnTopVfoBSelect.ClrBorder := TColor($00404040);
|
BtnTopVfoBSelect.ClrBorder := T.VfoSelInaBorder;
|
||||||
BtnTopVfoBSelect.ClrText := CLR_TEXTDIM;
|
BtnTopVfoBSelect.ClrText := T.VfoSelInaText;
|
||||||
BtnTopVfoBSelect.ClrTextAct := CLR_TEXT;
|
BtnTopVfoBSelect.ClrTextAct := T.VfoSelInaTextAct;
|
||||||
BtnTopVfoBSelect.Active := False;
|
BtnTopVfoBSelect.Active := False;
|
||||||
BtnTopVfoBSelect.Invalidate;
|
BtnTopVfoBSelect.Invalidate;
|
||||||
end;
|
end;
|
||||||
end else begin
|
end else begin
|
||||||
FreqDispA.ColorNormal := CLR_FREQ_DIM;
|
FreqDispA.ColorNormal := T.FreqDim;
|
||||||
FreqDispB.ColorNormal := CLR_FREQ;
|
FreqDispB.ColorNormal := T.FreqActive;
|
||||||
LblVfoALabel.Font.Color := CLR_TEXTDIM;
|
LblVfoALabel.Font.Color := T.TextDim;
|
||||||
LblVfoBLabel.Font.Color := CLR_FREQ;
|
LblVfoBLabel.Font.Color := T.FreqActive;
|
||||||
// Неактивный VFO-A: приглушённый
|
|
||||||
if BtnTopVfoASelect <> nil then begin
|
if BtnTopVfoASelect <> nil then begin
|
||||||
BtnTopVfoASelect.ClrNorm := TColor($001A1A1A);
|
BtnTopVfoASelect.ClrNorm := T.VfoSelInaNorm;
|
||||||
BtnTopVfoASelect.ClrActive := TColor($00282828);
|
BtnTopVfoASelect.ClrActive := T.VfoSelInaNorm;
|
||||||
BtnTopVfoASelect.ClrHot := TColor($00252525);
|
BtnTopVfoASelect.ClrHot := T.VfoSelInaNorm;
|
||||||
BtnTopVfoASelect.ClrBorder := TColor($00404040);
|
BtnTopVfoASelect.ClrBorder := T.VfoSelInaBorder;
|
||||||
BtnTopVfoASelect.ClrText := CLR_TEXTDIM;
|
BtnTopVfoASelect.ClrText := T.VfoSelInaText;
|
||||||
BtnTopVfoASelect.ClrTextAct := CLR_TEXT;
|
BtnTopVfoASelect.ClrTextAct := T.VfoSelInaTextAct;
|
||||||
BtnTopVfoASelect.Active := False;
|
BtnTopVfoASelect.Active := False;
|
||||||
BtnTopVfoASelect.Invalidate;
|
BtnTopVfoASelect.Invalidate;
|
||||||
end;
|
end;
|
||||||
// Активный VFO-B: зелёный акцент
|
|
||||||
if BtnTopVfoBSelect <> nil then begin
|
if BtnTopVfoBSelect <> nil then begin
|
||||||
BtnTopVfoBSelect.ClrNorm := TColor($00101C10);
|
BtnTopVfoBSelect.ClrNorm := T.VfoSelActNorm;
|
||||||
BtnTopVfoBSelect.ClrActive := TColor($00182818);
|
BtnTopVfoBSelect.ClrActive := T.VfoSelActNorm;
|
||||||
BtnTopVfoBSelect.ClrHot := TColor($00182818);
|
BtnTopVfoBSelect.ClrHot := T.VfoSelActNorm;
|
||||||
BtnTopVfoBSelect.ClrBorder := TColor($004A7A4A);
|
BtnTopVfoBSelect.ClrBorder := T.VfoSelActBorder;
|
||||||
BtnTopVfoBSelect.ClrText := TColor($0060B860);
|
BtnTopVfoBSelect.ClrText := T.VfoSelActText;
|
||||||
BtnTopVfoBSelect.ClrTextAct := TColor($0040FF60);
|
BtnTopVfoBSelect.ClrTextAct := T.VfoSelActTextAct;
|
||||||
BtnTopVfoBSelect.Active := True;
|
BtnTopVfoBSelect.Active := True;
|
||||||
BtnTopVfoBSelect.Invalidate;
|
BtnTopVfoBSelect.Invalidate;
|
||||||
end;
|
end;
|
||||||
@@ -2314,22 +2394,22 @@ begin
|
|||||||
begin
|
begin
|
||||||
if not FSplitTxB then
|
if not FSplitTxB then
|
||||||
begin
|
begin
|
||||||
BtnTopVfoATX.ClrNorm := TColor($00000060);
|
BtnTopVfoATX.ClrNorm := T.VfoTxActNorm;
|
||||||
BtnTopVfoATX.ClrHot := TColor($00000090);
|
BtnTopVfoATX.ClrHot := T.VfoTxActNorm;
|
||||||
BtnTopVfoATX.ClrActive := TColor($00000090);
|
BtnTopVfoATX.ClrActive := T.VfoTxActNorm;
|
||||||
BtnTopVfoATX.ClrBorder := TColor($001010B0);
|
BtnTopVfoATX.ClrBorder := T.VfoTxActBorder;
|
||||||
BtnTopVfoATX.ClrText := TColor($00C8D8FF);
|
BtnTopVfoATX.ClrText := T.VfoTxActText;
|
||||||
BtnTopVfoATX.ClrTextAct := TColor($00E8F0FF);
|
BtnTopVfoATX.ClrTextAct := T.VfoTxActText;
|
||||||
BtnTopVfoATX.Active := True;
|
BtnTopVfoATX.Active := True;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
BtnTopVfoATX.ClrNorm := TColor($00303030);
|
BtnTopVfoATX.ClrNorm := T.VfoTxInaNorm;
|
||||||
BtnTopVfoATX.ClrHot := TColor($00404040);
|
BtnTopVfoATX.ClrHot := T.VfoTxInaNorm;
|
||||||
BtnTopVfoATX.ClrActive := TColor($00404040);
|
BtnTopVfoATX.ClrActive := T.VfoTxInaNorm;
|
||||||
BtnTopVfoATX.ClrBorder := TColor($00505050);
|
BtnTopVfoATX.ClrBorder := T.VfoTxInaBorder;
|
||||||
BtnTopVfoATX.ClrText := CLR_TEXTDIM;
|
BtnTopVfoATX.ClrText := T.VfoTxInaText;
|
||||||
BtnTopVfoATX.ClrTextAct := CLR_TEXT;
|
BtnTopVfoATX.ClrTextAct := T.VfoTxInaText;
|
||||||
BtnTopVfoATX.Active := False;
|
BtnTopVfoATX.Active := False;
|
||||||
end;
|
end;
|
||||||
BtnTopVfoATX.Invalidate;
|
BtnTopVfoATX.Invalidate;
|
||||||
@@ -2338,22 +2418,22 @@ begin
|
|||||||
begin
|
begin
|
||||||
if FSplitTxB then
|
if FSplitTxB then
|
||||||
begin
|
begin
|
||||||
BtnTopVfoBTX.ClrNorm := TColor($00000060);
|
BtnTopVfoBTX.ClrNorm := T.VfoTxActNorm;
|
||||||
BtnTopVfoBTX.ClrHot := TColor($00000090);
|
BtnTopVfoBTX.ClrHot := T.VfoTxActNorm;
|
||||||
BtnTopVfoBTX.ClrActive := TColor($00000090);
|
BtnTopVfoBTX.ClrActive := T.VfoTxActNorm;
|
||||||
BtnTopVfoBTX.ClrBorder := TColor($001010B0);
|
BtnTopVfoBTX.ClrBorder := T.VfoTxActBorder;
|
||||||
BtnTopVfoBTX.ClrText := TColor($00C8D8FF);
|
BtnTopVfoBTX.ClrText := T.VfoTxActText;
|
||||||
BtnTopVfoBTX.ClrTextAct := TColor($00E8F0FF);
|
BtnTopVfoBTX.ClrTextAct := T.VfoTxActText;
|
||||||
BtnTopVfoBTX.Active := True;
|
BtnTopVfoBTX.Active := True;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
BtnTopVfoBTX.ClrNorm := TColor($00303030);
|
BtnTopVfoBTX.ClrNorm := T.VfoTxInaNorm;
|
||||||
BtnTopVfoBTX.ClrHot := TColor($00404040);
|
BtnTopVfoBTX.ClrHot := T.VfoTxInaNorm;
|
||||||
BtnTopVfoBTX.ClrActive := TColor($00404040);
|
BtnTopVfoBTX.ClrActive := T.VfoTxInaNorm;
|
||||||
BtnTopVfoBTX.ClrBorder := TColor($00505050);
|
BtnTopVfoBTX.ClrBorder := T.VfoTxInaBorder;
|
||||||
BtnTopVfoBTX.ClrText := CLR_TEXTDIM;
|
BtnTopVfoBTX.ClrText := T.VfoTxInaText;
|
||||||
BtnTopVfoBTX.ClrTextAct := CLR_TEXT;
|
BtnTopVfoBTX.ClrTextAct := T.VfoTxInaText;
|
||||||
BtnTopVfoBTX.Active := False;
|
BtnTopVfoBTX.Active := False;
|
||||||
end;
|
end;
|
||||||
BtnTopVfoBTX.Invalidate;
|
BtnTopVfoBTX.Invalidate;
|
||||||
@@ -2907,6 +2987,8 @@ begin
|
|||||||
if not Assigned(FDeviceDialog) then
|
if not Assigned(FDeviceDialog) then
|
||||||
FDeviceDialog := TDeviceDialog.Create(Self);
|
FDeviceDialog := TDeviceDialog.Create(Self);
|
||||||
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
||||||
|
if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
|
||||||
|
else FDeviceDialog.SetTheme(DarkTheme);
|
||||||
FDeviceDialog.ShowModal;
|
FDeviceDialog.ShowModal;
|
||||||
// Результат диалога не обрабатываем здесь — START сам спросит если нужно
|
// Результат диалога не обрабатываем здесь — START сам спросит если нужно
|
||||||
end;
|
end;
|
||||||
@@ -2986,6 +3068,8 @@ begin
|
|||||||
if not Assigned(FDeviceDialog) then
|
if not Assigned(FDeviceDialog) then
|
||||||
FDeviceDialog := TDeviceDialog.Create(Self);
|
FDeviceDialog := TDeviceDialog.Create(Self);
|
||||||
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
|
||||||
|
if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
|
||||||
|
else FDeviceDialog.SetTheme(DarkTheme);
|
||||||
if FDeviceDialog.ShowModal <> mrOk then Exit;
|
if FDeviceDialog.ShowModal <> mrOk then Exit;
|
||||||
if not FDeviceDialog.DialogResult.Accepted then Exit;
|
if not FDeviceDialog.DialogResult.Accepted then Exit;
|
||||||
FPendingIP := FDeviceDialog.DialogResult.IPAddress;
|
FPendingIP := FDeviceDialog.DialogResult.IPAddress;
|
||||||
@@ -5016,6 +5100,7 @@ begin
|
|||||||
SF.OnFPSChange := ApplyFPS;
|
SF.OnFPSChange := ApplyFPS;
|
||||||
SF.OnPAChange := OnPASettingsChange;
|
SF.OnPAChange := OnPASettingsChange;
|
||||||
SF.OnCATChange := OnCATSettingsChange;
|
SF.OnCATChange := OnCATSettingsChange;
|
||||||
|
SF.OnThemeChange := SetLightTheme;
|
||||||
end;
|
end;
|
||||||
SF := TSettingsForm(FSettingsForm);
|
SF := TSettingsForm(FSettingsForm);
|
||||||
SF.LoadPASettings(FPAMaxPower, FPABandCal);
|
SF.LoadPASettings(FPAMaxPower, FPABandCal);
|
||||||
@@ -5032,6 +5117,7 @@ begin
|
|||||||
SF.RefreshAudioDevices(FAudioOut, FAudioIn);
|
SF.RefreshAudioDevices(FAudioOut, FAudioIn);
|
||||||
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
|
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
|
||||||
SF.LoadFPS(FDisplayFPS);
|
SF.LoadFPS(FDisplayFPS);
|
||||||
|
SF.LoadLightTheme(FLightTheme);
|
||||||
// Загружаем текущие значения
|
// Загружаем текущие значения
|
||||||
if FWDSPReady then
|
if FWDSPReady then
|
||||||
SF.LoadValues(
|
SF.LoadValues(
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ type
|
|||||||
ShowWaterfall: Boolean; // True = draw waterfall on main form
|
ShowWaterfall: Boolean; // True = draw waterfall on main form
|
||||||
// --- Display FPS ---
|
// --- Display FPS ---
|
||||||
DisplayFPS: Integer; // spectrum/waterfall timer fps (1..100)
|
DisplayFPS: Integer; // spectrum/waterfall timer fps (1..100)
|
||||||
|
// --- Theme ---
|
||||||
|
LightTheme: Boolean; // False = dark (default), True = light
|
||||||
// --- PA (Power Amplifier) settings ---
|
// --- PA (Power Amplifier) settings ---
|
||||||
PAMaxPower: Double; // максимальная выходная мощность, Вт (5..200)
|
PAMaxPower: Double; // максимальная выходная мощность, Вт (5..200)
|
||||||
PABandCal: array[0..CFG_BAND_COUNT-1] of Double; // калибровка на диапазон 38.8..100.0
|
PABandCal: array[0..CFG_BAND_COUNT-1] of Double; // калибровка на диапазон 38.8..100.0
|
||||||
@@ -128,6 +130,9 @@ type
|
|||||||
// CAT settings — не привязаны к MAC, хранятся в корне JSON (доступны до подключения)
|
// CAT settings — не привязаны к MAC, хранятся в корне JSON (доступны до подключения)
|
||||||
procedure SaveCATSettings(const G: TGlobalSettings);
|
procedure SaveCATSettings(const G: TGlobalSettings);
|
||||||
procedure LoadCATSettings(var G: TGlobalSettings);
|
procedure LoadCATSettings(var G: TGlobalSettings);
|
||||||
|
// Тема — глобальная настройка, не привязана к устройству
|
||||||
|
procedure SaveTheme(ALightTheme: Boolean);
|
||||||
|
function LoadTheme: Boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -413,6 +418,7 @@ begin
|
|||||||
G.ShowSpectrum := JB(GObj,'show_spectrum',True);
|
G.ShowSpectrum := JB(GObj,'show_spectrum',True);
|
||||||
G.ShowWaterfall := JB(GObj,'show_waterfall',True);
|
G.ShowWaterfall := JB(GObj,'show_waterfall',True);
|
||||||
G.DisplayFPS := JI(GObj,'display_fps',60);
|
G.DisplayFPS := JI(GObj,'display_fps',60);
|
||||||
|
G.LightTheme := JB(GObj,'light_theme',False);
|
||||||
// PA settings
|
// PA settings
|
||||||
G.PAMaxPower := JD(GObj,'pa_max_power',100.0);
|
G.PAMaxPower := JD(GObj,'pa_max_power',100.0);
|
||||||
for i := 0 to CFG_BAND_COUNT-1 do
|
for i := 0 to CFG_BAND_COUNT-1 do
|
||||||
@@ -489,6 +495,7 @@ begin
|
|||||||
JW(O,'show_spectrum',G.ShowSpectrum);
|
JW(O,'show_spectrum',G.ShowSpectrum);
|
||||||
JW(O,'show_waterfall',G.ShowWaterfall);
|
JW(O,'show_waterfall',G.ShowWaterfall);
|
||||||
JW(O,'display_fps',G.DisplayFPS);
|
JW(O,'display_fps',G.DisplayFPS);
|
||||||
|
JW(O,'light_theme',G.LightTheme);
|
||||||
// PA settings
|
// PA settings
|
||||||
JW(O,'pa_max_power',G.PAMaxPower);
|
JW(O,'pa_max_power',G.PAMaxPower);
|
||||||
for i := 0 to CFG_BAND_COUNT-1 do
|
for i := 0 to CFG_BAND_COUNT-1 do
|
||||||
@@ -621,4 +628,20 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSettingsManager.SaveTheme(ALightTheme: Boolean);
|
||||||
|
var O: TJSONObject;
|
||||||
|
begin
|
||||||
|
O := EnsureObj(FRoot, 'preferences');
|
||||||
|
JW(O, 'light_theme', ALightTheme);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TSettingsManager.LoadTheme: Boolean;
|
||||||
|
var O: TJSONObject;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
if FRoot.Find('preferences') = nil then Exit;
|
||||||
|
O := EnsureObj(FRoot, 'preferences');
|
||||||
|
Result := JB(O, 'light_theme', False);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
+101
-14
@@ -27,7 +27,7 @@ uses
|
|||||||
Classes, SysUtils, Math,
|
Classes, SysUtils, Math,
|
||||||
Forms, Controls, Graphics, Dialogs,
|
Forms, Controls, Graphics, Dialogs,
|
||||||
StdCtrls, ExtCtrls, Spin,
|
StdCtrls, ExtCtrls, Spin,
|
||||||
FlatButton, AudioOutput, AudioInput;
|
FlatButton, AudioOutput, AudioInput, AppTheme;
|
||||||
|
|
||||||
type
|
type
|
||||||
// PA: MaxPower в Вт, BandCal[0..10] — калибровка 38.8..100.0 на диапазон
|
// PA: MaxPower в Вт, BandCal[0..10] — калибровка 38.8..100.0 на диапазон
|
||||||
@@ -43,6 +43,7 @@ type
|
|||||||
TOnAudioInDevChange = procedure(DevIndex: Integer; const DevName: string) of object;
|
TOnAudioInDevChange = procedure(DevIndex: Integer; const DevName: string) of object;
|
||||||
TOnVisibilityChange = procedure(ShowSpectrum, ShowWaterfall: Boolean) of object;
|
TOnVisibilityChange = procedure(ShowSpectrum, ShowWaterfall: Boolean) of object;
|
||||||
TOnFPSChange = procedure(FPS: Integer) of object;
|
TOnFPSChange = procedure(FPS: Integer) of object;
|
||||||
|
TOnThemeChange = procedure(LightTheme: Boolean) of object;
|
||||||
TOnCATChange = procedure(
|
TOnCATChange = procedure(
|
||||||
const SerEnabled: array of Boolean;
|
const SerEnabled: array of Boolean;
|
||||||
const SerPort: array of string;
|
const SerPort: array of string;
|
||||||
@@ -101,6 +102,7 @@ type
|
|||||||
FChkShowSpectrum: TCheckBox;
|
FChkShowSpectrum: TCheckBox;
|
||||||
FChkShowWaterfall: TCheckBox;
|
FChkShowWaterfall: TCheckBox;
|
||||||
FCmbFPS: TComboBox;
|
FCmbFPS: TComboBox;
|
||||||
|
FChkLightTheme: TCheckBox;
|
||||||
|
|
||||||
// ---- PA Settings tab controls ----
|
// ---- PA Settings tab controls ----
|
||||||
FEdMaxPower: TSpinEdit;
|
FEdMaxPower: TSpinEdit;
|
||||||
@@ -129,6 +131,7 @@ type
|
|||||||
FOnAudioInDevChange: TOnAudioInDevChange;
|
FOnAudioInDevChange: TOnAudioInDevChange;
|
||||||
FOnVisibilityChange: TOnVisibilityChange;
|
FOnVisibilityChange: TOnVisibilityChange;
|
||||||
FOnFPSChange: TOnFPSChange;
|
FOnFPSChange: TOnFPSChange;
|
||||||
|
FOnThemeChange: TOnThemeChange;
|
||||||
|
|
||||||
FLoading: Boolean;
|
FLoading: Boolean;
|
||||||
|
|
||||||
@@ -138,7 +141,7 @@ type
|
|||||||
procedure BuildRX1Tab;
|
procedure BuildRX1Tab;
|
||||||
procedure BuildPATab;
|
procedure BuildPATab;
|
||||||
procedure BuildCATTab;
|
procedure BuildCATTab;
|
||||||
procedure ApplyTheme;
|
procedure ApplyTheme(const T: TAppTheme);
|
||||||
procedure NavClick(Sender: TObject);
|
procedure NavClick(Sender: TObject);
|
||||||
procedure SelectPage(APage: TWinControl; ANav: TFlatButton);
|
procedure SelectPage(APage: TWinControl; ANav: TFlatButton);
|
||||||
|
|
||||||
@@ -167,6 +170,7 @@ type
|
|||||||
procedure OnTXDevChange(Sender: TObject);
|
procedure OnTXDevChange(Sender: TObject);
|
||||||
procedure OnVisibilityChkChange(Sender: TObject);
|
procedure OnVisibilityChkChange(Sender: TObject);
|
||||||
procedure OnFPSCmbChange(Sender: TObject);
|
procedure OnFPSCmbChange(Sender: TObject);
|
||||||
|
procedure OnLightThemeChkChange(Sender: TObject);
|
||||||
procedure OnMaxPowerChange(Sender: TObject);
|
procedure OnMaxPowerChange(Sender: TObject);
|
||||||
procedure OnBandCalChange(Sender: TObject);
|
procedure OnBandCalChange(Sender: TObject);
|
||||||
procedure OnCATSerialChange(Sender: TObject);
|
procedure OnCATSerialChange(Sender: TObject);
|
||||||
@@ -203,6 +207,7 @@ type
|
|||||||
procedure RefreshAudioDevices(AudioOut: TAudioOutput; AudioIn: TAudioInput);
|
procedure RefreshAudioDevices(AudioOut: TAudioOutput; AudioIn: TAudioInput);
|
||||||
procedure LoadVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
procedure LoadVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
||||||
procedure LoadFPS(FPS: Integer);
|
procedure LoadFPS(FPS: Integer);
|
||||||
|
procedure LoadLightTheme(ALight: Boolean);
|
||||||
procedure LoadPASettings(MaxPower: Double; const BandCal: array of Double);
|
procedure LoadPASettings(MaxPower: Double; const BandCal: array of Double);
|
||||||
procedure LoadCATSettings(
|
procedure LoadCATSettings(
|
||||||
const SerEnabled: array of Boolean;
|
const SerEnabled: array of Boolean;
|
||||||
@@ -219,6 +224,7 @@ type
|
|||||||
property OnAudioInDevChange: TOnAudioInDevChange read FOnAudioInDevChange write FOnAudioInDevChange;
|
property OnAudioInDevChange: TOnAudioInDevChange read FOnAudioInDevChange write FOnAudioInDevChange;
|
||||||
property OnVisibilityChange: TOnVisibilityChange read FOnVisibilityChange write FOnVisibilityChange;
|
property OnVisibilityChange: TOnVisibilityChange read FOnVisibilityChange write FOnVisibilityChange;
|
||||||
property OnFPSChange: TOnFPSChange read FOnFPSChange write FOnFPSChange;
|
property OnFPSChange: TOnFPSChange read FOnFPSChange write FOnFPSChange;
|
||||||
|
property OnThemeChange: TOnThemeChange read FOnThemeChange write FOnThemeChange;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -287,7 +293,7 @@ begin
|
|||||||
FLoading := False;
|
FLoading := False;
|
||||||
FRXDevCount := 0;
|
FRXDevCount := 0;
|
||||||
BuildUI;
|
BuildUI;
|
||||||
ApplyTheme;
|
ApplyTheme(DarkTheme);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -611,6 +617,18 @@ begin
|
|||||||
for i := 0 to High(FPS_NAMES) do
|
for i := 0 to High(FPS_NAMES) do
|
||||||
FCmbFPS.Items.Add(FPS_NAMES[i]);
|
FCmbFPS.Items.Add(FPS_NAMES[i]);
|
||||||
FCmbFPS.ItemIndex := 8;
|
FCmbFPS.ItemIndex := 8;
|
||||||
|
|
||||||
|
Grp := MakeGroupPanel(FPageDisplay, 'Appearance', MARGIN, 292, 650, 68);
|
||||||
|
|
||||||
|
FChkLightTheme := TCheckBox.Create(Self);
|
||||||
|
FChkLightTheme.Parent := Grp;
|
||||||
|
FChkLightTheme.Caption := 'Light theme';
|
||||||
|
FChkLightTheme.SetBounds(PAD, R1, CHKW, 22);
|
||||||
|
FChkLightTheme.Checked := False;
|
||||||
|
FChkLightTheme.Font.Color := CLR_TEXT;
|
||||||
|
FChkLightTheme.Font.Name := UI_FONT;
|
||||||
|
FChkLightTheme.Font.Size := 9;
|
||||||
|
FChkLightTheme.OnChange := OnLightThemeChkChange;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -888,18 +906,66 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSettingsForm.ApplyTheme;
|
procedure TSettingsForm.ApplyTheme(const T: TAppTheme);
|
||||||
|
|
||||||
|
procedure StyleBtn(B: TFlatButton);
|
||||||
|
begin
|
||||||
|
B.ClrNorm := T.Panel;
|
||||||
|
B.ClrBorder := T.Panel;
|
||||||
|
B.ClrHot := T.BG;
|
||||||
|
B.ClrActive := T.Panel;
|
||||||
|
B.ClrText := T.Text;
|
||||||
|
B.ClrTextAct := T.FreqActive;
|
||||||
|
B.Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure WalkControls(C: TWinControl);
|
||||||
|
var i: Integer; Ctrl: TControl;
|
||||||
|
begin
|
||||||
|
for i := 0 to C.ControlCount - 1 do
|
||||||
|
begin
|
||||||
|
Ctrl := C.Controls[i];
|
||||||
|
if Ctrl is TFlatButton then
|
||||||
|
StyleBtn(TFlatButton(Ctrl))
|
||||||
|
else if Ctrl is TScrollBox then
|
||||||
|
begin
|
||||||
|
TScrollBox(Ctrl).Color := T.BG;
|
||||||
|
WalkControls(TScrollBox(Ctrl));
|
||||||
|
end
|
||||||
|
else if Ctrl is TPanel then
|
||||||
|
begin
|
||||||
|
if TPanel(Ctrl).Height = 1 then
|
||||||
|
TPanel(Ctrl).Color := T.Border
|
||||||
|
else
|
||||||
|
TPanel(Ctrl).Color := T.Panel;
|
||||||
|
WalkControls(TPanel(Ctrl));
|
||||||
|
end
|
||||||
|
else if Ctrl is TLabel then
|
||||||
|
begin
|
||||||
|
if Ctrl.Font.Size >= 12 then
|
||||||
|
TLabel(Ctrl).Font.Color := T.Text
|
||||||
|
else if fsBold in Ctrl.Font.Style then
|
||||||
|
TLabel(Ctrl).Font.Color := T.FreqActive
|
||||||
|
else
|
||||||
|
TLabel(Ctrl).Font.Color := T.TextDim;
|
||||||
|
end
|
||||||
|
else if Ctrl is TCheckBox then
|
||||||
|
TCheckBox(Ctrl).Font.Color := T.Text
|
||||||
|
else if Ctrl is TListBox then
|
||||||
|
begin
|
||||||
|
TListBox(Ctrl).Color := T.BG;
|
||||||
|
TListBox(Ctrl).Font.Color := T.Text;
|
||||||
|
end
|
||||||
|
else if Ctrl is TWinControl then
|
||||||
|
WalkControls(TWinControl(Ctrl));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Color := CLR_BG;
|
Color := T.BG;
|
||||||
if Assigned(FNavPanel) then FNavPanel.Color := TColor($00151515);
|
Font.Color := T.Text;
|
||||||
if Assigned(FContentPanel) then FContentPanel.Color := CLR_BG;
|
WalkControls(Self);
|
||||||
if Assigned(FPageAudio) then FPageAudio.Color := CLR_BG;
|
Invalidate;
|
||||||
if Assigned(FPageDisplay) then FPageDisplay.Color := CLR_BG;
|
|
||||||
if Assigned(FPageSpectrum) then FPageSpectrum.Color := CLR_BG;
|
|
||||||
if Assigned(FPageWaterfall) then FPageWaterfall.Color := CLR_BG;
|
|
||||||
if Assigned(FPagePA) then FPagePA.Color := CLR_BG;
|
|
||||||
if Assigned(FPageAdvanced) then FPageAdvanced.Color := CLR_BG;
|
|
||||||
if Assigned(FPageCAT) then FPageCAT.Color := CLR_BG;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -1265,6 +1331,15 @@ begin
|
|||||||
FOnVisibilityChange(FChkShowSpectrum.Checked, FChkShowWaterfall.Checked);
|
FOnVisibilityChange(FChkShowSpectrum.Checked, FChkShowWaterfall.Checked);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSettingsForm.OnLightThemeChkChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
if FLoading then Exit;
|
||||||
|
if FChkLightTheme.Checked then ApplyTheme(LightTheme)
|
||||||
|
else ApplyTheme(DarkTheme);
|
||||||
|
if Assigned(FOnThemeChange) then
|
||||||
|
FOnThemeChange(FChkLightTheme.Checked);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSettingsForm.OnFPSCmbChange(Sender: TObject);
|
procedure TSettingsForm.OnFPSCmbChange(Sender: TObject);
|
||||||
var
|
var
|
||||||
Idx: Integer;
|
Idx: Integer;
|
||||||
@@ -1291,6 +1366,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSettingsForm.LoadLightTheme(ALight: Boolean);
|
||||||
|
begin
|
||||||
|
FLoading := True;
|
||||||
|
try
|
||||||
|
FChkLightTheme.Checked := ALight;
|
||||||
|
finally
|
||||||
|
FLoading := False;
|
||||||
|
end;
|
||||||
|
if ALight then ApplyTheme(LightTheme)
|
||||||
|
else ApplyTheme(DarkTheme);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSettingsForm.LoadPASettings(MaxPower: Double;
|
procedure TSettingsForm.LoadPASettings(MaxPower: Double;
|
||||||
const BandCal: array of Double);
|
const BandCal: array of Double);
|
||||||
var i, n: Integer;
|
var i, n: Integer;
|
||||||
|
|||||||
+69
-44
@@ -18,7 +18,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
|
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
|
||||||
IntfGraphics, FPImage, LCLIntf, LCLType, GraphType;
|
IntfGraphics, FPImage, LCLIntf, LCLType, GraphType, AppTheme;
|
||||||
|
|
||||||
const
|
const
|
||||||
SV_CLR_BG = TColor($00101010);
|
SV_CLR_BG = TColor($00101010);
|
||||||
@@ -44,6 +44,9 @@ type
|
|||||||
FWfIntfImg: TLazIntfImage;
|
FWfIntfImg: TLazIntfImage;
|
||||||
FWfPixels: array of LongWord;
|
FWfPixels: array of LongWord;
|
||||||
FSpPts: array of TPoint;
|
FSpPts: array of TPoint;
|
||||||
|
// ── Тема ─────────────────────────────────────────────────────────────────
|
||||||
|
FTheme: TAppTheme;
|
||||||
|
FLightTheme: Boolean;
|
||||||
FSpPtsLen: Integer;
|
FSpPtsLen: Integer;
|
||||||
FSmBitmap: TBitmap;
|
FSmBitmap: TBitmap;
|
||||||
FRulerLastFreq: Double;
|
FRulerLastFreq: Double;
|
||||||
@@ -197,6 +200,8 @@ type
|
|||||||
|
|
||||||
// ── Утилиты ───────────────────────────────────────────────────────────────
|
// ── Утилиты ───────────────────────────────────────────────────────────────
|
||||||
procedure InvalidateGridCache;
|
procedure InvalidateGridCache;
|
||||||
|
// ── Тема ─────────────────────────────────────────────────────────────────
|
||||||
|
procedure SetTheme(const T: TAppTheme);
|
||||||
procedure InvalidateRulerCache;
|
procedure InvalidateRulerCache;
|
||||||
procedure ResetSpectrumBuf;
|
procedure ResetSpectrumBuf;
|
||||||
procedure ResetWfAvgBuf;
|
procedure ResetWfAvgBuf;
|
||||||
@@ -360,6 +365,8 @@ begin
|
|||||||
FWaterfallDirty := True;
|
FWaterfallDirty := True;
|
||||||
FLastSMeter := -130; FSMeterPeak := -130; FSMeterMin := -130;
|
FLastSMeter := -130; FSMeterPeak := -130; FSMeterMin := -130;
|
||||||
FLastFwdW := 0; FLastSWR := 1;
|
FLastFwdW := 0; FLastSWR := 1;
|
||||||
|
FLightTheme := False;
|
||||||
|
FTheme := DarkTheme;
|
||||||
ResetSpectrumBuf;
|
ResetSpectrumBuf;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -439,14 +446,17 @@ begin
|
|||||||
Alpha := Round((1.0 - Sqr((Row - YMin) / Max(1.0, H - YMin - 1.0))) * 200);
|
Alpha := Round((1.0 - Sqr((Row - YMin) / Max(1.0, H - YMin - 1.0))) * 200);
|
||||||
if Alpha <= 0 then Continue;
|
if Alpha <= 0 then Continue;
|
||||||
if Alpha > 200 then Alpha := 200;
|
if Alpha > 200 then Alpha := 200;
|
||||||
GG := Byte(Alpha shr 1); RG := Byte(Alpha);
|
GG := Byte(FTheme.SpecGradB * Alpha div 200);
|
||||||
|
RG := Byte(FTheme.SpecGradG * Alpha div 200);
|
||||||
RowPtr := FSpecGradImg.GetDataLineStart(Row);
|
RowPtr := FSpecGradImg.GetDataLineStart(Row);
|
||||||
if RowPtr = nil then Continue;
|
if RowPtr = nil then Continue;
|
||||||
for Col := 0 to W - 1 do
|
for Col := 0 to W - 1 do
|
||||||
begin
|
begin
|
||||||
if SpPts[Col].Y <= Row then
|
if SpPts[Col].Y <= Row then
|
||||||
begin
|
begin
|
||||||
RowPtr[0] := GG; RowPtr[1] := RG; RowPtr[2] := 0;
|
RowPtr[0] := GG;
|
||||||
|
RowPtr[1] := RG;
|
||||||
|
RowPtr[2] := Byte(FTheme.SpecGradR * Alpha div 200);
|
||||||
if BPPg >= 4 then RowPtr[3] := Byte(Alpha);
|
if BPPg >= 4 then RowPtr[3] := Byte(Alpha);
|
||||||
end else begin
|
end else begin
|
||||||
RowPtr[0] := 0; RowPtr[1] := 0; RowPtr[2] := 0;
|
RowPtr[0] := 0; RowPtr[1] := 0; RowPtr[2] := 0;
|
||||||
@@ -495,7 +505,7 @@ procedure TSpectrumView.SetSpectrumBitmapSize(W, H: Integer);
|
|||||||
begin
|
begin
|
||||||
if (W <= 0) or (H <= 0) then Exit;
|
if (W <= 0) or (H <= 0) then Exit;
|
||||||
FSpectrumBitmap.SetSize(W, H);
|
FSpectrumBitmap.SetSize(W, H);
|
||||||
FSpectrumBitmap.Canvas.Brush.Color := SV_CLR_BG;
|
FSpectrumBitmap.Canvas.Brush.Color := FTheme.BG;
|
||||||
FSpectrumBitmap.Canvas.FillRect(Rect(0, 0, W, H));
|
FSpectrumBitmap.Canvas.FillRect(Rect(0, 0, W, H));
|
||||||
FreeAndNil(FSpecGradImg);
|
FreeAndNil(FSpecGradImg);
|
||||||
InvalidateGridCache;
|
InvalidateGridCache;
|
||||||
@@ -532,6 +542,16 @@ begin
|
|||||||
FSpectrumDirty := True;
|
FSpectrumDirty := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpectrumView.SetTheme(const T: TAppTheme);
|
||||||
|
begin
|
||||||
|
FTheme := T;
|
||||||
|
FLightTheme := T.BG > TColor($00808080); // светлая тема если фон светлее 50%
|
||||||
|
FreeAndNil(FSpecGradImg); // пересчитать градиент
|
||||||
|
InvalidateGridCache;
|
||||||
|
InvalidateRulerCache;
|
||||||
|
FWaterfallDirty := True;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpectrumView.InvalidateRulerCache;
|
procedure TSpectrumView.InvalidateRulerCache;
|
||||||
begin
|
begin
|
||||||
FRulerLastFreq := -1.0; FRulerLastVfo := -1.0; FRulerLastSpan := -1.0;
|
FRulerLastFreq := -1.0; FRulerLastVfo := -1.0; FRulerLastSpan := -1.0;
|
||||||
@@ -606,20 +626,20 @@ begin
|
|||||||
FGridBitmapW := W; FGridBitmapH := H;
|
FGridBitmapW := W; FGridBitmapH := H;
|
||||||
FGridBitmap.SetSize(W, H);
|
FGridBitmap.SetSize(W, H);
|
||||||
GC := FGridBitmap.Canvas;
|
GC := FGridBitmap.Canvas;
|
||||||
PaintVerticalGradient(GC, W, H, TColor($0020160B), TColor($006C4F1F));
|
PaintVerticalGradient(GC, W, H, FTheme.SpecGradTop, FTheme.SpecGradBot);
|
||||||
LabelBandW := 28;
|
LabelBandW := 28;
|
||||||
GC.Pen.Style := psClear; GC.Brush.Style := bsSolid;
|
GC.Pen.Style := psClear; GC.Brush.Style := bsSolid;
|
||||||
GC.Brush.Color := TColor($00543F18);
|
GC.Brush.Color := FTheme.SpecLabelBand;
|
||||||
GC.FillRect(Rect(0, 0, LabelBandW, H));
|
GC.FillRect(Rect(0, 0, LabelBandW, H));
|
||||||
GC.Pen.Style := psSolid;
|
GC.Pen.Style := psSolid;
|
||||||
GC.Font.Size := 7; GC.Font.Name := 'Courier New';
|
GC.Font.Size := 7; GC.Font.Name := 'Courier New';
|
||||||
GC.Font.Color := TColor($00A8C9D9);
|
GC.Font.Color := FTheme.SpecLabelText;
|
||||||
GC.Brush.Style := bsClear;
|
GC.Brush.Style := bsClear;
|
||||||
dB := DBmax - FSpecGridStep;
|
dB := DBmax - FSpecGridStep;
|
||||||
while dB >= DBmin do
|
while dB >= DBmin do
|
||||||
begin
|
begin
|
||||||
Yp := Round((DBmax - dB) * InvRange * H);
|
Yp := Round((DBmax - dB) * InvRange * H);
|
||||||
GC.Pen.Color := TColor($00685624); GC.Pen.Width := 1;
|
GC.Pen.Color := FTheme.SpecGrid; GC.Pen.Width := 1;
|
||||||
GC.MoveTo(0, Yp); GC.LineTo(W-1, Yp);
|
GC.MoveTo(0, Yp); GC.LineTo(W-1, Yp);
|
||||||
GC.TextOut(1, Yp - 9, Format('%4.0f', [dB]));
|
GC.TextOut(1, Yp - 9, Format('%4.0f', [dB]));
|
||||||
dB := dB - FSpecGridStep;
|
dB := dB - FSpecGridStep;
|
||||||
@@ -627,7 +647,7 @@ begin
|
|||||||
for i := 0 to 8 do
|
for i := 0 to 8 do
|
||||||
begin
|
begin
|
||||||
GX := ScaleX(i, 8, W);
|
GX := ScaleX(i, 8, W);
|
||||||
GC.Pen.Color := TColor($00685624);
|
GC.Pen.Color := FTheme.SpecGrid;
|
||||||
GC.MoveTo(GX, 0); GC.LineTo(GX, H);
|
GC.MoveTo(GX, 0); GC.LineTo(GX, H);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -646,7 +666,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
X1 := Max(0, Min(W-1, VfoX + Round(Lo_Hz / FSpanHz * W)));
|
X1 := Max(0, Min(W-1, VfoX + Round(Lo_Hz / FSpanHz * W)));
|
||||||
X2 := Max(0, Min(W-1, VfoX + Round(Hi_Hz / FSpanHz * W)));
|
X2 := Max(0, Min(W-1, VfoX + Round(Hi_Hz / FSpanHz * W)));
|
||||||
C.Brush.Color := TColor($006A4E22); C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
C.Brush.Color := FTheme.SpecFilter; C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
||||||
if X2 > X1 then C.FillRect(Rect(X1, 0, X2, H));
|
if X2 > X1 then C.FillRect(Rect(X1, 0, X2, H));
|
||||||
C.Pen.Style := psSolid;
|
C.Pen.Style := psSolid;
|
||||||
|
|
||||||
@@ -656,26 +676,26 @@ begin
|
|||||||
AGCy := Round((DBmax - FAGCThresh) * InvRange * H);
|
AGCy := Round((DBmax - FAGCThresh) * InvRange * H);
|
||||||
if (AGCy >= 0) and (AGCy < H) then
|
if (AGCy >= 0) and (AGCy < H) then
|
||||||
begin
|
begin
|
||||||
C.Pen.Color := TColor($0000AAFF); C.Pen.Width := 1; C.Pen.Style := psDash;
|
C.Pen.Color := FTheme.SpecAgcColor; C.Pen.Width := 1; C.Pen.Style := psDash;
|
||||||
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
||||||
C.Pen.Style := psSolid; C.Font.Color := TColor($0000AAFF); C.Font.Size := 6;
|
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcColor; C.Font.Size := 6;
|
||||||
C.TextOut(4, AGCy - 9, 'AGC T');
|
C.TextOut(4, AGCy - 9, 'AGC T');
|
||||||
end;
|
end;
|
||||||
AGCHangY := Round((DBmax - FAGCHangLevel) * InvRange * H);
|
AGCHangY := Round((DBmax - FAGCHangLevel) * InvRange * H);
|
||||||
if (AGCHangY >= 0) and (AGCHangY < H) and (Abs(AGCHangY - AGCy) > 4) then
|
if (AGCHangY >= 0) and (AGCHangY < H) and (Abs(AGCHangY - AGCy) > 4) then
|
||||||
begin
|
begin
|
||||||
C.Pen.Color := TColor($00FFCC00); C.Pen.Width := 1; C.Pen.Style := psDot;
|
C.Pen.Color := FTheme.SpecAgcHangColor; C.Pen.Width := 1; C.Pen.Style := psDot;
|
||||||
C.MoveTo(0, AGCHangY); C.LineTo(W, AGCHangY);
|
C.MoveTo(0, AGCHangY); C.LineTo(W, AGCHangY);
|
||||||
C.Pen.Style := psSolid; C.Font.Color := TColor($00FFCC00); C.Font.Size := 6;
|
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcHangColor; C.Font.Size := 6;
|
||||||
C.TextOut(4, AGCHangY + 2, 'AGC H');
|
C.TextOut(4, AGCHangY + 2, 'AGC H');
|
||||||
end;
|
end;
|
||||||
end else begin
|
end else begin
|
||||||
AGCy := Round((DBmax - (-FAGCTop)) * InvRange * H);
|
AGCy := Round((DBmax - (-FAGCTop)) * InvRange * H);
|
||||||
if (AGCy >= 0) and (AGCy < H) then
|
if (AGCy >= 0) and (AGCy < H) then
|
||||||
begin
|
begin
|
||||||
C.Pen.Color := TColor($0000AAFF); C.Pen.Width := 1; C.Pen.Style := psDash;
|
C.Pen.Color := FTheme.SpecAgcColor; C.Pen.Width := 1; C.Pen.Style := psDash;
|
||||||
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
C.MoveTo(0, AGCy); C.LineTo(W, AGCy);
|
||||||
C.Pen.Style := psSolid; C.Font.Color := TColor($0000AAFF); C.Font.Size := 6;
|
C.Pen.Style := psSolid; C.Font.Color := FTheme.SpecAgcColor; C.Font.Size := 6;
|
||||||
C.TextOut(4, AGCy - 9, Format('AGC -%ddB', [FAGCTop]));
|
C.TextOut(4, AGCy - 9, Format('AGC -%ddB', [FAGCTop]));
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -700,16 +720,16 @@ begin
|
|||||||
DrawSpectrumGradient(FSpPts, W, H);
|
DrawSpectrumGradient(FSpPts, W, H);
|
||||||
|
|
||||||
// ── 6. Линия спектра ──────────────────────────────────────────────────────
|
// ── 6. Линия спектра ──────────────────────────────────────────────────────
|
||||||
C.Pen.Style := psSolid; C.Pen.Color := TColor($0040FF80); C.Pen.Width := 1;
|
C.Pen.Style := psSolid; C.Pen.Color := FTheme.SpecLine; C.Pen.Width := 1;
|
||||||
C.Polyline(Slice(FSpPts, W));
|
C.Polyline(Slice(FSpPts, W));
|
||||||
|
|
||||||
// ── 7. Края фильтра + VFO ─────────────────────────────────────────────────
|
// ── 7. Края фильтра + VFO ─────────────────────────────────────────────────
|
||||||
C.Pen.Color := TColor($0040FFCC); C.Pen.Width := 1; C.Pen.Style := psSolid;
|
C.Pen.Color := FTheme.SpecFilterEdge; C.Pen.Width := 1; C.Pen.Style := psSolid;
|
||||||
C.MoveTo(X1, 0); C.LineTo(X1, H);
|
C.MoveTo(X1, 0); C.LineTo(X1, H);
|
||||||
C.MoveTo(X2, 0); C.LineTo(X2, H);
|
C.MoveTo(X2, 0); C.LineTo(X2, H);
|
||||||
C.Pen.Color := TColor($0000AAFF); C.Pen.Width := 2;
|
C.Pen.Color := FTheme.SpecVfoCursor; C.Pen.Width := 2;
|
||||||
C.MoveTo(VfoX, 0); C.LineTo(VfoX, H - 12);
|
C.MoveTo(VfoX, 0); C.LineTo(VfoX, H - 12);
|
||||||
C.Brush.Color := TColor($0000AAFF); C.Brush.Style := bsSolid; C.Pen.Width := 1;
|
C.Brush.Color := FTheme.SpecVfoCursor; C.Brush.Style := bsSolid; C.Pen.Width := 1;
|
||||||
C.Polygon([Point(VfoX-5,0), Point(VfoX+5,0), Point(VfoX,8)]);
|
C.Polygon([Point(VfoX-5,0), Point(VfoX+5,0), Point(VfoX,8)]);
|
||||||
|
|
||||||
if FMarkerActive then DrawMarkerLine(C, W, H);
|
if FMarkerActive then DrawMarkerLine(C, W, H);
|
||||||
@@ -862,8 +882,8 @@ begin
|
|||||||
if (FRulerBitmap.Width <> W) or (FRulerBitmap.Height <> H) then
|
if (FRulerBitmap.Width <> W) or (FRulerBitmap.Height <> H) then
|
||||||
FRulerBitmap.SetSize(W, H);
|
FRulerBitmap.SetSize(W, H);
|
||||||
C := FRulerBitmap.Canvas;
|
C := FRulerBitmap.Canvas;
|
||||||
PaintVerticalGradient(C, W, H, TColor($00372A12), TColor($00705A2A));
|
PaintVerticalGradient(C, W, H, FTheme.RulerGradTop, FTheme.RulerGradBot);
|
||||||
C.Pen.Color := TColor($00685624); C.Pen.Width := 1;
|
C.Pen.Color := FTheme.RulerBorder; C.Pen.Width := 1;
|
||||||
C.MoveTo(0, 0); C.LineTo(W, 0);
|
C.MoveTo(0, 0); C.LineTo(W, 0);
|
||||||
C.MoveTo(0, H-1); C.LineTo(W, H-1);
|
C.MoveTo(0, H-1); C.LineTo(W, H-1);
|
||||||
C.Font.Name := 'Courier New'; C.Font.Size := 7;
|
C.Font.Name := 'Courier New'; C.Font.Size := 7;
|
||||||
@@ -872,18 +892,18 @@ begin
|
|||||||
for i := 0 to 8 do
|
for i := 0 to 8 do
|
||||||
begin
|
begin
|
||||||
X := ScaleX(i, 8, W);
|
X := ScaleX(i, 8, W);
|
||||||
C.Pen.Color := TColor($00685624);
|
C.Pen.Color := FTheme.RulerBorder;
|
||||||
C.MoveTo(X, 0); C.LineTo(X, H div 2);
|
C.MoveTo(X, 0); C.LineTo(X, H div 2);
|
||||||
FreqHz := FreqStart + i * FSpanHz / 8;
|
FreqHz := FreqStart + i * FSpanHz / 8;
|
||||||
Lbl := Format('%.3f', [FreqHz / 1e6]);
|
Lbl := Format('%.3f', [FreqHz / 1e6]);
|
||||||
TW := C.TextWidth(Lbl);
|
TW := C.TextWidth(Lbl);
|
||||||
C.Font.Color := TColor($00C8D8E2);
|
C.Font.Color := FTheme.RulerText;
|
||||||
C.TextOut(X - TW div 2, H div 2 - 1, Lbl);
|
C.TextOut(X - TW div 2, H div 2 - 1, Lbl);
|
||||||
end;
|
end;
|
||||||
VfoX := Round((ActiveVfoFreq - FCenterFreq + FSpanHz/2) / FSpanHz * W);
|
VfoX := Round((ActiveVfoFreq - FCenterFreq + FSpanHz/2) / FSpanHz * W);
|
||||||
if (VfoX >= 0) and (VfoX < W) then
|
if (VfoX >= 0) and (VfoX < W) then
|
||||||
begin
|
begin
|
||||||
C.Pen.Color := TColor($0000FF80); C.Pen.Width := 2;
|
C.Pen.Color := FTheme.RulerVfo; C.Pen.Width := 2;
|
||||||
C.MoveTo(VfoX, 0); C.LineTo(VfoX, H - 1); C.Pen.Width := 1;
|
C.MoveTo(VfoX, 0); C.LineTo(VfoX, H - 1); C.Pen.Width := 1;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -896,7 +916,7 @@ procedure TSpectrumView.DrawBarMeter(ACanvas: TCanvas; R: TRect;
|
|||||||
Value, MaxVal: Double; BarColor: TColor);
|
Value, MaxVal: Double; BarColor: TColor);
|
||||||
var Pct, BarW: Integer;
|
var Pct, BarW: Integer;
|
||||||
begin
|
begin
|
||||||
ACanvas.Brush.Color := TColor($00080808);
|
ACanvas.Brush.Color := FTheme.SMeterBG;
|
||||||
ACanvas.FillRect(R);
|
ACanvas.FillRect(R);
|
||||||
if MaxVal > 0 then
|
if MaxVal > 0 then
|
||||||
Pct := Round(Max(0.0, Min(1.0, Value / MaxVal)) * (R.Right - R.Left - 2))
|
Pct := Round(Max(0.0, Min(1.0, Value / MaxVal)) * (R.Right - R.Left - 2))
|
||||||
@@ -918,22 +938,13 @@ const
|
|||||||
DBM_LABELS: array[0..5] of string = ('-120','-100','-80','-60','-40','-20');
|
DBM_LABELS: array[0..5] of string = ('-120','-100','-80','-60','-40','-20');
|
||||||
S_MARKS_DBM: array[0..7] of Double = (-121,-109,-97,-85,-73,-53,-33,-13);
|
S_MARKS_DBM: array[0..7] of Double = (-121,-109,-97,-85,-73,-53,-33,-13);
|
||||||
S_MARKS_LBL: array[0..7] of string = ('S1','S3','S5','S7','S9','+20','+40','+60');
|
S_MARKS_LBL: array[0..7] of string = ('S1','S3','S5','S7','S9','+20','+40','+60');
|
||||||
CLR_SMETER_BG = TColor($00181818);
|
|
||||||
CLR_BAR_GREEN = TColor($00091F00);
|
|
||||||
CLR_BAR_OVER = TColor($00091528);
|
|
||||||
CLR_PEAK_MARKER = TColor($00F8F8FF);
|
|
||||||
CLR_TICK_GREEN = TColor($00708070);
|
|
||||||
CLR_TICK_WHITE = TColor($00E0E0DC);
|
|
||||||
CLR_TICK_BLUE = TColor($0070A090);
|
|
||||||
CLR_LABEL_DBM = TColor($0096D8DC);
|
|
||||||
CLR_LABEL_S = TColor($00F0F0F0);
|
|
||||||
CLR_SCALE_DBM = TColor($00D0DCDC);
|
|
||||||
CLR_SCALE_S_GREEN = TColor($00E0E0E0);
|
|
||||||
CLR_SCALE_S_BLUE = TColor($0090D090);
|
|
||||||
CLR_BDR = TColor($00303028);
|
|
||||||
LEFT_INFO_MIN = 62; RIGHT_PAD = 8; LABEL_PAD = 4;
|
LEFT_INFO_MIN = 62; RIGHT_PAD = 8; LABEL_PAD = 4;
|
||||||
TICK_LONG = 5; TICK_MED = 3;
|
TICK_LONG = 5; TICK_MED = 3;
|
||||||
var
|
var
|
||||||
|
CLR_SMETER_BG, CLR_BAR_GREEN, CLR_BAR_OVER: TColor;
|
||||||
|
CLR_PEAK_MARKER, CLR_TICK_GREEN, CLR_TICK_WHITE, CLR_TICK_BLUE: TColor;
|
||||||
|
CLR_LABEL_DBM, CLR_LABEL_S, CLR_SCALE_DBM: TColor;
|
||||||
|
CLR_SCALE_S_GREEN, CLR_SCALE_S_BLUE, CLR_BDR: TColor;
|
||||||
W, H, BX, BW, LeftInfo: Integer;
|
W, H, BX, BW, LeftInfo: Integer;
|
||||||
Y_BAR_TOP, Y_BAR_BOT: Integer;
|
Y_BAR_TOP, Y_BAR_BOT: Integer;
|
||||||
BarEnd, PeakLeft, PeakRight, S9X, OvrX: Integer;
|
BarEnd, PeakLeft, PeakRight, S9X, OvrX: Integer;
|
||||||
@@ -960,6 +971,20 @@ var
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
CLR_SMETER_BG := FTheme.SMeterBG;
|
||||||
|
CLR_BAR_GREEN := FTheme.SMeterBarGreen;
|
||||||
|
CLR_BAR_OVER := FTheme.SMeterBarOver;
|
||||||
|
CLR_PEAK_MARKER := FTheme.SMeterPeakMarker;
|
||||||
|
CLR_TICK_GREEN := FTheme.SMeterTickGreen;
|
||||||
|
CLR_TICK_WHITE := FTheme.SMeterTickWhite;
|
||||||
|
CLR_TICK_BLUE := FTheme.SMeterTickBlue;
|
||||||
|
CLR_LABEL_DBM := FTheme.SMeterLabelDbm;
|
||||||
|
CLR_LABEL_S := FTheme.SMeterLabelS;
|
||||||
|
CLR_SCALE_DBM := FTheme.SMeterScaleDbm;
|
||||||
|
CLR_SCALE_S_GREEN:= FTheme.SMeterScaleSGreen;
|
||||||
|
CLR_SCALE_S_BLUE := FTheme.SMeterScaleSBlue;
|
||||||
|
CLR_BDR := FTheme.SMeterBdr;
|
||||||
|
|
||||||
W := R.Right - R.Left; H := R.Bottom - R.Top;
|
W := R.Right - R.Left; H := R.Bottom - R.Top;
|
||||||
ZX1 := 0; ZX2 := 0; ZY1 := 0; ZY2 := 0;
|
ZX1 := 0; ZX2 := 0; ZY1 := 0; ZY2 := 0;
|
||||||
if (W < 80) or (H < 16) then Exit;
|
if (W < 80) or (H < 16) then Exit;
|
||||||
@@ -997,9 +1022,9 @@ begin
|
|||||||
|
|
||||||
ACanvas.Brush.Color := CLR_SMETER_BG; ACanvas.Brush.Style := bsSolid;
|
ACanvas.Brush.Color := CLR_SMETER_BG; ACanvas.Brush.Style := bsSolid;
|
||||||
ACanvas.Pen.Style := psClear; ACanvas.FillRect(R); ACanvas.Pen.Style := psSolid;
|
ACanvas.Pen.Style := psClear; ACanvas.FillRect(R); ACanvas.Pen.Style := psSolid;
|
||||||
FillBar(BX, Y_BAR_TOP, S9X, Y_BAR_BOT, TColor($00061006));
|
FillBar(BX, Y_BAR_TOP, S9X, Y_BAR_BOT, CLR_BAR_GREEN);
|
||||||
FillBar(S9X, Y_BAR_TOP, OvrX, Y_BAR_BOT, TColor($000A1006));
|
FillBar(S9X, Y_BAR_TOP, OvrX, Y_BAR_BOT, CLR_BAR_GREEN);
|
||||||
FillBar(OvrX, Y_BAR_TOP, BX + BW, Y_BAR_BOT, TColor($00060A10));
|
FillBar(OvrX, Y_BAR_TOP, BX + BW, Y_BAR_BOT, CLR_BAR_OVER);
|
||||||
|
|
||||||
BarEnd := DBtoX(Value);
|
BarEnd := DBtoX(Value);
|
||||||
PeakLeft := DBtoX(MinVal);
|
PeakLeft := DBtoX(MinVal);
|
||||||
@@ -1029,7 +1054,7 @@ begin
|
|||||||
ACanvas.Brush.Style := bsClear; ACanvas.Pen.Color := CLR_BDR;
|
ACanvas.Brush.Style := bsClear; ACanvas.Pen.Color := CLR_BDR;
|
||||||
ACanvas.Rectangle(LblZoneL, Y_BAR_TOP, BX + BW, Y_BAR_BOT);
|
ACanvas.Rectangle(LblZoneL, Y_BAR_TOP, BX + BW, Y_BAR_BOT);
|
||||||
// разделитель между зоной надписей и шкалой
|
// разделитель между зоной надписей и шкалой
|
||||||
ACanvas.Pen.Color := TColor($00404040);
|
ACanvas.Pen.Color := FTheme.SMeterDivider;
|
||||||
ACanvas.MoveTo(BX, Y_BAR_TOP + 1); ACanvas.LineTo(BX, Y_BAR_BOT - 1);
|
ACanvas.MoveTo(BX, Y_BAR_TOP + 1); ACanvas.LineTo(BX, Y_BAR_BOT - 1);
|
||||||
|
|
||||||
// --- Шкальные тики и надписи ---
|
// --- Шкальные тики и надписи ---
|
||||||
@@ -1066,7 +1091,7 @@ begin
|
|||||||
// "-85.3" над "dBm", снизу прижаты к верхнему краю полосы
|
// "-85.3" над "dBm", снизу прижаты к верхнему краю полосы
|
||||||
ACanvas.Font.Size := 10; ACanvas.Font.Style := [fsBold]; ACanvas.Font.Color := CLR_LABEL_DBM;
|
ACanvas.Font.Size := 10; ACanvas.Font.Style := [fsBold]; ACanvas.Font.Color := CLR_LABEL_DBM;
|
||||||
ACanvas.TextOut(LblZoneL + 4, Y_BAR_TOP - TH10 - 2, LblDbm);
|
ACanvas.TextOut(LblZoneL + 4, Y_BAR_TOP - TH10 - 2, LblDbm);
|
||||||
ACanvas.Font.Size := 6; ACanvas.Font.Style := []; ACanvas.Font.Color := TColor($00507070);
|
ACanvas.Font.Size := 6; ACanvas.Font.Style := []; ACanvas.Font.Color := CLR_TICK_BLUE;
|
||||||
ACanvas.TextOut(LblZoneL + 4 + TWDbm + 2, Y_BAR_TOP - TH6 - 4, 'dBm');
|
ACanvas.TextOut(LblZoneL + 4 + TWDbm + 2, Y_BAR_TOP - TH6 - 4, 'dBm');
|
||||||
// S-значение под полосой, левый край у LblZoneL+4
|
// S-значение под полосой, левый край у LblZoneL+4
|
||||||
ACanvas.Font.Size := 10; ACanvas.Font.Style := [fsBold]; ACanvas.Font.Color := CLR_LABEL_S;
|
ACanvas.Font.Size := 10; ACanvas.Font.Style := [fsBold]; ACanvas.Font.Color := CLR_LABEL_S;
|
||||||
|
|||||||
@@ -115,6 +115,10 @@
|
|||||||
<Filename Value="FlatButton.pas"/>
|
<Filename Value="FlatButton.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
</Unit>
|
</Unit>
|
||||||
|
<Unit>
|
||||||
|
<Filename Value="AppTheme.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit>
|
||||||
<Unit>
|
<Unit>
|
||||||
<Filename Value="FlatSlider.pas"/>
|
<Filename Value="FlatSlider.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user