mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-27 05:17:32 +00:00
Add AGC picker to VfoOverlay DSP row
AGC button in DSP row shows current mode (FAST/MED/SLOW/LONG/OFF). Click toggles a picker row below; selecting a mode closes it, fires OnAGCChange, and syncs MainForm BtnAGCMode buttons and DSP engine. Overlay height expands 136→159 px while picker is open. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+18
-3
@@ -665,6 +665,7 @@ type
|
|||||||
procedure PositionVfoOverlay;
|
procedure PositionVfoOverlay;
|
||||||
procedure OnModeFilterSelect(Mode: Integer; FilterBW: Integer);
|
procedure OnModeFilterSelect(Mode: Integer; FilterBW: Integer);
|
||||||
procedure OnVfoOverlayDSPChange(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
procedure OnVfoOverlayDSPChange(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
||||||
|
procedure OnVfoOverlayAGCChange(AGCMode: Integer);
|
||||||
procedure PbSpectrumDblClick(Sender: TObject);
|
procedure PbSpectrumDblClick(Sender: TObject);
|
||||||
procedure TrkDriveChange(Sender: TObject);
|
procedure TrkDriveChange(Sender: TObject);
|
||||||
procedure TrkVolumeChange(Sender: TObject);
|
procedure TrkVolumeChange(Sender: TObject);
|
||||||
@@ -1330,6 +1331,7 @@ begin
|
|||||||
FVfoOverlay := TVfoOverlay.Create(Self);
|
FVfoOverlay := TVfoOverlay.Create(Self);
|
||||||
FVfoOverlay.OnSelect := OnModeFilterSelect;
|
FVfoOverlay.OnSelect := OnModeFilterSelect;
|
||||||
FVfoOverlay.OnDSPChange := OnVfoOverlayDSPChange;
|
FVfoOverlay.OnDSPChange := OnVfoOverlayDSPChange;
|
||||||
|
FVfoOverlay.OnAGCChange := OnVfoOverlayAGCChange;
|
||||||
FVfoOverlay.Visible := False;
|
FVfoOverlay.Visible := False;
|
||||||
FPanelHidden := False;
|
FPanelHidden := False;
|
||||||
FShowSpectrum := True;
|
FShowSpectrum := True;
|
||||||
@@ -5397,9 +5399,9 @@ begin
|
|||||||
BtnHidePanel.Caption := '▶';
|
BtnHidePanel.Caption := '▶';
|
||||||
FVfoOverlay.Parent := PanelRight;
|
FVfoOverlay.Parent := PanelRight;
|
||||||
FVfoOverlay.Width := 260;
|
FVfoOverlay.Width := 260;
|
||||||
FVfoOverlay.Height := 136;
|
FVfoOverlay.Height := 136; // OVL_H_NORM — расширяется сам при открытии AGC-пикера
|
||||||
FVfoOverlay.SetState(FMode, FFilterBW, FVfoA, FLastSMeter);
|
FVfoOverlay.SetState(FMode, FFilterBW, FVfoA, FLastSMeter);
|
||||||
FVfoOverlay.SetDSPState(BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0);
|
FVfoOverlay.SetDSPState(BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0, FAGCMode);
|
||||||
FVfoOverlay.Visible := True;
|
FVfoOverlay.Visible := True;
|
||||||
FVfoOverlay.BringToFront;
|
FVfoOverlay.BringToFront;
|
||||||
PositionVfoOverlay;
|
PositionVfoOverlay;
|
||||||
@@ -5463,7 +5465,7 @@ begin
|
|||||||
if Assigned(FVfoOverlay) and FVfoOverlay.Visible then
|
if Assigned(FVfoOverlay) and FVfoOverlay.Visible then
|
||||||
begin
|
begin
|
||||||
FVfoOverlay.SetState(FMode, FFilterBW, FVfoA, FLastSMeter);
|
FVfoOverlay.SetState(FMode, FFilterBW, FVfoA, FLastSMeter);
|
||||||
FVfoOverlay.SetDSPState(BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0);
|
FVfoOverlay.SetDSPState(BtnNR.Tag, BtnNB.Tag, BtnSNB.Tag <> 0, BtnANF.Tag <> 0, FAGCMode);
|
||||||
PositionVfoOverlay; // перепозиционируем при смене LSB↔USB
|
PositionVfoOverlay; // перепозиционируем при смене LSB↔USB
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -5477,6 +5479,19 @@ begin
|
|||||||
ApplyNoiseFilterButtonsToDSP;
|
ApplyNoiseFilterButtonsToDSP;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMainForm.OnVfoOverlayAGCChange(AGCMode: Integer);
|
||||||
|
const
|
||||||
|
AGCModes: array[0..4] of TWDSPAGCMode = (agcFast, agcMedium, agcSlow, agcLong, agcOff);
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
FAGCMode := AGCMode;
|
||||||
|
for I := 0 to 4 do StyleButton(BtnAGCMode[I], I = AGCMode);
|
||||||
|
if FWDSPReady then
|
||||||
|
FDSPEngine.SetAGC(AGCModes[AGCMode], 50.0);
|
||||||
|
FBandCache[FCurrentBand].AGCMode := FAGCMode;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMainForm.BtnSpanClick(Sender: TObject);
|
procedure TMainForm.BtnSpanClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
NewRate: Integer;
|
NewRate: Integer;
|
||||||
|
|||||||
+109
-26
@@ -10,6 +10,7 @@ uses
|
|||||||
type
|
type
|
||||||
TModeFilterEvent = procedure(Mode: Integer; FilterBW: Integer) of object;
|
TModeFilterEvent = procedure(Mode: Integer; FilterBW: Integer) of object;
|
||||||
TDSPChangeEvent = procedure(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean) of object;
|
TDSPChangeEvent = procedure(NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean) of object;
|
||||||
|
TAGCChangeEvent = procedure(AGCMode: Integer) of object;
|
||||||
|
|
||||||
TVfoOverlay = class(TCustomControl)
|
TVfoOverlay = class(TCustomControl)
|
||||||
private
|
private
|
||||||
@@ -17,17 +18,20 @@ type
|
|||||||
FFilterBW: Integer;
|
FFilterBW: Integer;
|
||||||
FVfoHz: Double;
|
FVfoHz: Double;
|
||||||
FSMeterDB: Double;
|
FSMeterDB: Double;
|
||||||
FOnSelect: TModeFilterEvent;
|
FOnSelect: TModeFilterEvent;
|
||||||
FOnDSPChange: TDSPChangeEvent;
|
FOnDSPChange: TDSPChangeEvent;
|
||||||
|
FOnAGCChange: TAGCChangeEvent;
|
||||||
FModeFilter: array[0..7] of Integer;
|
FModeFilter: array[0..7] of Integer;
|
||||||
|
|
||||||
FNRMode: Integer; // 0=off, 1..4=NR/NR2/NR3/NR4
|
FNRMode: Integer; // 0=off, 1..4=NR/NR2/NR3/NR4
|
||||||
FNBMode: Integer; // 0=off, 1=NB, 2=NB2
|
FNBMode: Integer; // 0=off, 1=NB, 2=NB2
|
||||||
FSNBOn: Boolean;
|
FSNBOn: Boolean;
|
||||||
FANFOn: Boolean;
|
FANFOn: Boolean;
|
||||||
|
FAGCMode: Integer; // 0=FAST 1=MED 2=SLOW 3=LONG 4=OFF
|
||||||
|
FAGCPickerOpen: Boolean;
|
||||||
|
|
||||||
FHitRects: array[0..19] of TRect;
|
FHitRects: array[0..24] of TRect;
|
||||||
FHitActions: array[0..19] of Integer; // <0 = режим/DSP, >0 = BW фильтра
|
FHitActions: array[0..24] of Integer;
|
||||||
FHitCount: Integer;
|
FHitCount: Integer;
|
||||||
FHotIdx: Integer;
|
FHotIdx: Integer;
|
||||||
|
|
||||||
@@ -36,6 +40,7 @@ type
|
|||||||
procedure DrawModeRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
procedure DrawModeRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
||||||
procedure DrawFilterRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
procedure DrawFilterRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
||||||
procedure DrawDSPRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
procedure DrawDSPRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
||||||
|
procedure DrawAGCPickerRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
||||||
procedure RegisterHit(HR: TRect; HV: Integer);
|
procedure RegisterHit(HR: TRect; HV: Integer);
|
||||||
function CalcSLabel: string;
|
function CalcSLabel: string;
|
||||||
function FormatFreq(Hz: Double): string;
|
function FormatFreq(Hz: Double): string;
|
||||||
@@ -53,11 +58,13 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(AOwner: TComponent); override;
|
constructor Create(AOwner: TComponent); override;
|
||||||
procedure SetState(AMode, ABW: Integer; AVfoHz, ASMeterDB: Double);
|
procedure SetState(AMode, ABW: Integer; AVfoHz, ASMeterDB: Double);
|
||||||
procedure SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean);
|
procedure SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean;
|
||||||
|
AAGCMode: Integer);
|
||||||
procedure UpdateSMeter(DB: Double);
|
procedure UpdateSMeter(DB: Double);
|
||||||
procedure UpdateVfo(AVfoHz: Double);
|
procedure UpdateVfo(AVfoHz: Double);
|
||||||
property OnSelect: TModeFilterEvent read FOnSelect write FOnSelect;
|
property OnSelect: TModeFilterEvent read FOnSelect write FOnSelect;
|
||||||
property OnDSPChange: TDSPChangeEvent read FOnDSPChange write FOnDSPChange;
|
property OnDSPChange: TDSPChangeEvent read FOnDSPChange write FOnDSPChange;
|
||||||
|
property OnAGCChange: TAGCChangeEvent read FOnAGCChange write FOnAGCChange;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -67,6 +74,14 @@ const
|
|||||||
HIT_NB = -10;
|
HIT_NB = -10;
|
||||||
HIT_SNB = -11;
|
HIT_SNB = -11;
|
||||||
HIT_ANF = -12;
|
HIT_ANF = -12;
|
||||||
|
HIT_AGC = -13;
|
||||||
|
|
||||||
|
HIT_AGC_PICK_BASE = 100000; // 100000+N — выбор режима AGC (>всех BW фильтров)
|
||||||
|
|
||||||
|
AGC_NAMES: array[0..4] of string = ('FAST', 'MED', 'SLOW', 'LONG', 'OFF');
|
||||||
|
|
||||||
|
OVL_H_NORM = 136; // высота без пикера AGC
|
||||||
|
OVL_H_AGC = 159; // высота с открытым пикером (136 + GAP(3) + ROW_H(20))
|
||||||
|
|
||||||
CLR_PANEL_BG = TColor($00141414);
|
CLR_PANEL_BG = TColor($00141414);
|
||||||
CLR_BORDER = TColor($00505050);
|
CLR_BORDER = TColor($00505050);
|
||||||
@@ -185,12 +200,14 @@ begin
|
|||||||
FModeFilter[5] := 11000; // FM (NFM по умолчанию)
|
FModeFilter[5] := 11000; // FM (NFM по умолчанию)
|
||||||
FModeFilter[6] := 8000; // AM
|
FModeFilter[6] := 8000; // AM
|
||||||
FModeFilter[7] := 8000; // SAM
|
FModeFilter[7] := 8000; // SAM
|
||||||
FNRMode := 0;
|
FNRMode := 0;
|
||||||
FNBMode := 0;
|
FNBMode := 0;
|
||||||
FSNBOn := False;
|
FSNBOn := False;
|
||||||
FANFOn := False;
|
FANFOn := False;
|
||||||
Width := 260;
|
FAGCMode := 0;
|
||||||
Height := 136;
|
FAGCPickerOpen := False;
|
||||||
|
Width := 260;
|
||||||
|
Height := OVL_H_NORM;
|
||||||
Cursor := crHandPoint;
|
Cursor := crHandPoint;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -356,8 +373,8 @@ end;
|
|||||||
|
|
||||||
procedure TVfoOverlay.DrawDSPRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
procedure TVfoOverlay.DrawDSPRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
||||||
const
|
const
|
||||||
DSP_COUNT = 4;
|
DSP_COUNT = 5;
|
||||||
DSP_HITS: array[0..3] of Integer = (HIT_NR, HIT_NB, HIT_SNB, HIT_ANF);
|
DSP_HITS: array[0..4] of Integer = (HIT_NR, HIT_NB, HIT_SNB, HIT_ANF, HIT_AGC);
|
||||||
var
|
var
|
||||||
I, BX, BRight: Integer;
|
I, BX, BRight: Integer;
|
||||||
HR: TRect;
|
HR: TRect;
|
||||||
@@ -386,6 +403,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
2: begin Lbl := 'SNB'; IsAct := FSNBOn; end;
|
2: begin Lbl := 'SNB'; IsAct := FSNBOn; end;
|
||||||
3: begin Lbl := 'ANF'; IsAct := FANFOn; end;
|
3: begin Lbl := 'ANF'; IsAct := FANFOn; end;
|
||||||
|
4: begin Lbl := AGC_NAMES[FAGCMode]; IsAct := FAGCPickerOpen; end;
|
||||||
else Lbl := ''; IsAct := False;
|
else Lbl := ''; IsAct := False;
|
||||||
end;
|
end;
|
||||||
IsHot := (FHotIdx >= 0) and (FHitActions[FHotIdx] = DSP_HITS[I]);
|
IsHot := (FHotIdx >= 0) and (FHitActions[FHotIdx] = DSP_HITS[I]);
|
||||||
@@ -410,6 +428,43 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TVfoOverlay.DrawAGCPickerRow(C: TCanvas; X, Y, RowW, RowH: Integer);
|
||||||
|
const
|
||||||
|
AGC_COUNT = 5;
|
||||||
|
var
|
||||||
|
I, BX, BRight: Integer;
|
||||||
|
HR: TRect;
|
||||||
|
IsAct, IsHot: Boolean;
|
||||||
|
begin
|
||||||
|
BX := X;
|
||||||
|
for I := 0 to AGC_COUNT - 1 do
|
||||||
|
begin
|
||||||
|
BRight := X + ((I + 1) * RowW) div AGC_COUNT;
|
||||||
|
HR := Rect(BX, Y, BRight, Y + RowH);
|
||||||
|
IsAct := (I = FAGCMode);
|
||||||
|
IsHot := (FHotIdx >= 0) and
|
||||||
|
(FHitActions[FHotIdx] = HIT_AGC_PICK_BASE + I);
|
||||||
|
|
||||||
|
if IsAct then C.Brush.Color := CLR_BTN_ACT
|
||||||
|
else if IsHot then C.Brush.Color := CLR_BTN_HOT
|
||||||
|
else C.Brush.Color := CLR_BTN_NORM;
|
||||||
|
C.Brush.Style := bsSolid; C.Pen.Style := psClear;
|
||||||
|
C.FillRect(HR);
|
||||||
|
C.Pen.Style := psSolid; C.Pen.Color := CLR_BORDER;
|
||||||
|
C.Brush.Style := bsClear; C.Rectangle(HR);
|
||||||
|
|
||||||
|
if IsAct then C.Font.Color := CLR_ACCENT
|
||||||
|
else C.Font.Color := CLR_TEXT;
|
||||||
|
C.Font.Size := 7; C.Font.Name := 'Courier New';
|
||||||
|
C.Brush.Style := bsClear;
|
||||||
|
C.TextOut(BX + (BRight - BX - C.TextWidth(AGC_NAMES[I])) div 2,
|
||||||
|
Y + (RowH - C.TextHeight('A')) div 2, AGC_NAMES[I]);
|
||||||
|
|
||||||
|
RegisterHit(HR, HIT_AGC_PICK_BASE + I);
|
||||||
|
BX := BRight + 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TVfoOverlay.DrawSelf(C: TCanvas; W, H: Integer);
|
procedure TVfoOverlay.DrawSelf(C: TCanvas; W, H: Integer);
|
||||||
const
|
const
|
||||||
PAD = 4;
|
PAD = 4;
|
||||||
@@ -463,8 +518,15 @@ begin
|
|||||||
DrawFilterRow(C, PAD, CurY, W - PAD * 2, ROW_H);
|
DrawFilterRow(C, PAD, CurY, W - PAD * 2, ROW_H);
|
||||||
Inc(CurY, ROW_H + GAP);
|
Inc(CurY, ROW_H + GAP);
|
||||||
|
|
||||||
// Кнопки DSP (NR, NB, SNB, ANF)
|
// Кнопки DSP (NR, NB, SNB, ANF, AGC)
|
||||||
DrawDSPRow(C, PAD, CurY, W - PAD * 2, ROW_H);
|
DrawDSPRow(C, PAD, CurY, W - PAD * 2, ROW_H);
|
||||||
|
|
||||||
|
// Пикер AGC (открывается кнопкой AGC)
|
||||||
|
if FAGCPickerOpen then
|
||||||
|
begin
|
||||||
|
Inc(CurY, ROW_H + GAP);
|
||||||
|
DrawAGCPickerRow(C, PAD, CurY, W - PAD * 2, ROW_H);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TVfoOverlay.Paint;
|
procedure TVfoOverlay.Paint;
|
||||||
@@ -501,17 +563,36 @@ begin
|
|||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
// Кнопка DSP
|
// Кнопка DSP
|
||||||
case HV of
|
if HV = HIT_AGC then
|
||||||
HIT_NR: FNRMode := (FNRMode + 1) mod 5;
|
begin
|
||||||
HIT_NB: FNBMode := (FNBMode + 1) mod 3;
|
FAGCPickerOpen := not FAGCPickerOpen;
|
||||||
HIT_SNB: FSNBOn := not FSNBOn;
|
if FAGCPickerOpen then Height := OVL_H_AGC
|
||||||
HIT_ANF: FANFOn := not FANFOn;
|
else Height := OVL_H_NORM;
|
||||||
|
Invalidate;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
case HV of
|
||||||
|
HIT_NR: FNRMode := (FNRMode + 1) mod 5;
|
||||||
|
HIT_NB: FNBMode := (FNBMode + 1) mod 3;
|
||||||
|
HIT_SNB: FSNBOn := not FSNBOn;
|
||||||
|
HIT_ANF: FANFOn := not FANFOn;
|
||||||
|
end;
|
||||||
|
Invalidate;
|
||||||
|
if Assigned(FOnDSPChange) then
|
||||||
|
FOnDSPChange(FNRMode, FNBMode, FSNBOn, FANFOn);
|
||||||
end;
|
end;
|
||||||
Invalidate;
|
|
||||||
if Assigned(FOnDSPChange) then
|
|
||||||
FOnDSPChange(FNRMode, FNBMode, FSNBOn, FANFOn);
|
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
|
else if HV >= HIT_AGC_PICK_BASE then
|
||||||
|
begin
|
||||||
|
// Выбор режима AGC из пикера
|
||||||
|
FAGCMode := HV - HIT_AGC_PICK_BASE;
|
||||||
|
FAGCPickerOpen := False;
|
||||||
|
Height := OVL_H_NORM;
|
||||||
|
Invalidate;
|
||||||
|
if Assigned(FOnAGCChange) then FOnAGCChange(FAGCMode);
|
||||||
|
end
|
||||||
else if HV > 0 then
|
else if HV > 0 then
|
||||||
begin
|
begin
|
||||||
NewBW := HV;
|
NewBW := HV;
|
||||||
@@ -556,12 +637,14 @@ begin
|
|||||||
Invalidate;
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TVfoOverlay.SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean);
|
procedure TVfoOverlay.SetDSPState(ANRMode, ANBMode: Integer; ASNBOn, AANFOn: Boolean;
|
||||||
|
AAGCMode: Integer);
|
||||||
begin
|
begin
|
||||||
FNRMode := ANRMode;
|
FNRMode := ANRMode;
|
||||||
FNBMode := ANBMode;
|
FNBMode := ANBMode;
|
||||||
FSNBOn := ASNBOn;
|
FSNBOn := ASNBOn;
|
||||||
FANFOn := AANFOn;
|
FANFOn := AANFOn;
|
||||||
|
FAGCMode := AAGCMode;
|
||||||
Invalidate;
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user