mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Add configurable VFO frequency range with GHz support
- Settings > Display: new "VFO Display" control to select max frequency range (999 MHz / 9.999 GHz / 99.999 GHz), persisted as freq_mhz_digits - FreqDisplay: extend digit map [0..10] to support up to 11 digit positions; keyboard navigation adapts to MinMhzDigits dynamically - MainForm/LayoutTopVfoBlock: VFO panel width scales automatically with selected digit count using dynamic text measurement - Web VFO: fix broken HTML (class attr not closed before data-s — wheel and hover were completely non-functional); rewrite fmtVfo to use variable MHz digit count synced from server state; fix missing </span> for .vfo-hz - WebServer: publish freq_mhz_digits in state JSON; updated from ApplyFreqMhzDigits so desktop and web stay in sync - Fix Int32 overflow on frequencies above ~2.15 GHz: CATEngine.Pad V param Int64, FormatFreq/FormatFreqSV Mhz var Int64 (Mhz*1000000 overflowed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -88,7 +88,7 @@ type
|
|||||||
FCtx: TCATContext;
|
FCtx: TCATContext;
|
||||||
FLock: TCriticalSection;
|
FLock: TCriticalSection;
|
||||||
|
|
||||||
function Pad(V, W: Integer): string;
|
function Pad(V: Int64; W: Integer): string;
|
||||||
function FreqToStr(Hz: Double): string;
|
function FreqToStr(Hz: Double): string;
|
||||||
function StrToFreq(const S: string): Double;
|
function StrToFreq(const S: string): Double;
|
||||||
function ModeToK(M: Integer): Integer;
|
function ModeToK(M: Integer): Integer;
|
||||||
@@ -311,7 +311,7 @@ begin if B then Result := '1' else Result := '0'; end;
|
|||||||
|
|
||||||
{ ── Helpers ──────────────────────────────────────────────────────────────── }
|
{ ── Helpers ──────────────────────────────────────────────────────────────── }
|
||||||
|
|
||||||
function TCATEngine.Pad(V, W: Integer): string;
|
function TCATEngine.Pad(V: Int64; W: Integer): string;
|
||||||
begin
|
begin
|
||||||
Result := IntToStr(Abs(V));
|
Result := IntToStr(Abs(V));
|
||||||
while Length(Result) < W do Result := '0' + Result;
|
while Length(Result) < W do Result := '0' + Result;
|
||||||
|
|||||||
+9
-9
@@ -36,8 +36,8 @@ type
|
|||||||
FCenterText: Boolean;
|
FCenterText: Boolean;
|
||||||
FOnChange: TFreqChangeEvent;
|
FOnChange: TFreqChangeEvent;
|
||||||
|
|
||||||
FHoverDigit: Integer; // 0=единицы .. 8=100МГц, -1=нет
|
FHoverDigit: Integer; // 0=единицы .. 10=10ГГц, -1=нет
|
||||||
FDigitX: array[0..8] of Integer; // X левого края каждой цифры
|
FDigitX: array[0..10] of Integer; // X левого края каждой цифры
|
||||||
FDigitW: Integer;
|
FDigitW: Integer;
|
||||||
FCharH: Integer;
|
FCharH: Integer;
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ var
|
|||||||
begin
|
begin
|
||||||
Result := -1;
|
Result := -1;
|
||||||
if FDigitW = 0 then Exit;
|
if FDigitW = 0 then Exit;
|
||||||
for i := 0 to 8 do
|
for i := 0 to 10 do
|
||||||
if (X >= FDigitX[i]) and (X < FDigitX[i] + FDigitW) then
|
if (X >= FDigitX[i]) and (X < FDigitX[i] + FDigitW) then
|
||||||
begin
|
begin
|
||||||
Result := i;
|
Result := i;
|
||||||
@@ -137,14 +137,14 @@ end;
|
|||||||
// Цифры нумеруются справа налево: digit0=единицы, digit8=сотни млн
|
// Цифры нумеруются справа налево: digit0=единицы, digit8=сотни млн
|
||||||
procedure TFreqDisplay.BuildDigitMap(const S: string; StartX: Integer);
|
procedure TFreqDisplay.BuildDigitMap(const S: string; StartX: Integer);
|
||||||
var
|
var
|
||||||
Xs: array[0..11] of Integer; // X каждого символа строки (макс 12 симв)
|
Xs: array[0..13] of Integer; // X каждого символа строки (макс 14 симв)
|
||||||
ci: Integer;
|
ci: Integer;
|
||||||
xi: Integer;
|
xi: Integer;
|
||||||
dIdx: Integer;
|
dIdx: Integer;
|
||||||
len: Integer;
|
len: Integer;
|
||||||
begin
|
begin
|
||||||
len := Length(S);
|
len := Length(S);
|
||||||
if len > 12 then len := 12;
|
if len > 13 then len := 13;
|
||||||
|
|
||||||
xi := StartX;
|
xi := StartX;
|
||||||
for ci := 0 to len - 1 do
|
for ci := 0 to len - 1 do
|
||||||
@@ -159,7 +159,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
if S[ci + 1] <> '.' then
|
if S[ci + 1] <> '.' then
|
||||||
begin
|
begin
|
||||||
if dIdx <= 8 then
|
if dIdx <= 10 then
|
||||||
FDigitX[dIdx] := Xs[ci];
|
FDigitX[dIdx] := Xs[ci];
|
||||||
Inc(dIdx);
|
Inc(dIdx);
|
||||||
end;
|
end;
|
||||||
@@ -185,7 +185,7 @@ var
|
|||||||
ch: Char;
|
ch: Char;
|
||||||
dIdx: Integer;
|
dIdx: Integer;
|
||||||
col: TColor;
|
col: TColor;
|
||||||
DiChar: array[0..11] of Integer;
|
DiChar: array[0..13] of Integer;
|
||||||
tmpIdx: Integer;
|
tmpIdx: Integer;
|
||||||
len: Integer;
|
len: Integer;
|
||||||
begin
|
begin
|
||||||
@@ -234,7 +234,7 @@ begin
|
|||||||
|
|
||||||
// Строим обратную карту символ → digit index
|
// Строим обратную карту символ → digit index
|
||||||
len := Length(S);
|
len := Length(S);
|
||||||
if len > 12 then len := 12;
|
if len > 13 then len := 13;
|
||||||
tmpIdx := 0;
|
tmpIdx := 0;
|
||||||
for ci := len - 1 downto 0 do
|
for ci := len - 1 downto 0 do
|
||||||
begin
|
begin
|
||||||
@@ -385,7 +385,7 @@ begin
|
|||||||
VK_DOWN: begin ChangeByDigit(d, -1); Key := 0; end;
|
VK_DOWN: begin ChangeByDigit(d, -1); Key := 0; end;
|
||||||
VK_LEFT: begin
|
VK_LEFT: begin
|
||||||
if FHoverDigit < 0 then FHoverDigit := 3;
|
if FHoverDigit < 0 then FHoverDigit := 3;
|
||||||
if FHoverDigit < 8 then Inc(FHoverDigit);
|
if FHoverDigit < FMinMhzDigits + 5 then Inc(FHoverDigit);
|
||||||
Invalidate; Key := 0;
|
Invalidate; Key := 0;
|
||||||
end;
|
end;
|
||||||
VK_RIGHT: begin
|
VK_RIGHT: begin
|
||||||
|
|||||||
+26
-3
@@ -278,6 +278,7 @@ type
|
|||||||
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 = светлая тема
|
FLightTheme: Boolean; // True = светлая тема
|
||||||
|
FFreqMhzDigits: Integer; // 3=999MHz, 4=9.999GHz, 5=99.999GHz
|
||||||
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)
|
||||||
@@ -630,6 +631,7 @@ type
|
|||||||
function BuildMicLineSelectByte: Byte;
|
function BuildMicLineSelectByte: Byte;
|
||||||
procedure ApplyVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
procedure ApplyVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
||||||
procedure ApplyFPS(FPS: Integer);
|
procedure ApplyFPS(FPS: Integer);
|
||||||
|
procedure ApplyFreqMhzDigits(Digits: Integer);
|
||||||
|
|
||||||
published
|
published
|
||||||
// Обработчики событий формы — должны быть в published для RTTI/LFM
|
// Обработчики событий формы — должны быть в published для RTTI/LFM
|
||||||
@@ -919,6 +921,7 @@ begin
|
|||||||
Result.DisplayDuplex := FDisplayDuplex;
|
Result.DisplayDuplex := FDisplayDuplex;
|
||||||
Result.DisplayFPS := FDisplayFPS;
|
Result.DisplayFPS := FDisplayFPS;
|
||||||
Result.LightTheme := FLightTheme;
|
Result.LightTheme := FLightTheme;
|
||||||
|
Result.FreqMhzDigits := FFreqMhzDigits;
|
||||||
// Audio device names
|
// Audio device names
|
||||||
Result.AudioOutDevice := FAudioOutDevName;
|
Result.AudioOutDevice := FAudioOutDevName;
|
||||||
Result.AudioInDevice := FAudioInDevName;
|
Result.AudioInDevice := FAudioInDevName;
|
||||||
@@ -1182,6 +1185,7 @@ begin
|
|||||||
FShowSpectrum := True;
|
FShowSpectrum := True;
|
||||||
FShowWaterfall := True;
|
FShowWaterfall := True;
|
||||||
FDisplayFPS := 60;
|
FDisplayFPS := 60;
|
||||||
|
FFreqMhzDigits := 3;
|
||||||
FSplitterRatio := 0.40;
|
FSplitterRatio := 0.40;
|
||||||
FSplitterDrag := False;
|
FSplitterDrag := False;
|
||||||
|
|
||||||
@@ -1992,7 +1996,7 @@ begin
|
|||||||
Canvas.Font.Style := [fsBold];
|
Canvas.Font.Style := [fsBold];
|
||||||
FreqDispA.Left := VFO_BTN_W + VFO_BTN_FREQ_GAP - VFO_FREQ_LEFT_PAD;
|
FreqDispA.Left := VFO_BTN_W + VFO_BTN_FREQ_GAP - VFO_FREQ_LEFT_PAD;
|
||||||
FreqDispB.Left := VFO_B_LEFT_PAD + VFO_BTN_W + VFO_BTN_FREQ_GAP - VFO_FREQ_LEFT_PAD;
|
FreqDispB.Left := VFO_B_LEFT_PAD + VFO_BTN_W + VFO_BTN_FREQ_GAP - VFO_FREQ_LEFT_PAD;
|
||||||
FreqTextW := Canvas.TextWidth('000.000.000');
|
FreqTextW := Canvas.TextWidth(StringOfChar('0', Max(3, FFreqMhzDigits)) + '.000.000');
|
||||||
NeedFreqAW := FreqDispA.Left + FreqTextW + VFO_FREQ_LEFT_PAD + VFO_FREQ_RIGHT_PAD;
|
NeedFreqAW := FreqDispA.Left + FreqTextW + VFO_FREQ_LEFT_PAD + VFO_FREQ_RIGHT_PAD;
|
||||||
NeedFreqBW := FreqDispB.Left + FreqTextW + VFO_FREQ_LEFT_PAD + VFO_FREQ_RIGHT_PAD;
|
NeedFreqBW := FreqDispB.Left + FreqTextW + VFO_FREQ_LEFT_PAD + VFO_FREQ_RIGHT_PAD;
|
||||||
TopVfoAW := NeedFreqAW;
|
TopVfoAW := NeedFreqAW;
|
||||||
@@ -2448,12 +2452,13 @@ end;
|
|||||||
|
|
||||||
function TMainForm.FormatFreq(Hz: Double): string;
|
function TMainForm.FormatFreq(Hz: Double): string;
|
||||||
var
|
var
|
||||||
Mhz, KHz, Rest: Integer;
|
Mhz: Int64;
|
||||||
|
KHz, Rest: Integer;
|
||||||
begin
|
begin
|
||||||
Mhz := Trunc(Hz / 1000000);
|
Mhz := Trunc(Hz / 1000000);
|
||||||
KHz := Trunc((Hz - Mhz * 1000000) / 1000);
|
KHz := Trunc((Hz - Mhz * 1000000) / 1000);
|
||||||
Rest := Trunc(Hz) mod 1000;
|
Rest := Trunc(Hz) mod 1000;
|
||||||
Result := Format('%3d.%3.3d.%3.3d', [Mhz, KHz, Rest]);
|
Result := Format('%d.%3.3d.%3.3d', [Mhz, KHz, Rest]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.UpdateVfoDisplay;
|
procedure TMainForm.UpdateVfoDisplay;
|
||||||
@@ -3568,6 +3573,7 @@ begin
|
|||||||
if BtnDUP <> nil then StyleButton(BtnDUP, FDisplayDuplex);
|
if BtnDUP <> nil then StyleButton(BtnDUP, FDisplayDuplex);
|
||||||
if G_Settings.DisplayFPS > 0 then
|
if G_Settings.DisplayFPS > 0 then
|
||||||
ApplyFPS(G_Settings.DisplayFPS);
|
ApplyFPS(G_Settings.DisplayFPS);
|
||||||
|
ApplyFreqMhzDigits(EnsureRange(G_Settings.FreqMhzDigits, 3, 5));
|
||||||
// Настройки дисплея и сетки
|
// Настройки дисплея и сетки
|
||||||
if G_Settings.FFTSize > 0 then
|
if G_Settings.FFTSize > 0 then
|
||||||
begin
|
begin
|
||||||
@@ -6116,6 +6122,21 @@ begin
|
|||||||
FDSPEngine.SetDisplayFPS(FPS);
|
FDSPEngine.SetDisplayFPS(FPS);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.ApplyFreqMhzDigits(Digits: Integer);
|
||||||
|
const
|
||||||
|
MaxFreqs: array[3..5] of Int64 = (999999999, 9999999999, 99999999999);
|
||||||
|
begin
|
||||||
|
Digits := EnsureRange(Digits, 3, 5);
|
||||||
|
FFreqMhzDigits := Digits;
|
||||||
|
FreqDispA.MinMhzDigits := Digits;
|
||||||
|
FreqDispB.MinMhzDigits := Digits;
|
||||||
|
FreqDispA.MaxFreq := MaxFreqs[Digits];
|
||||||
|
FreqDispB.MaxFreq := MaxFreqs[Digits];
|
||||||
|
if Assigned(FWebServer) then
|
||||||
|
FWebServer.FreqMhzDigits := Digits;
|
||||||
|
LayoutTopVfoBlock;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainForm.BtnSettingsClick(Sender: TObject);
|
procedure TMainForm.BtnSettingsClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
SF: TSettingsForm;
|
SF: TSettingsForm;
|
||||||
@@ -6134,6 +6155,7 @@ begin
|
|||||||
SF.OnPAChange := OnPASettingsChange;
|
SF.OnPAChange := OnPASettingsChange;
|
||||||
SF.OnCATChange := OnCATSettingsChange;
|
SF.OnCATChange := OnCATSettingsChange;
|
||||||
SF.OnThemeChange := SetLightTheme;
|
SF.OnThemeChange := SetLightTheme;
|
||||||
|
SF.OnFreqMhzDigitsChange := ApplyFreqMhzDigits;
|
||||||
SF.OnTXChange := OnTXSettingsChange;
|
SF.OnTXChange := OnTXSettingsChange;
|
||||||
SF.OnAlexChange := OnAlexSettingsChange;
|
SF.OnAlexChange := OnAlexSettingsChange;
|
||||||
SF.OnXvtrChange := OnXvtrSettingsChange;
|
SF.OnXvtrChange := OnXvtrSettingsChange;
|
||||||
@@ -6158,6 +6180,7 @@ begin
|
|||||||
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
|
SF.LoadVisibility(FShowSpectrum, FShowWaterfall);
|
||||||
SF.LoadFPS(FDisplayFPS);
|
SF.LoadFPS(FDisplayFPS);
|
||||||
SF.LoadLightTheme(FLightTheme);
|
SF.LoadLightTheme(FLightTheme);
|
||||||
|
SF.LoadFreqMhzDigits(FFreqMhzDigits);
|
||||||
// Загружаем текущие значения
|
// Загружаем текущие значения
|
||||||
if FWDSPReady then
|
if FWDSPReady then
|
||||||
SF.LoadValues(
|
SF.LoadValues(
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ type
|
|||||||
DisplayFPS: Integer; // spectrum/waterfall timer fps (1..100)
|
DisplayFPS: Integer; // spectrum/waterfall timer fps (1..100)
|
||||||
// --- Theme ---
|
// --- Theme ---
|
||||||
LightTheme: Boolean; // False = dark (default), True = light
|
LightTheme: Boolean; // False = dark (default), True = light
|
||||||
|
// --- VFO display digits ---
|
||||||
|
FreqMhzDigits: Integer; // minimum MHz digit count: 3=999MHz, 4=9.999GHz, 5=99.999GHz
|
||||||
// --- 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
|
||||||
@@ -346,6 +348,7 @@ begin
|
|||||||
G.ShowWaterfall := True;
|
G.ShowWaterfall := True;
|
||||||
G.DisplayDuplex := False;
|
G.DisplayDuplex := False;
|
||||||
G.DisplayFPS := 60;
|
G.DisplayFPS := 60;
|
||||||
|
G.FreqMhzDigits := 3;
|
||||||
// CAT defaults
|
// CAT defaults
|
||||||
for i := 0 to 3 do begin
|
for i := 0 to 3 do begin
|
||||||
G.CATSerialEnabled[i] := False;
|
G.CATSerialEnabled[i] := False;
|
||||||
@@ -557,6 +560,7 @@ begin
|
|||||||
G.DisplayDuplex := JB(GObj,'display_duplex',False);
|
G.DisplayDuplex := JB(GObj,'display_duplex',False);
|
||||||
G.DisplayFPS := JI(GObj,'display_fps',60);
|
G.DisplayFPS := JI(GObj,'display_fps',60);
|
||||||
G.LightTheme := JB(GObj,'light_theme',False);
|
G.LightTheme := JB(GObj,'light_theme',False);
|
||||||
|
G.FreqMhzDigits := EnsureRange(JI(GObj,'freq_mhz_digits',3), 3, 5);
|
||||||
// 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
|
||||||
@@ -636,6 +640,7 @@ begin
|
|||||||
JW(O,'display_duplex',G.DisplayDuplex);
|
JW(O,'display_duplex',G.DisplayDuplex);
|
||||||
JW(O,'display_fps',G.DisplayFPS);
|
JW(O,'display_fps',G.DisplayFPS);
|
||||||
JW(O,'light_theme',G.LightTheme);
|
JW(O,'light_theme',G.LightTheme);
|
||||||
|
JW(O,'freq_mhz_digits',G.FreqMhzDigits);
|
||||||
// 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
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type
|
|||||||
// TX-настройки целиком (любая правка → один callback с актуальной структурой)
|
// TX-настройки целиком (любая правка → один callback с актуальной структурой)
|
||||||
TOnTXSettingsChange = procedure(const T: TTXSettings) of object;
|
TOnTXSettingsChange = procedure(const T: TTXSettings) of object;
|
||||||
|
|
||||||
|
TOnFreqMhzDigitsChange = procedure(Digits: Integer) of object;
|
||||||
TOnDisplayParamChange = procedure(FFTSize, WindowType, SpecDetector,
|
TOnDisplayParamChange = procedure(FFTSize, WindowType, SpecDetector,
|
||||||
SpecAvgMode: Integer; SpecAvgTimeMS: Double) of object;
|
SpecAvgMode: Integer; SpecAvgTimeMS: Double) of object;
|
||||||
TOnWaterfallParamChange = procedure(WfDetector, WfAvgMode: Integer;
|
TOnWaterfallParamChange = procedure(WfDetector, WfAvgMode: Integer;
|
||||||
@@ -109,6 +110,7 @@ type
|
|||||||
FChkShowWaterfall: TCheckBox;
|
FChkShowWaterfall: TCheckBox;
|
||||||
FCmbFPS: TComboBox;
|
FCmbFPS: TComboBox;
|
||||||
FChkLightTheme: TCheckBox;
|
FChkLightTheme: TCheckBox;
|
||||||
|
FCmbFreqMhzDigits: TComboBox;
|
||||||
|
|
||||||
// ---- PA Settings tab controls ----
|
// ---- PA Settings tab controls ----
|
||||||
FEdMaxPower: TSpinEdit;
|
FEdMaxPower: TSpinEdit;
|
||||||
@@ -244,6 +246,7 @@ type
|
|||||||
FOnVisibilityChange: TOnVisibilityChange;
|
FOnVisibilityChange: TOnVisibilityChange;
|
||||||
FOnFPSChange: TOnFPSChange;
|
FOnFPSChange: TOnFPSChange;
|
||||||
FOnThemeChange: TOnThemeChange;
|
FOnThemeChange: TOnThemeChange;
|
||||||
|
FOnFreqMhzDigitsChange: TOnFreqMhzDigitsChange;
|
||||||
FOnTXChange: TOnTXSettingsChange;
|
FOnTXChange: TOnTXSettingsChange;
|
||||||
|
|
||||||
FLoading: Boolean;
|
FLoading: Boolean;
|
||||||
@@ -298,6 +301,7 @@ type
|
|||||||
procedure OnVisibilityChkChange(Sender: TObject);
|
procedure OnVisibilityChkChange(Sender: TObject);
|
||||||
procedure OnFPSCmbChange(Sender: TObject);
|
procedure OnFPSCmbChange(Sender: TObject);
|
||||||
procedure OnLightThemeChkChange(Sender: TObject);
|
procedure OnLightThemeChkChange(Sender: TObject);
|
||||||
|
procedure OnFreqMhzDigitsCmbChange(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);
|
||||||
@@ -335,6 +339,7 @@ type
|
|||||||
procedure LoadVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
procedure LoadVisibility(ShowSpectrum, ShowWaterfall: Boolean);
|
||||||
procedure LoadFPS(FPS: Integer);
|
procedure LoadFPS(FPS: Integer);
|
||||||
procedure LoadLightTheme(ALight: Boolean);
|
procedure LoadLightTheme(ALight: Boolean);
|
||||||
|
procedure LoadFreqMhzDigits(Digits: Integer);
|
||||||
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;
|
||||||
@@ -357,6 +362,7 @@ type
|
|||||||
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;
|
property OnThemeChange: TOnThemeChange read FOnThemeChange write FOnThemeChange;
|
||||||
|
property OnFreqMhzDigitsChange: TOnFreqMhzDigitsChange read FOnFreqMhzDigitsChange write FOnFreqMhzDigitsChange;
|
||||||
property OnTXChange: TOnTXSettingsChange read FOnTXChange write FOnTXChange;
|
property OnTXChange: TOnTXSettingsChange read FOnTXChange write FOnTXChange;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -783,6 +789,15 @@ begin
|
|||||||
FChkLightTheme.Font.Name := UI_FONT;
|
FChkLightTheme.Font.Name := UI_FONT;
|
||||||
FChkLightTheme.Font.Size := 9;
|
FChkLightTheme.Font.Size := 9;
|
||||||
FChkLightTheme.OnChange := OnLightThemeChkChange;
|
FChkLightTheme.OnChange := OnLightThemeChkChange;
|
||||||
|
|
||||||
|
Grp := MakeGroupPanel(FPageDisplay, 'VFO Display', MARGIN, 378, 650, 92);
|
||||||
|
|
||||||
|
MakeLbl(Grp, 'Frequency range', PAD, R1 + 5, LW);
|
||||||
|
FCmbFreqMhzDigits := MakeCombo(Grp, CX, R1, 240, OnFreqMhzDigitsCmbChange);
|
||||||
|
FCmbFreqMhzDigits.Items.Add('up to 999 MHz (3 digits)');
|
||||||
|
FCmbFreqMhzDigits.Items.Add('up to 9.999 GHz (4 digits)');
|
||||||
|
FCmbFreqMhzDigits.Items.Add('up to 99.999 GHz (5 digits)');
|
||||||
|
FCmbFreqMhzDigits.ItemIndex := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -2014,6 +2029,23 @@ begin
|
|||||||
else ApplyTheme(DarkTheme);
|
else ApplyTheme(DarkTheme);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSettingsForm.LoadFreqMhzDigits(Digits: Integer);
|
||||||
|
begin
|
||||||
|
FLoading := True;
|
||||||
|
try
|
||||||
|
FCmbFreqMhzDigits.ItemIndex := EnsureRange(Digits - 3, 0, 2);
|
||||||
|
finally
|
||||||
|
FLoading := False;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSettingsForm.OnFreqMhzDigitsCmbChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
if FLoading then Exit;
|
||||||
|
if Assigned(FOnFreqMhzDigitsChange) then
|
||||||
|
FOnFreqMhzDigitsChange(FCmbFreqMhzDigits.ItemIndex + 3);
|
||||||
|
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;
|
||||||
|
|||||||
+2
-2
@@ -371,12 +371,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function FormatFreqSV(Hz: Double): string;
|
function FormatFreqSV(Hz: Double): string;
|
||||||
var Mhz, KHz, Rest: Integer;
|
var Mhz: Int64; KHz, Rest: Integer;
|
||||||
begin
|
begin
|
||||||
Mhz := Trunc(Hz / 1000000);
|
Mhz := Trunc(Hz / 1000000);
|
||||||
KHz := Trunc((Hz - Mhz * 1000000) / 1000);
|
KHz := Trunc((Hz - Mhz * 1000000) / 1000);
|
||||||
Rest := Trunc(Hz) mod 1000;
|
Rest := Trunc(Hz) mod 1000;
|
||||||
Result := Format('%3d.%3.3d.%3.3d', [Mhz, KHz, Rest]);
|
Result := Format('%d.%3.3d.%3.3d', [Mhz, KHz, Rest]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ════════════════════════════════════════════════════════════════════════════
|
// ════════════════════════════════════════════════════════════════════════════
|
||||||
|
|||||||
+18
-11
@@ -323,22 +323,28 @@ begin
|
|||||||
'q("muteIc").onclick=()=>{cur.mute=!cur.mute;q("muteIc").textContent=cur.mute?"\uD83D\uDD07":"\uD83D\uDD0A";cmd("set_mute",cur.mute);};' +
|
'q("muteIc").onclick=()=>{cur.mute=!cur.mute;q("muteIc").textContent=cur.mute?"\uD83D\uDD07":"\uD83D\uDD0A";cmd("set_mute",cur.mute);};' +
|
||||||
|
|
||||||
'let stA=0,stAmem=100,stB=0,stBmem=100;' +
|
'let stA=0,stAmem=100,stB=0,stBmem=100;' +
|
||||||
|
'let freqMhzDigits=3,freqMaxHz=999999999;' +
|
||||||
'function fmtVfo(hz,step){' +
|
'function fmtVfo(hz,step){' +
|
||||||
'const s=String(Math.max(0,Math.round(hz||0))).padStart(9,"0");' +
|
'const N=freqMhzDigits+6;' +
|
||||||
|
'const s=String(Math.max(0,Math.round(hz||0))).padStart(N,"0");' +
|
||||||
'let h="",seenNZ=false;' +
|
'let h="",seenNZ=false;' +
|
||||||
'for(let i=0;i<6;i++){' +
|
'for(let i=0;i<freqMhzDigits;i++){' +
|
||||||
'const st=Math.pow(10,8-i);' +
|
'const st=Math.pow(10,freqMhzDigits+5-i);' +
|
||||||
'if(s[i]!=="0")seenNZ=true;' +
|
'if(s[i]!=="0")seenNZ=true;' +
|
||||||
'const lead=(!seenNZ)?" lead":"";' +
|
'const lead=(!seenNZ)?" lead":"";' +
|
||||||
'const sel=(step>0&&st===step)?" sel":"";' +
|
'const sel=(step>0&&st===step)?" sel":"";' +
|
||||||
'h+="<span class=\"dg"+lead+sel+" data-s=\""+st+"\">"+s[i]+"</span>";' +
|
'h+="<span class=\"dg"+lead+sel+"\" data-s=\""+st+"\">"+s[i]+"</span>";}' +
|
||||||
'if(i===2)h+="<span class=\"sp\">.</span>";}' +
|
|
||||||
'h+="<span class=\"sp\">.</span>";' +
|
'h+="<span class=\"sp\">.</span>";' +
|
||||||
'h+="<span class=\"vfo-hz\">";' +
|
'for(let i=freqMhzDigits;i<freqMhzDigits+3;i++){' +
|
||||||
'for(let i=6;i<9;i++){const st=Math.pow(10,8-i);' +
|
'const st=Math.pow(10,freqMhzDigits+5-i);' +
|
||||||
'const sel=(step>0&&st===step)?" sel":"";' +
|
'const sel=(step>0&&st===step)?" sel":"";' +
|
||||||
'h+="<span class=\"dg"+sel+" data-s=\""+st+"\">"+s[i]+"</span>";}' +
|
'h+="<span class=\"dg"+sel+"\" data-s=\""+st+"\">"+s[i]+"</span>";}' +
|
||||||
'return h;}' +
|
'h+="<span class=\"sp\">.</span><span class=\"vfo-hz\">";' +
|
||||||
|
'for(let i=freqMhzDigits+3;i<N;i++){' +
|
||||||
|
'const st=Math.pow(10,freqMhzDigits+5-i);' +
|
||||||
|
'const sel=(step>0&&st===step)?" sel":"";' +
|
||||||
|
'h+="<span class=\"dg"+sel+"\" data-s=\""+st+"\">"+s[i]+"</span>";}' +
|
||||||
|
'h+="</span>";return h;}' +
|
||||||
'function renderVfos(){q("vDispA").innerHTML=fmtVfo(vfoA,stA);q("vDispB").innerHTML=fmtVfo(vfoB,stB);}' +
|
'function renderVfos(){q("vDispA").innerHTML=fmtVfo(vfoA,stA);q("vDispB").innerHTML=fmtVfo(vfoB,stB);}' +
|
||||||
|
|
||||||
'function bindVfo(dispId,getHz,setHz,getSt,setSt,getMem,setMem,onSend){' +
|
'function bindVfo(dispId,getHz,setHz,getSt,setSt,getMem,setMem,onSend){' +
|
||||||
@@ -348,12 +354,12 @@ begin
|
|||||||
'el.addEventListener("mouseleave",()=>{if(getSt()!==0){setSt(0);renderVfos();}});' +
|
'el.addEventListener("mouseleave",()=>{if(getSt()!==0){setSt(0);renderVfos();}});' +
|
||||||
'el.addEventListener("wheel",e=>{e.preventDefault();e.stopPropagation();audioKick();' +
|
'el.addEventListener("wheel",e=>{e.preventDefault();e.stopPropagation();audioKick();' +
|
||||||
'const dir=e.deltaY<0?1:-1,st=getSt()||getMem()||100;' +
|
'const dir=e.deltaY<0?1:-1,st=getSt()||getMem()||100;' +
|
||||||
'const nf=cl(Math.round(getHz())+st*dir,30000,60000000);' +
|
'const nf=cl(Math.round(getHz())+st*dir,30000,freqMaxHz);' +
|
||||||
'setHz(nf);onSend(nf);},{passive:false});' +
|
'setHz(nf);onSend(nf);},{passive:false});' +
|
||||||
'el.addEventListener("dblclick",()=>{' +
|
'el.addEventListener("dblclick",()=>{' +
|
||||||
'const s=prompt("Set Hz",String(Math.round(getHz())));if(!s)return;' +
|
'const s=prompt("Set Hz",String(Math.round(getHz())));if(!s)return;' +
|
||||||
'const f=parseInt(s.replace(/[^0-9]/g,""),10);if(!isFinite(f))return;' +
|
'const f=parseInt(s.replace(/[^0-9]/g,""),10);if(!isFinite(f))return;' +
|
||||||
'const nf=cl(f,30000,60000000);setHz(nf);renderVfos();onSend(nf);' +
|
'const nf=cl(f,30000,freqMaxHz);setHz(nf);renderVfos();onSend(nf);' +
|
||||||
'});}' +
|
'});}' +
|
||||||
'bindVfo("vDispA",()=>vfoA,v=>{vfoA=v;},()=>stA,v=>{stA=v;},()=>stAmem,v=>{stAmem=v;},' +
|
'bindVfo("vDispA",()=>vfoA,v=>{vfoA=v;},()=>stA,v=>{stA=v;},()=>stAmem,v=>{stAmem=v;},' +
|
||||||
'function(nf){renderVfos();pend("freq");if(activeVfo==="A"){localCenter=nf;ws2({cmd:"freq",hz:nf});}else ws2({cmd:"freq_b",hz:nf});});' +
|
'function(nf){renderVfos();pend("freq");if(activeVfo==="A"){localCenter=nf;ws2({cmd:"freq",hz:nf});}else ws2({cmd:"freq_b",hz:nf});});' +
|
||||||
@@ -483,6 +489,7 @@ begin
|
|||||||
'}' +
|
'}' +
|
||||||
'if(!isPending("freq")){vfoA=cur.vfo_a_hz||vfoA;}' +
|
'if(!isPending("freq")){vfoA=cur.vfo_a_hz||vfoA;}' +
|
||||||
'if(msg.vfo_b_hz!=null)vfoB=msg.vfo_b_hz;' +
|
'if(msg.vfo_b_hz!=null)vfoB=msg.vfo_b_hz;' +
|
||||||
|
'if(msg.freq_mhz_digits!=null){freqMhzDigits=Math.max(3,Math.min(5,msg.freq_mhz_digits|0));freqMaxHz=Math.pow(10,freqMhzDigits+6)-1;}' +
|
||||||
'if(msg.active_vfo!=null&&!isPending("freq")){' +
|
'if(msg.active_vfo!=null&&!isPending("freq")){' +
|
||||||
'const sv=msg.active_vfo===0?"A":"B";' +
|
'const sv=msg.active_vfo===0?"A":"B";' +
|
||||||
'if(sv!==activeVfo){activeVfo=sv;' +
|
'if(sv!==activeVfo){activeVfo=sv;' +
|
||||||
|
|||||||
+5
-2
@@ -242,6 +242,7 @@ type
|
|||||||
FOnTun: TWebCmdTun;
|
FOnTun: TWebCmdTun;
|
||||||
FTuning: Boolean;
|
FTuning: Boolean;
|
||||||
FDuplex: Boolean;
|
FDuplex: Boolean;
|
||||||
|
FFreqMhzDigits: Integer; // 3=999MHz, 4=9.999GHz, 5=99.999GHz
|
||||||
FXvtrBands: TWebXvtrArray; // список enabled XVTR (для web-UI)
|
FXvtrBands: TWebXvtrArray; // список enabled XVTR (для web-UI)
|
||||||
FCurrentXvtr: Integer; // -1 = HF, иначе индекс активного XVTR
|
FCurrentXvtr: Integer; // -1 = HF, иначе индекс активного XVTR
|
||||||
FOnXvtrBand: TWebCmdXvtrBand;
|
FOnXvtrBand: TWebCmdXvtrBand;
|
||||||
@@ -292,6 +293,7 @@ type
|
|||||||
AttnIdx: Integer; Tuning: Boolean; Duplex: Boolean);
|
AttnIdx: Integer; Tuning: Boolean; Duplex: Boolean);
|
||||||
|
|
||||||
property WebClientActive: Boolean read FWebClientActive;
|
property WebClientActive: Boolean read FWebClientActive;
|
||||||
|
property FreqMhzDigits: Integer read FFreqMhzDigits write FFreqMhzDigits;
|
||||||
|
|
||||||
property OnFreq: TWebCmdFreq read FOnFreq write FOnFreq;
|
property OnFreq: TWebCmdFreq read FOnFreq write FOnFreq;
|
||||||
property OnMode: TWebCmdMode read FOnMode write FOnMode;
|
property OnMode: TWebCmdMode read FOnMode write FOnMode;
|
||||||
@@ -420,6 +422,7 @@ begin
|
|||||||
FSMeter := -120;
|
FSMeter := -120;
|
||||||
FBandIdx := 5;
|
FBandIdx := 5;
|
||||||
FCurrentXvtr := -1;
|
FCurrentXvtr := -1;
|
||||||
|
FFreqMhzDigits := 3;
|
||||||
SetLength(FXvtrBands, 0);
|
SetLength(FXvtrBands, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -1233,7 +1236,7 @@ begin
|
|||||||
'"running":%s,"mute":%s,"ctun":%s,' +
|
'"running":%s,"mute":%s,"ctun":%s,' +
|
||||||
'"nr_mode":%d,"nr":%s,"nb_mode":%d,"nb":%s,"snb":%s,"anf":%s,"connected":%s,' +
|
'"nr_mode":%d,"nr":%s,"nb_mode":%d,"nb":%s,"snb":%s,"anf":%s,"connected":%s,' +
|
||||||
'"transmitting":%s,"drive":%d,"attn_idx":%d,"tuning":%s,"dup":%s,' +
|
'"transmitting":%s,"drive":%d,"attn_idx":%d,"tuning":%s,"dup":%s,' +
|
||||||
'"xvtr_current":%d,"xvtr_bands":%s}',
|
'"xvtr_current":%d,"xvtr_bands":%s,"freq_mhz_digits":%d}',
|
||||||
[FFreq, FVfoB, FActiveVfo,
|
[FFreq, FVfoB, FActiveVfo,
|
||||||
FMode, MODE_N[FMode mod 8],
|
FMode, MODE_N[FMode mod 8],
|
||||||
FFilterIdx, FFilterBW,
|
FFilterIdx, FFilterBW,
|
||||||
@@ -1257,7 +1260,7 @@ begin
|
|||||||
FAttnIdx,
|
FAttnIdx,
|
||||||
BoolToStr(FTuning, 'true', 'false'),
|
BoolToStr(FTuning, 'true', 'false'),
|
||||||
BoolToStr(FDuplex, 'true', 'false'),
|
BoolToStr(FDuplex, 'true', 'false'),
|
||||||
FCurrentXvtr, XvtrJson
|
FCurrentXvtr, XvtrJson, FFreqMhzDigits
|
||||||
], FS);
|
], FS);
|
||||||
finally
|
finally
|
||||||
FStateLock.Leave;
|
FStateLock.Leave;
|
||||||
|
|||||||
Reference in New Issue
Block a user