diff --git a/AppTheme.pas b/AppTheme.pas
new file mode 100644
index 0000000..0e512e4
--- /dev/null
+++ b/AppTheme.pas
@@ -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.
diff --git a/DeviceForm.pas b/DeviceForm.pas
index c32cc85..1fbaa33 100644
--- a/DeviceForm.pas
+++ b/DeviceForm.pas
@@ -5,7 +5,7 @@ unit DeviceForm;
interface
uses
- Classes, SysUtils, FlatButton, Forms, Controls, Graphics, Dialogs,
+ Classes, SysUtils, FlatButton, AppTheme, Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, ComCtrls, IniFiles;
// Декодирование типа платы (совпадает с MainForm.BoardTypeName)
@@ -94,6 +94,8 @@ type
public
constructor Create(AOwner: TComponent); override;
+ procedure SetTheme(const T: TAppTheme);
+
// Добавить найденное устройство (вызывается из MainForm при discovery)
procedure AddDiscovered(const IP, DisplayName: string; BoardType: Integer = 0);
procedure ClearDiscovered;
@@ -271,7 +273,69 @@ end;
procedure TDeviceDialog.ApplyTheme;
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;
procedure TDeviceDialog.LoadSaved;
diff --git a/FlatSlider.pas b/FlatSlider.pas
index 9df066b..28fa5e1 100644
--- a/FlatSlider.pas
+++ b/FlatSlider.pas
@@ -1,7 +1,8 @@
unit FlatSlider;
-{ Кастомный горизонтальный ползунок с тёмной темой — замена TTrackBar.
- Полностью отрисован через Canvas, одинаково выглядит на Windows и Linux. }
+{ Кастомный горизонтальный ползунок — замена TTrackBar.
+ Полностью отрисован через Canvas, одинаково выглядит на Windows и Linux.
+ Цвета настраиваемые: применяй SetThemeColors(T: TAppTheme) для смены темы. }
{$mode objfpc}{$H+}
@@ -20,6 +21,14 @@ type
FDragging: Boolean;
FHot: Boolean;
FOnChange: TNotifyEvent;
+ // Цвета (настраиваются через SetThemeColors или напрямую)
+ FClrBG: TColor;
+ FClrTrackEmpty: TColor;
+ FClrTrackFill: TColor;
+ FClrThumbNorm: TColor;
+ FClrThumbHot: TColor;
+ FClrThumbDrag: TColor;
+ FClrThumbBdr: TColor;
procedure SetPosition(V: Integer);
procedure SetMin(V: Integer);
procedure SetMax(V: Integer);
@@ -39,6 +48,11 @@ type
public
constructor Create(AOwner: TComponent); override;
+ // Применить набор цветов из темы
+ procedure SetThemeColors(
+ ABG, ATrackEmpty, ATrackFill,
+ AThumbNorm, AThumbHot, AThumbDrag, AThumbBdr: TColor);
+
property Min: Integer read FMin write SetMin;
property Max: Integer read FMax write SetMax;
property Position: Integer read FPosition write SetPosition;
@@ -51,17 +65,9 @@ type
implementation
const
- THUMB_R = 6; // радиус ручки (px)
- TRACK_H = 4; // высота рельса (px)
- 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);
+ THUMB_R = 6;
+ TRACK_H = 4;
+ PAD = THUMB_R + 2;
constructor TFlatSlider.Create(AOwner: TComponent);
begin
@@ -73,11 +79,32 @@ begin
FDragging := False;
FHot := False;
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;
procedure TFlatSlider.SetPosition(V: Integer);
-var
- C: Integer;
+var C: Integer;
begin
C := EnsureRange(V, FMin, FMax);
if FPosition = C then Exit;
@@ -102,10 +129,8 @@ begin
Invalidate;
end;
-// Позиция значения → пиксельная X-координата ручки
function TFlatSlider.PosToX(APos: Integer): Integer;
-var
- Range, TrackW: Integer;
+var Range, TrackW: Integer;
begin
Range := FMax - FMin;
TrackW := Width - PAD * 2;
@@ -116,10 +141,8 @@ begin
Result := PAD + Round((APos - FMin) / Range * TrackW);
end;
-// Пиксельная X-координата → значение позиции
function TFlatSlider.XToPos(AX: Integer): Integer;
-var
- Range, TrackW, RawX: Integer;
+var Range, TrackW, RawX: Integer;
begin
Range := FMax - FMin;
TrackW := Width - PAD * 2;
@@ -141,32 +164,29 @@ begin
CY := Height div 2;
TX := PosToX(FPosition);
- Canvas.Brush.Color := CLR_BG;
+ Canvas.Brush.Color := FClrBG;
Canvas.Brush.Style := bsSolid;
Canvas.Pen.Style := psClear;
Canvas.FillRect(ClientRect);
- // Рельс — весь
TR := Rect(PAD, CY - TRACK_H 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);
- // Рельс — заполненная часть
if not FReversed then begin FL := PAD; FR := TX; end
else begin FL := TX; FR := Width - PAD; end;
if FR > FL then
begin
- Canvas.Brush.Color := CLR_TRACK_FILL;
+ Canvas.Brush.Color := FClrTrackFill;
Canvas.RoundRect(FL, TR.Top, FR, TR.Bottom, TRACK_H, TRACK_H);
end;
- // Ручка — круг
- if FDragging then ThC := CLR_THUMB_DRAG
- else if FHot then ThC := CLR_THUMB_HOT
- else ThC := CLR_THUMB_NORM;
+ if FDragging then ThC := FClrThumbDrag
+ else if FHot then ThC := FClrThumbHot
+ else ThC := FClrThumbNorm;
Canvas.Brush.Color := ThC;
- Canvas.Pen.Color := CLR_THUMB_BDR;
+ Canvas.Pen.Color := FClrThumbBdr;
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 1;
Canvas.Ellipse(TX - THUMB_R, CY - THUMB_R,
diff --git a/MainForm.pas b/MainForm.pas
index 391b0ab..3a05929 100644
--- a/MainForm.pas
+++ b/MainForm.pas
@@ -22,7 +22,7 @@ unit MainForm;
interface
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,
LCLIntf, LCLType, GraphType,
HPSDRProtocol, HPSDRNetwork,
@@ -249,6 +249,7 @@ type
FPendingDev: THPSDRDevice; // устройство ожидающее открытия WDSP
FBandCache: array[0..CFG_BAND_COUNT-1] of TBandSettings; // кэш диапазонов
FDevConnected: Boolean; // True после первого подключения
+ FLightTheme: Boolean; // True = светлая тема
FCenterFreq: Double; // центр спектра = LO (DDC). При CTUN ON не меняется при кручении VFO
FSpanHz: Double;
FSampleRate: Integer; // текущий DDC sample rate (Hz)
@@ -345,6 +346,7 @@ type
// ---- Helpers ----
procedure BuildUI;
procedure ApplyDarkTheme;
+ procedure SetLightTheme(V: Boolean);
procedure StyleButton(B: TFlatButton; Active: Boolean = False);
procedure StyleSpanButton(B: TFlatButton; Active: Boolean = False);
procedure PositionSpanOverlayButtons;
@@ -845,6 +847,7 @@ begin
Result.ShowSpectrum := FShowSpectrum;
Result.ShowWaterfall := FShowWaterfall;
Result.DisplayFPS := FDisplayFPS;
+ Result.LightTheme := FLightTheme;
// Audio device names
Result.AudioOutDevice := FAudioOutDevName;
Result.AudioInDevice := FAudioInDevName;
@@ -1053,6 +1056,7 @@ begin
{$ENDIF}
end;
FSettings.LoadCATSettings(FCATLastGlobal);
+ FLightTheme := FSettings.LoadTheme;
InitCATEngine;
CATApplySettings(FCATLastGlobal);
FSMeterPeak := -130;
@@ -2125,12 +2129,20 @@ end;
// ===========================================================================
procedure TMainForm.ApplyDarkTheme;
+var T: TAppTheme; i: Integer;
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
- 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;
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(PanelTopVfoGroup); DP(PanelTopVfoA); DP(PanelTopVfoB);
DP(PanelVfoA); DP(PanelVfoB); DP(PanelVfoButtons);
@@ -2138,38 +2150,107 @@ begin
DP(PanelRX); DP(PanelTX);
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;
- if PanelSMeterRight <> nil then PanelSMeterRight.Color := CLR_PANEL;
- if PbSMeterRight <> nil then PbSMeterRight.Color := CLR_PANEL;
- PbFwdPower.Color := CLR_BG;
- PbSWR.Color := CLR_BG;
+ // Метки
+ DL(LblAGCTop, False);
+ DL(LblDrv); DL(LblSpan);
+ LblFwdPwr.Font.Color := T.MeterOn;
+ LblSWRVal.Font.Color := T.TextDim;
+
+ // Кнопки тулбара
+ 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;
procedure TMainForm.StyleButton(B: TFlatButton; Active: Boolean);
+var T: TAppTheme;
begin
+ if FLightTheme then T := LightTheme else T := DarkTheme;
B.Active := Active;
- B.ClrNorm := CLR_INACTIVE;
- B.ClrActive := CLR_ACTIVE;
- B.ClrHot := TColor($00282828);
- if Active then B.ClrBorder := CLR_ACTIVE_BDR
- else B.ClrBorder := TColor($00444444);
- B.ClrText := CLR_TEXT;
- B.ClrTextAct := TColor($0000FF88);
+ B.ClrNorm := T.BtnNorm;
+ B.ClrActive := T.BtnActive;
+ B.ClrHot := T.BtnHot;
+ if Active then B.ClrBorder := T.BtnBorderActive
+ else B.ClrBorder := T.BtnBorderNorm;
+ B.ClrText := T.BtnText;
+ B.ClrTextAct := T.BtnTextActive;
B.Font.Name := 'Courier New';
B.Font.Size := 8;
end;
procedure TMainForm.StyleSpanButton(B: TFlatButton; Active: Boolean);
+var T: TAppTheme;
begin
+ if FLightTheme then T := LightTheme else T := DarkTheme;
B.Active := Active;
- B.ClrNorm := TColor($00543F18);
- B.ClrActive := TColor($00624B1D);
- B.ClrHot := TColor($00624B1D);
- B.ClrBorder := TColor($00685624);
- B.ClrText := TColor($00D8E6EE);
- B.ClrTextAct := TColor($00F0FAFF);
+ B.ClrNorm := T.SpanNorm;
+ B.ClrActive := T.SpanActive;
+ B.ClrHot := T.SpanActive;
+ B.ClrBorder := T.SpanBorder;
+ B.ClrText := T.SpanText;
+ B.ClrTextAct := T.SpanText;
B.Font.Name := 'Courier New';
B.Font.Size := 7;
end;
@@ -2246,7 +2327,10 @@ end;
procedure TMainForm.UpdateVfoDisplay;
const
TOP_VFO_FREQ_H = 47;
+var T: TAppTheme;
begin
+ if FLightTheme then T := LightTheme else T := DarkTheme;
+
FreqDispA.Frequency := Round(FVfoA);
FreqDispB.Frequency := Round(FVfoB);
FreqDispA.FontSize := TOP_VFO_FONT;
@@ -2256,56 +2340,52 @@ begin
if FActiveVfo = 0 then
begin
- FreqDispA.ColorNormal := CLR_FREQ;
- FreqDispB.ColorNormal := CLR_FREQ_DIM;
- LblVfoALabel.Font.Color := CLR_FREQ;
- LblVfoBLabel.Font.Color := CLR_TEXTDIM;
- // Активный VFO-A: зелёный акцент
+ FreqDispA.ColorNormal := T.FreqActive;
+ FreqDispB.ColorNormal := T.FreqDim;
+ LblVfoALabel.Font.Color := T.FreqActive;
+ LblVfoBLabel.Font.Color := T.TextDim;
if BtnTopVfoASelect <> nil then begin
- BtnTopVfoASelect.ClrNorm := TColor($00101C10);
- BtnTopVfoASelect.ClrActive := TColor($00182818);
- BtnTopVfoASelect.ClrHot := TColor($00182818);
- BtnTopVfoASelect.ClrBorder := TColor($004A7A4A);
- BtnTopVfoASelect.ClrText := TColor($0060B860);
- BtnTopVfoASelect.ClrTextAct := TColor($0040FF60);
+ BtnTopVfoASelect.ClrNorm := T.VfoSelActNorm;
+ BtnTopVfoASelect.ClrActive := T.VfoSelActNorm;
+ BtnTopVfoASelect.ClrHot := T.VfoSelActNorm;
+ BtnTopVfoASelect.ClrBorder := T.VfoSelActBorder;
+ BtnTopVfoASelect.ClrText := T.VfoSelActText;
+ BtnTopVfoASelect.ClrTextAct := T.VfoSelActTextAct;
BtnTopVfoASelect.Active := True;
BtnTopVfoASelect.Invalidate;
end;
- // Неактивный VFO-B: приглушённый
if BtnTopVfoBSelect <> nil then begin
- BtnTopVfoBSelect.ClrNorm := TColor($001A1A1A);
- BtnTopVfoBSelect.ClrActive := TColor($00282828);
- BtnTopVfoBSelect.ClrHot := TColor($00252525);
- BtnTopVfoBSelect.ClrBorder := TColor($00404040);
- BtnTopVfoBSelect.ClrText := CLR_TEXTDIM;
- BtnTopVfoBSelect.ClrTextAct := CLR_TEXT;
+ BtnTopVfoBSelect.ClrNorm := T.VfoSelInaNorm;
+ BtnTopVfoBSelect.ClrActive := T.VfoSelInaNorm;
+ BtnTopVfoBSelect.ClrHot := T.VfoSelInaNorm;
+ BtnTopVfoBSelect.ClrBorder := T.VfoSelInaBorder;
+ BtnTopVfoBSelect.ClrText := T.VfoSelInaText;
+ BtnTopVfoBSelect.ClrTextAct := T.VfoSelInaTextAct;
BtnTopVfoBSelect.Active := False;
BtnTopVfoBSelect.Invalidate;
end;
end else begin
- FreqDispA.ColorNormal := CLR_FREQ_DIM;
- FreqDispB.ColorNormal := CLR_FREQ;
- LblVfoALabel.Font.Color := CLR_TEXTDIM;
- LblVfoBLabel.Font.Color := CLR_FREQ;
- // Неактивный VFO-A: приглушённый
+ FreqDispA.ColorNormal := T.FreqDim;
+ FreqDispB.ColorNormal := T.FreqActive;
+ LblVfoALabel.Font.Color := T.TextDim;
+ LblVfoBLabel.Font.Color := T.FreqActive;
if BtnTopVfoASelect <> nil then begin
- BtnTopVfoASelect.ClrNorm := TColor($001A1A1A);
- BtnTopVfoASelect.ClrActive := TColor($00282828);
- BtnTopVfoASelect.ClrHot := TColor($00252525);
- BtnTopVfoASelect.ClrBorder := TColor($00404040);
- BtnTopVfoASelect.ClrText := CLR_TEXTDIM;
- BtnTopVfoASelect.ClrTextAct := CLR_TEXT;
+ BtnTopVfoASelect.ClrNorm := T.VfoSelInaNorm;
+ BtnTopVfoASelect.ClrActive := T.VfoSelInaNorm;
+ BtnTopVfoASelect.ClrHot := T.VfoSelInaNorm;
+ BtnTopVfoASelect.ClrBorder := T.VfoSelInaBorder;
+ BtnTopVfoASelect.ClrText := T.VfoSelInaText;
+ BtnTopVfoASelect.ClrTextAct := T.VfoSelInaTextAct;
BtnTopVfoASelect.Active := False;
BtnTopVfoASelect.Invalidate;
end;
- // Активный VFO-B: зелёный акцент
if BtnTopVfoBSelect <> nil then begin
- BtnTopVfoBSelect.ClrNorm := TColor($00101C10);
- BtnTopVfoBSelect.ClrActive := TColor($00182818);
- BtnTopVfoBSelect.ClrHot := TColor($00182818);
- BtnTopVfoBSelect.ClrBorder := TColor($004A7A4A);
- BtnTopVfoBSelect.ClrText := TColor($0060B860);
- BtnTopVfoBSelect.ClrTextAct := TColor($0040FF60);
+ BtnTopVfoBSelect.ClrNorm := T.VfoSelActNorm;
+ BtnTopVfoBSelect.ClrActive := T.VfoSelActNorm;
+ BtnTopVfoBSelect.ClrHot := T.VfoSelActNorm;
+ BtnTopVfoBSelect.ClrBorder := T.VfoSelActBorder;
+ BtnTopVfoBSelect.ClrText := T.VfoSelActText;
+ BtnTopVfoBSelect.ClrTextAct := T.VfoSelActTextAct;
BtnTopVfoBSelect.Active := True;
BtnTopVfoBSelect.Invalidate;
end;
@@ -2314,22 +2394,22 @@ begin
begin
if not FSplitTxB then
begin
- BtnTopVfoATX.ClrNorm := TColor($00000060);
- BtnTopVfoATX.ClrHot := TColor($00000090);
- BtnTopVfoATX.ClrActive := TColor($00000090);
- BtnTopVfoATX.ClrBorder := TColor($001010B0);
- BtnTopVfoATX.ClrText := TColor($00C8D8FF);
- BtnTopVfoATX.ClrTextAct := TColor($00E8F0FF);
+ BtnTopVfoATX.ClrNorm := T.VfoTxActNorm;
+ BtnTopVfoATX.ClrHot := T.VfoTxActNorm;
+ BtnTopVfoATX.ClrActive := T.VfoTxActNorm;
+ BtnTopVfoATX.ClrBorder := T.VfoTxActBorder;
+ BtnTopVfoATX.ClrText := T.VfoTxActText;
+ BtnTopVfoATX.ClrTextAct := T.VfoTxActText;
BtnTopVfoATX.Active := True;
end
else
begin
- BtnTopVfoATX.ClrNorm := TColor($00303030);
- BtnTopVfoATX.ClrHot := TColor($00404040);
- BtnTopVfoATX.ClrActive := TColor($00404040);
- BtnTopVfoATX.ClrBorder := TColor($00505050);
- BtnTopVfoATX.ClrText := CLR_TEXTDIM;
- BtnTopVfoATX.ClrTextAct := CLR_TEXT;
+ BtnTopVfoATX.ClrNorm := T.VfoTxInaNorm;
+ BtnTopVfoATX.ClrHot := T.VfoTxInaNorm;
+ BtnTopVfoATX.ClrActive := T.VfoTxInaNorm;
+ BtnTopVfoATX.ClrBorder := T.VfoTxInaBorder;
+ BtnTopVfoATX.ClrText := T.VfoTxInaText;
+ BtnTopVfoATX.ClrTextAct := T.VfoTxInaText;
BtnTopVfoATX.Active := False;
end;
BtnTopVfoATX.Invalidate;
@@ -2338,22 +2418,22 @@ begin
begin
if FSplitTxB then
begin
- BtnTopVfoBTX.ClrNorm := TColor($00000060);
- BtnTopVfoBTX.ClrHot := TColor($00000090);
- BtnTopVfoBTX.ClrActive := TColor($00000090);
- BtnTopVfoBTX.ClrBorder := TColor($001010B0);
- BtnTopVfoBTX.ClrText := TColor($00C8D8FF);
- BtnTopVfoBTX.ClrTextAct := TColor($00E8F0FF);
+ BtnTopVfoBTX.ClrNorm := T.VfoTxActNorm;
+ BtnTopVfoBTX.ClrHot := T.VfoTxActNorm;
+ BtnTopVfoBTX.ClrActive := T.VfoTxActNorm;
+ BtnTopVfoBTX.ClrBorder := T.VfoTxActBorder;
+ BtnTopVfoBTX.ClrText := T.VfoTxActText;
+ BtnTopVfoBTX.ClrTextAct := T.VfoTxActText;
BtnTopVfoBTX.Active := True;
end
else
begin
- BtnTopVfoBTX.ClrNorm := TColor($00303030);
- BtnTopVfoBTX.ClrHot := TColor($00404040);
- BtnTopVfoBTX.ClrActive := TColor($00404040);
- BtnTopVfoBTX.ClrBorder := TColor($00505050);
- BtnTopVfoBTX.ClrText := CLR_TEXTDIM;
- BtnTopVfoBTX.ClrTextAct := CLR_TEXT;
+ BtnTopVfoBTX.ClrNorm := T.VfoTxInaNorm;
+ BtnTopVfoBTX.ClrHot := T.VfoTxInaNorm;
+ BtnTopVfoBTX.ClrActive := T.VfoTxInaNorm;
+ BtnTopVfoBTX.ClrBorder := T.VfoTxInaBorder;
+ BtnTopVfoBTX.ClrText := T.VfoTxInaText;
+ BtnTopVfoBTX.ClrTextAct := T.VfoTxInaText;
BtnTopVfoBTX.Active := False;
end;
BtnTopVfoBTX.Invalidate;
@@ -2907,6 +2987,8 @@ begin
if not Assigned(FDeviceDialog) then
FDeviceDialog := TDeviceDialog.Create(Self);
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
+ if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
+ else FDeviceDialog.SetTheme(DarkTheme);
FDeviceDialog.ShowModal;
// Результат диалога не обрабатываем здесь — START сам спросит если нужно
end;
@@ -2986,6 +3068,8 @@ begin
if not Assigned(FDeviceDialog) then
FDeviceDialog := TDeviceDialog.Create(Self);
FDeviceDialog.OnDiscover := BtnDiscoverFromDialog;
+ if FLightTheme then FDeviceDialog.SetTheme(LightTheme)
+ else FDeviceDialog.SetTheme(DarkTheme);
if FDeviceDialog.ShowModal <> mrOk then Exit;
if not FDeviceDialog.DialogResult.Accepted then Exit;
FPendingIP := FDeviceDialog.DialogResult.IPAddress;
@@ -5016,6 +5100,7 @@ begin
SF.OnFPSChange := ApplyFPS;
SF.OnPAChange := OnPASettingsChange;
SF.OnCATChange := OnCATSettingsChange;
+ SF.OnThemeChange := SetLightTheme;
end;
SF := TSettingsForm(FSettingsForm);
SF.LoadPASettings(FPAMaxPower, FPABandCal);
@@ -5032,6 +5117,7 @@ begin
SF.RefreshAudioDevices(FAudioOut, FAudioIn);
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
SF.LoadFPS(FDisplayFPS);
+ SF.LoadLightTheme(FLightTheme);
// Загружаем текущие значения
if FWDSPReady then
SF.LoadValues(
diff --git a/Settings.pas b/Settings.pas
index 9d31672..8868d55 100644
--- a/Settings.pas
+++ b/Settings.pas
@@ -72,6 +72,8 @@ type
ShowWaterfall: Boolean; // True = draw waterfall on main form
// --- Display FPS ---
DisplayFPS: Integer; // spectrum/waterfall timer fps (1..100)
+ // --- Theme ---
+ LightTheme: Boolean; // False = dark (default), True = light
// --- PA (Power Amplifier) settings ---
PAMaxPower: Double; // максимальная выходная мощность, Вт (5..200)
PABandCal: array[0..CFG_BAND_COUNT-1] of Double; // калибровка на диапазон 38.8..100.0
@@ -128,6 +130,9 @@ type
// CAT settings — не привязаны к MAC, хранятся в корне JSON (доступны до подключения)
procedure SaveCATSettings(const G: TGlobalSettings);
procedure LoadCATSettings(var G: TGlobalSettings);
+ // Тема — глобальная настройка, не привязана к устройству
+ procedure SaveTheme(ALightTheme: Boolean);
+ function LoadTheme: Boolean;
end;
implementation
@@ -413,6 +418,7 @@ begin
G.ShowSpectrum := JB(GObj,'show_spectrum',True);
G.ShowWaterfall := JB(GObj,'show_waterfall',True);
G.DisplayFPS := JI(GObj,'display_fps',60);
+ G.LightTheme := JB(GObj,'light_theme',False);
// PA settings
G.PAMaxPower := JD(GObj,'pa_max_power',100.0);
for i := 0 to CFG_BAND_COUNT-1 do
@@ -489,6 +495,7 @@ begin
JW(O,'show_spectrum',G.ShowSpectrum);
JW(O,'show_waterfall',G.ShowWaterfall);
JW(O,'display_fps',G.DisplayFPS);
+ JW(O,'light_theme',G.LightTheme);
// PA settings
JW(O,'pa_max_power',G.PAMaxPower);
for i := 0 to CFG_BAND_COUNT-1 do
@@ -621,4 +628,20 @@ begin
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.
diff --git a/SettingsForm.pas b/SettingsForm.pas
index 62a39c9..05ade3c 100644
--- a/SettingsForm.pas
+++ b/SettingsForm.pas
@@ -27,7 +27,7 @@ uses
Classes, SysUtils, Math,
Forms, Controls, Graphics, Dialogs,
StdCtrls, ExtCtrls, Spin,
- FlatButton, AudioOutput, AudioInput;
+ FlatButton, AudioOutput, AudioInput, AppTheme;
type
// PA: MaxPower в Вт, BandCal[0..10] — калибровка 38.8..100.0 на диапазон
@@ -43,6 +43,7 @@ type
TOnAudioInDevChange = procedure(DevIndex: Integer; const DevName: string) of object;
TOnVisibilityChange = procedure(ShowSpectrum, ShowWaterfall: Boolean) of object;
TOnFPSChange = procedure(FPS: Integer) of object;
+ TOnThemeChange = procedure(LightTheme: Boolean) of object;
TOnCATChange = procedure(
const SerEnabled: array of Boolean;
const SerPort: array of string;
@@ -101,6 +102,7 @@ type
FChkShowSpectrum: TCheckBox;
FChkShowWaterfall: TCheckBox;
FCmbFPS: TComboBox;
+ FChkLightTheme: TCheckBox;
// ---- PA Settings tab controls ----
FEdMaxPower: TSpinEdit;
@@ -129,6 +131,7 @@ type
FOnAudioInDevChange: TOnAudioInDevChange;
FOnVisibilityChange: TOnVisibilityChange;
FOnFPSChange: TOnFPSChange;
+ FOnThemeChange: TOnThemeChange;
FLoading: Boolean;
@@ -138,7 +141,7 @@ type
procedure BuildRX1Tab;
procedure BuildPATab;
procedure BuildCATTab;
- procedure ApplyTheme;
+ procedure ApplyTheme(const T: TAppTheme);
procedure NavClick(Sender: TObject);
procedure SelectPage(APage: TWinControl; ANav: TFlatButton);
@@ -167,6 +170,7 @@ type
procedure OnTXDevChange(Sender: TObject);
procedure OnVisibilityChkChange(Sender: TObject);
procedure OnFPSCmbChange(Sender: TObject);
+ procedure OnLightThemeChkChange(Sender: TObject);
procedure OnMaxPowerChange(Sender: TObject);
procedure OnBandCalChange(Sender: TObject);
procedure OnCATSerialChange(Sender: TObject);
@@ -203,6 +207,7 @@ type
procedure RefreshAudioDevices(AudioOut: TAudioOutput; AudioIn: TAudioInput);
procedure LoadVisibility(ShowSpectrum, ShowWaterfall: Boolean);
procedure LoadFPS(FPS: Integer);
+ procedure LoadLightTheme(ALight: Boolean);
procedure LoadPASettings(MaxPower: Double; const BandCal: array of Double);
procedure LoadCATSettings(
const SerEnabled: array of Boolean;
@@ -219,6 +224,7 @@ type
property OnAudioInDevChange: TOnAudioInDevChange read FOnAudioInDevChange write FOnAudioInDevChange;
property OnVisibilityChange: TOnVisibilityChange read FOnVisibilityChange write FOnVisibilityChange;
property OnFPSChange: TOnFPSChange read FOnFPSChange write FOnFPSChange;
+ property OnThemeChange: TOnThemeChange read FOnThemeChange write FOnThemeChange;
end;
implementation
@@ -287,7 +293,7 @@ begin
FLoading := False;
FRXDevCount := 0;
BuildUI;
- ApplyTheme;
+ ApplyTheme(DarkTheme);
end;
// ---------------------------------------------------------------------------
@@ -611,6 +617,18 @@ begin
for i := 0 to High(FPS_NAMES) do
FCmbFPS.Items.Add(FPS_NAMES[i]);
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;
// ---------------------------------------------------------------------------
@@ -888,18 +906,66 @@ begin
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
- Color := CLR_BG;
- if Assigned(FNavPanel) then FNavPanel.Color := TColor($00151515);
- if Assigned(FContentPanel) then FContentPanel.Color := CLR_BG;
- if Assigned(FPageAudio) then FPageAudio.Color := CLR_BG;
- 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;
+ Color := T.BG;
+ Font.Color := T.Text;
+ WalkControls(Self);
+ Invalidate;
end;
// ---------------------------------------------------------------------------
@@ -1265,6 +1331,15 @@ begin
FOnVisibilityChange(FChkShowSpectrum.Checked, FChkShowWaterfall.Checked);
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);
var
Idx: Integer;
@@ -1291,6 +1366,18 @@ begin
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;
const BandCal: array of Double);
var i, n: Integer;
diff --git a/SpectrumView.pas b/SpectrumView.pas
index 7b5d468..826c33d 100644
--- a/SpectrumView.pas
+++ b/SpectrumView.pas
@@ -18,7 +18,7 @@ interface
uses
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
- IntfGraphics, FPImage, LCLIntf, LCLType, GraphType;
+ IntfGraphics, FPImage, LCLIntf, LCLType, GraphType, AppTheme;
const
SV_CLR_BG = TColor($00101010);
@@ -44,6 +44,9 @@ type
FWfIntfImg: TLazIntfImage;
FWfPixels: array of LongWord;
FSpPts: array of TPoint;
+ // ── Тема ─────────────────────────────────────────────────────────────────
+ FTheme: TAppTheme;
+ FLightTheme: Boolean;
FSpPtsLen: Integer;
FSmBitmap: TBitmap;
FRulerLastFreq: Double;
@@ -197,6 +200,8 @@ type
// ── Утилиты ───────────────────────────────────────────────────────────────
procedure InvalidateGridCache;
+ // ── Тема ─────────────────────────────────────────────────────────────────
+ procedure SetTheme(const T: TAppTheme);
procedure InvalidateRulerCache;
procedure ResetSpectrumBuf;
procedure ResetWfAvgBuf;
@@ -360,6 +365,8 @@ begin
FWaterfallDirty := True;
FLastSMeter := -130; FSMeterPeak := -130; FSMeterMin := -130;
FLastFwdW := 0; FLastSWR := 1;
+ FLightTheme := False;
+ FTheme := DarkTheme;
ResetSpectrumBuf;
end;
@@ -439,14 +446,17 @@ begin
Alpha := Round((1.0 - Sqr((Row - YMin) / Max(1.0, H - YMin - 1.0))) * 200);
if Alpha <= 0 then Continue;
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);
if RowPtr = nil then Continue;
for Col := 0 to W - 1 do
begin
if SpPts[Col].Y <= Row then
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);
end else begin
RowPtr[0] := 0; RowPtr[1] := 0; RowPtr[2] := 0;
@@ -495,7 +505,7 @@ procedure TSpectrumView.SetSpectrumBitmapSize(W, H: Integer);
begin
if (W <= 0) or (H <= 0) then Exit;
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));
FreeAndNil(FSpecGradImg);
InvalidateGridCache;
@@ -532,6 +542,16 @@ begin
FSpectrumDirty := True;
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;
begin
FRulerLastFreq := -1.0; FRulerLastVfo := -1.0; FRulerLastSpan := -1.0;
@@ -606,20 +626,20 @@ begin
FGridBitmapW := W; FGridBitmapH := H;
FGridBitmap.SetSize(W, H);
GC := FGridBitmap.Canvas;
- PaintVerticalGradient(GC, W, H, TColor($0020160B), TColor($006C4F1F));
+ PaintVerticalGradient(GC, W, H, FTheme.SpecGradTop, FTheme.SpecGradBot);
LabelBandW := 28;
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.Pen.Style := psSolid;
GC.Font.Size := 7; GC.Font.Name := 'Courier New';
- GC.Font.Color := TColor($00A8C9D9);
+ GC.Font.Color := FTheme.SpecLabelText;
GC.Brush.Style := bsClear;
dB := DBmax - FSpecGridStep;
while dB >= DBmin do
begin
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.TextOut(1, Yp - 9, Format('%4.0f', [dB]));
dB := dB - FSpecGridStep;
@@ -627,7 +647,7 @@ begin
for i := 0 to 8 do
begin
GX := ScaleX(i, 8, W);
- GC.Pen.Color := TColor($00685624);
+ GC.Pen.Color := FTheme.SpecGrid;
GC.MoveTo(GX, 0); GC.LineTo(GX, H);
end;
end;
@@ -646,7 +666,7 @@ begin
end;
X1 := Max(0, Min(W-1, VfoX + Round(Lo_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));
C.Pen.Style := psSolid;
@@ -656,26 +676,26 @@ begin
AGCy := Round((DBmax - FAGCThresh) * InvRange * H);
if (AGCy >= 0) and (AGCy < H) then
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.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');
end;
AGCHangY := Round((DBmax - FAGCHangLevel) * InvRange * H);
if (AGCHangY >= 0) and (AGCHangY < H) and (Abs(AGCHangY - AGCy) > 4) then
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.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');
end;
end else begin
AGCy := Round((DBmax - (-FAGCTop)) * InvRange * H);
if (AGCy >= 0) and (AGCy < H) then
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.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]));
end;
end;
@@ -700,16 +720,16 @@ begin
DrawSpectrumGradient(FSpPts, W, H);
// ── 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));
// ── 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(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.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)]);
if FMarkerActive then DrawMarkerLine(C, W, H);
@@ -862,8 +882,8 @@ begin
if (FRulerBitmap.Width <> W) or (FRulerBitmap.Height <> H) then
FRulerBitmap.SetSize(W, H);
C := FRulerBitmap.Canvas;
- PaintVerticalGradient(C, W, H, TColor($00372A12), TColor($00705A2A));
- C.Pen.Color := TColor($00685624); C.Pen.Width := 1;
+ PaintVerticalGradient(C, W, H, FTheme.RulerGradTop, FTheme.RulerGradBot);
+ C.Pen.Color := FTheme.RulerBorder; C.Pen.Width := 1;
C.MoveTo(0, 0); C.LineTo(W, 0);
C.MoveTo(0, H-1); C.LineTo(W, H-1);
C.Font.Name := 'Courier New'; C.Font.Size := 7;
@@ -872,18 +892,18 @@ begin
for i := 0 to 8 do
begin
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);
FreqHz := FreqStart + i * FSpanHz / 8;
Lbl := Format('%.3f', [FreqHz / 1e6]);
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);
end;
VfoX := Round((ActiveVfoFreq - FCenterFreq + FSpanHz/2) / FSpanHz * W);
if (VfoX >= 0) and (VfoX < W) then
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;
end;
end;
@@ -896,7 +916,7 @@ procedure TSpectrumView.DrawBarMeter(ACanvas: TCanvas; R: TRect;
Value, MaxVal: Double; BarColor: TColor);
var Pct, BarW: Integer;
begin
- ACanvas.Brush.Color := TColor($00080808);
+ ACanvas.Brush.Color := FTheme.SMeterBG;
ACanvas.FillRect(R);
if MaxVal > 0 then
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');
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');
- 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;
TICK_LONG = 5; TICK_MED = 3;
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;
Y_BAR_TOP, Y_BAR_BOT: Integer;
BarEnd, PeakLeft, PeakRight, S9X, OvrX: Integer;
@@ -960,6 +971,20 @@ var
end;
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;
ZX1 := 0; ZX2 := 0; ZY1 := 0; ZY2 := 0;
if (W < 80) or (H < 16) then Exit;
@@ -997,9 +1022,9 @@ begin
ACanvas.Brush.Color := CLR_SMETER_BG; ACanvas.Brush.Style := bsSolid;
ACanvas.Pen.Style := psClear; ACanvas.FillRect(R); ACanvas.Pen.Style := psSolid;
- FillBar(BX, Y_BAR_TOP, S9X, Y_BAR_BOT, TColor($00061006));
- FillBar(S9X, Y_BAR_TOP, OvrX, Y_BAR_BOT, TColor($000A1006));
- FillBar(OvrX, Y_BAR_TOP, BX + BW, Y_BAR_BOT, TColor($00060A10));
+ FillBar(BX, Y_BAR_TOP, S9X, Y_BAR_BOT, CLR_BAR_GREEN);
+ FillBar(S9X, Y_BAR_TOP, OvrX, Y_BAR_BOT, CLR_BAR_GREEN);
+ FillBar(OvrX, Y_BAR_TOP, BX + BW, Y_BAR_BOT, CLR_BAR_OVER);
BarEnd := DBtoX(Value);
PeakLeft := DBtoX(MinVal);
@@ -1029,7 +1054,7 @@ begin
ACanvas.Brush.Style := bsClear; ACanvas.Pen.Color := CLR_BDR;
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);
// --- Шкальные тики и надписи ---
@@ -1066,7 +1091,7 @@ begin
// "-85.3" над "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.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');
// S-значение под полосой, левый край у LblZoneL+4
ACanvas.Font.Size := 10; ACanvas.Font.Style := [fsBold]; ACanvas.Font.Color := CLR_LABEL_S;
diff --git a/ewsdr.lpi b/ewsdr.lpi
index d30731c..2e8f485 100644
--- a/ewsdr.lpi
+++ b/ewsdr.lpi
@@ -115,6 +115,10 @@
+
+
+
+