mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 18:43:51 +00:00
add alert overlay
This commit is contained in:
@@ -0,0 +1,109 @@
|
|||||||
|
unit AlertOverlay;
|
||||||
|
|
||||||
|
{
|
||||||
|
Reusable overlays for spectrum-like bitmap surfaces.
|
||||||
|
}
|
||||||
|
|
||||||
|
{$IFDEF FPC}
|
||||||
|
{$MODE Delphi}
|
||||||
|
{$ENDIF}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Graphics, Types, Math;
|
||||||
|
|
||||||
|
procedure DrawAlertOverlay(Target: TBitmap; C: TCanvas; W, H: Integer;
|
||||||
|
const Title, Detail: string);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
procedure BlendRect(Target: TBitmap; const Rct: TRect; R, G, B, Alpha: Byte);
|
||||||
|
var
|
||||||
|
Y, X, InvA: Integer;
|
||||||
|
Row: PByte;
|
||||||
|
RR: TRect;
|
||||||
|
begin
|
||||||
|
if (Target = nil) or (Alpha = 0) then Exit;
|
||||||
|
RR := Rct;
|
||||||
|
if RR.Left < 0 then RR.Left := 0;
|
||||||
|
if RR.Top < 0 then RR.Top := 0;
|
||||||
|
if RR.Right > Target.Width then RR.Right := Target.Width;
|
||||||
|
if RR.Bottom > Target.Height then RR.Bottom := Target.Height;
|
||||||
|
if (RR.Right <= RR.Left) or (RR.Bottom <= RR.Top) then Exit;
|
||||||
|
|
||||||
|
InvA := 255 - Alpha;
|
||||||
|
Target.BeginUpdate(False);
|
||||||
|
try
|
||||||
|
for Y := RR.Top to RR.Bottom - 1 do
|
||||||
|
begin
|
||||||
|
Row := PByte(Target.ScanLine[Y]);
|
||||||
|
if Row = nil then Continue;
|
||||||
|
Inc(Row, RR.Left * 4);
|
||||||
|
for X := RR.Left to RR.Right - 1 do
|
||||||
|
begin
|
||||||
|
Row[0] := Byte((Alpha * B + InvA * Row[0]) div 255);
|
||||||
|
Row[1] := Byte((Alpha * G + InvA * Row[1]) div 255);
|
||||||
|
Row[2] := Byte((Alpha * R + InvA * Row[2]) div 255);
|
||||||
|
Inc(Row, 4);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Target.EndUpdate(False);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawAlertOverlay(Target: TBitmap; C: TCanvas; W, H: Integer;
|
||||||
|
const Title, Detail: string);
|
||||||
|
const
|
||||||
|
PAD = 12;
|
||||||
|
INNER_X = 12;
|
||||||
|
ACCENT_W = 4;
|
||||||
|
var
|
||||||
|
R, AccentR: TRect;
|
||||||
|
TW, DW, BoxW, BoxH: Integer;
|
||||||
|
begin
|
||||||
|
if (Target = nil) or (C = nil) then Exit;
|
||||||
|
if (W < 220) or (H < 60) then Exit;
|
||||||
|
|
||||||
|
C.Font.Name := 'Courier New';
|
||||||
|
C.Font.Style := [fsBold];
|
||||||
|
C.Font.Size := 9;
|
||||||
|
TW := C.TextWidth(Title);
|
||||||
|
C.Font.Style := [];
|
||||||
|
C.Font.Size := 7;
|
||||||
|
DW := C.TextWidth(Detail);
|
||||||
|
|
||||||
|
BoxW := Max(TW, DW) + INNER_X * 2 + ACCENT_W + 8;
|
||||||
|
BoxH := 42;
|
||||||
|
R := Rect(W - PAD - BoxW, PAD, W - PAD, PAD + BoxH);
|
||||||
|
|
||||||
|
BlendRect(Target, R, $A8, $10, $16, 118);
|
||||||
|
BlendRect(Target, Rect(R.Left, R.Top, R.Right, R.Top + 1), $FF, $68, $68, 80);
|
||||||
|
|
||||||
|
C.Brush.Style := bsClear;
|
||||||
|
C.Pen.Style := psSolid;
|
||||||
|
C.Pen.Width := 1;
|
||||||
|
C.Pen.Color := TColor($003838C8);
|
||||||
|
C.Rectangle(R);
|
||||||
|
|
||||||
|
AccentR := Rect(R.Left + 7, R.Top + 7, R.Left + 7 + ACCENT_W, R.Bottom - 7);
|
||||||
|
C.Brush.Style := bsSolid;
|
||||||
|
C.Brush.Color := TColor($002828F0);
|
||||||
|
C.Pen.Style := psClear;
|
||||||
|
C.FillRect(AccentR);
|
||||||
|
|
||||||
|
C.Brush.Style := bsClear;
|
||||||
|
C.Font.Name := 'Courier New';
|
||||||
|
C.Font.Style := [fsBold];
|
||||||
|
C.Font.Size := 9;
|
||||||
|
C.Font.Color := TColor($008888FF);
|
||||||
|
C.TextOut(R.Left + INNER_X + ACCENT_W + 8, R.Top + 7, Title);
|
||||||
|
|
||||||
|
C.Font.Style := [];
|
||||||
|
C.Font.Size := 7;
|
||||||
|
C.Font.Color := TColor($00C8C8E8);
|
||||||
|
C.TextOut(R.Left + INNER_X + ACCENT_W + 8, R.Top + 25, Detail);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
+17
-1
@@ -18,7 +18,8 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
|
Classes, SysUtils, Graphics, ExtCtrls, Controls, Math,
|
||||||
IntfGraphics, FPImage, LCLIntf, LCLType, GraphType, AppTheme;
|
IntfGraphics, FPImage, LCLIntf, LCLType, GraphType, AppTheme,
|
||||||
|
AlertOverlay;
|
||||||
|
|
||||||
const
|
const
|
||||||
SV_CLR_BG = TColor($00101010);
|
SV_CLR_BG = TColor($00101010);
|
||||||
@@ -98,6 +99,9 @@ type
|
|||||||
// красным сверху). Без DUP при TX оба флага True. Без TX оба False.
|
// красным сверху). Без DUP при TX оба флага True. Без TX оба False.
|
||||||
FTXOverlay: Boolean;
|
FTXOverlay: Boolean;
|
||||||
|
|
||||||
|
// ── ADC overload overlay ─────────────────────────────────────────────────
|
||||||
|
FADCOverloadVisible: Boolean;
|
||||||
|
|
||||||
// ── Marker ────────────────────────────────────────────────────────────────
|
// ── Marker ────────────────────────────────────────────────────────────────
|
||||||
FMarkerActive: Boolean;
|
FMarkerActive: Boolean;
|
||||||
FMarkerX: Integer;
|
FMarkerX: Integer;
|
||||||
@@ -139,6 +143,7 @@ type
|
|||||||
// Используется для прозрачной заливки полосы фильтра разными цветами
|
// Используется для прозрачной заливки полосы фильтра разными цветами
|
||||||
// (RX-зелёный / TX-красный) поверх градиента сетки.
|
// (RX-зелёный / TX-красный) поверх градиента сетки.
|
||||||
procedure BlendBand(X1, X2, H: Integer; R, G, B, Alpha: Byte);
|
procedure BlendBand(X1, X2, H: Integer; R, G, B, Alpha: Byte);
|
||||||
|
procedure DrawADCOverloadOverlay(C: TCanvas; W, H: Integer);
|
||||||
// Считает X1/X2 для полосы фильтра вокруг указанной частоты VFO, c учётом
|
// Считает X1/X2 для полосы фильтра вокруг указанной частоты VFO, c учётом
|
||||||
// текущего режима (LSB/USB/DSB и пр.) и FFilterBW.
|
// текущего режима (LSB/USB/DSB и пр.) и FFilterBW.
|
||||||
procedure CalcFilterBandX(VfoFreq: Double; W: Integer;
|
procedure CalcFilterBandX(VfoFreq: Double; W: Integer;
|
||||||
@@ -181,6 +186,9 @@ type
|
|||||||
property TXVfoIndex: Integer read FTXVfoIndex write FTXVfoIndex;
|
property TXVfoIndex: Integer read FTXVfoIndex write FTXVfoIndex;
|
||||||
property TXOverlay: Boolean read FTXOverlay write FTXOverlay;
|
property TXOverlay: Boolean read FTXOverlay write FTXOverlay;
|
||||||
|
|
||||||
|
// Test overlay for ADC overload; later this will be driven from HP Status.
|
||||||
|
property ADCOverloadVisible: Boolean read FADCOverloadVisible write FADCOverloadVisible;
|
||||||
|
|
||||||
// ── Маркер ────────────────────────────────────────────────────────────────
|
// ── Маркер ────────────────────────────────────────────────────────────────
|
||||||
property MarkerActive: Boolean read FMarkerActive write FMarkerActive;
|
property MarkerActive: Boolean read FMarkerActive write FMarkerActive;
|
||||||
property MarkerX: Integer read FMarkerX write FMarkerX;
|
property MarkerX: Integer read FMarkerX write FMarkerX;
|
||||||
@@ -433,6 +441,7 @@ begin
|
|||||||
FTXSpanHz := 192000.0;
|
FTXSpanHz := 192000.0;
|
||||||
FTXVfoIndex := 0;
|
FTXVfoIndex := 0;
|
||||||
FTXOverlay := False;
|
FTXOverlay := False;
|
||||||
|
FADCOverloadVisible := True; // test indicator; later driven by HP Status.
|
||||||
FSpectrumBufCount := 1024;
|
FSpectrumBufCount := 1024;
|
||||||
FWaterfallBufCount := 1024;
|
FWaterfallBufCount := 1024;
|
||||||
FWfFrameInterval := 2;
|
FWfFrameInterval := 2;
|
||||||
@@ -540,6 +549,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpectrumView.DrawADCOverloadOverlay(C: TCanvas; W, H: Integer);
|
||||||
|
begin
|
||||||
|
if not FADCOverloadVisible then Exit;
|
||||||
|
DrawAlertOverlay(FSpectrumBitmap, C, W, H, 'ADC OVERLOAD', 'Input clipping detected');
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TSpectrumView.CalcFilterBandX(VfoFreq: Double; W: Integer;
|
procedure TSpectrumView.CalcFilterBandX(VfoFreq: Double; W: Integer;
|
||||||
out X1, X2, VfoX: Integer);
|
out X1, X2, VfoX: Integer);
|
||||||
// Возвращает X-координаты левого/правого края полосы фильтра вокруг VfoFreq
|
// Возвращает X-координаты левого/правого края полосы фильтра вокруг VfoFreq
|
||||||
@@ -962,6 +977,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if FMarkerActive then DrawMarkerLine(C, W, H);
|
if FMarkerActive then DrawMarkerLine(C, W, H);
|
||||||
|
DrawADCOverloadOverlay(C, W, H);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// ────────────────────────────────────────────────────────────────────────────
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user