mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
ui(spectrum): полоса главного фильтра — как у слайсов, со своим оттенком
Главный фильтр рисовался иначе, чем слайсовые полосы, причём в CPU-пути сильнее, чем в GL. 1. Порядок отрисовки. Кромки, несущая и её треугольник у главного шли ПОСЛЕ кривой спектра, у слайсов — до неё, а в GL-вьюхе весь блок фильтров идёт перед DrawSpectrumCurve. Из-за этого на CPU главная полоса единственная лезла поверх сигнала и выглядела жирнее и ярче слайсовых при тех же цвете и толщине линий. Блок перенесён к слайсам, до кривой: порядок кадра теперь одинаков у обоих путей. 2. Заливка. Была НЕПРОЗРАЧНОЙ, рядом с просвечивающими слайсовыми смотрелась плотным блоком. Теперь та же полупрозрачность, что у слайсов; прозрачность вынесена в общие SPEC_BAND_ALPHA/SPEC_BAND_ALPHA_TX (VfoOverlay, рядом с палитрой слайсов) — раньше это были четыре магических числа по двум вьюхам. Осиротевшая FillBandRaw удалена. 3. Цвет. С полупрозрачностью полоса перестала читаться: SpecFilter (34,78,106) почти совпадает с нижним цветом фонового градиента спектра (31,79,108), и заливка давала не оттенок, а затемнение — над низом градиента выходило ровно (32,79,108), то есть фон. Полосе дан свой цвет темы SpecFilterBand: тёплый янтарь RGB(255,150,40) на тёмной (фон сине-стальной, тёплое на нём читается) и насыщённый зелёный RGB(60,150,60) на светлой. SpecFilter остался подложкой подписей AGC — иначе перекрасились бы и они. 4. Слайс B перекрашен из оранжевого в васильковый RGB(97,118,255): с янтарной полосой главного фильтра оранжевый стал неразличим. Оттенок выбран по свободному месту в круге: заняты 0°(TX), 31°(полоса), 55°(E), 132°(A), 190°(C), 195°(G), 276°(F), 308°(D); самый широкий промежуток 195..276°, середина ≈236°. Палитра одна на всё, поэтому вместе с полосой и несущей перекрашиваются буква слайса на спектре и бейдж во флаге VfoOverlay. Сборка ewsdr (--ws=qt6) и ewsdrd — ОК. На экране не проверено: нужен эфир со слайсами; цвета правятся одной строкой (SpecFilterBand в AppTheme, SLICE_COLORS в VfoOverlay). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+14
-1
@@ -54,6 +54,12 @@ type
|
||||
// Спектр — сигнал и маркеры
|
||||
SpecLine: TColor;
|
||||
SpecFilter: TColor;
|
||||
// Заливка полосы главного фильтра. Отдельно от SpecFilter (тот остался
|
||||
// подложкой подписей AGC): полоса теперь полупрозрачная, как у слайсов, и
|
||||
// цвет ей нужен СВОЙ — SpecFilter почти совпадает с нижним цветом фонового
|
||||
// градиента спектра, поэтому такая заливка читалась не оттенком, а
|
||||
// затемнением.
|
||||
SpecFilterBand: TColor;
|
||||
SpecFilterEdge: TColor;
|
||||
SpecAgcColor: TColor;
|
||||
SpecAgcHangColor: TColor;
|
||||
@@ -158,6 +164,10 @@ begin
|
||||
Result.SpecGrid := TColor($00685624);
|
||||
Result.SpecLine := TColor($0040FF80);
|
||||
Result.SpecFilter := TColor($006A4E22);
|
||||
// Оттенок полосы — тёплый янтарный, из семейства курсора VFO (Amber): фон
|
||||
// спектра сине-стальной, поэтому янтарь на нём читается как оттенок, а не
|
||||
// как «потемнее фона». RGB(255,150,40).
|
||||
Result.SpecFilterBand := TColor($002896FF);
|
||||
Result.SpecFilterEdge := TColor($0040FFCC);
|
||||
Result.SpecAgcColor := TColor($0000AAFF);
|
||||
Result.SpecAgcHangColor := TColor($00FFCC00);
|
||||
@@ -266,7 +276,10 @@ begin
|
||||
Result.SpecLabelText := TColor($00404038);
|
||||
Result.SpecGrid := TColor($00B8B4A4);
|
||||
Result.SpecLine := TColor($00006400); // тёмно-зелёная линия
|
||||
Result.SpecFilter := TColor($00C8DCC8); // светло-зелёная полоса фильтра
|
||||
Result.SpecFilter := TColor($00C8DCC8); // подложка подписей AGC
|
||||
// Полоса фильтра на светлой теме: насыщённее фона (тот пергаментный), иначе
|
||||
// при той же полупрозрачности её не видно. RGB(60,150,60).
|
||||
Result.SpecFilterBand := TColor($003C963C);
|
||||
Result.SpecFilterEdge := TColor($00407840);
|
||||
Result.SpecAgcColor := TColor($00904000); // тёмно-оранжевый AGC
|
||||
Result.SpecAgcHangColor := TColor($00802000);
|
||||
|
||||
+31
-57
@@ -185,7 +185,6 @@ type
|
||||
procedure DrawIMDMarkersRaw(W, H: Integer; DBmax, InvRange: Double);
|
||||
procedure RawCircle(CX, CY, R: Integer; Color: TColor);
|
||||
procedure BlendBand(X1, X2, H: Integer; R, G, B, Alpha: Byte);
|
||||
procedure FillBandRaw(X1, X2, H: Integer; Color: TColor);
|
||||
procedure CopyGridToSpectrum(W, H: Integer);
|
||||
procedure DrawADCOverloadRaw(W, H: Integer);
|
||||
procedure CalcFilterBandX(VfoFreq: Double; W: Integer;
|
||||
@@ -1168,41 +1167,6 @@ end;
|
||||
// Canvas.FillRect для полосы фильтра в DrawSpectrum: полоса рисуется в
|
||||
// raw-фазе (между memcpy сетки и градиентом), а FillRect дёргал бы Canvas
|
||||
// и форсил лишнюю синхронизацию битмапа на Qt6.
|
||||
procedure TSpectrumView.FillBandRaw(X1, X2, H: Integer; Color: TColor);
|
||||
var
|
||||
Y, W: Integer;
|
||||
Row: PLongWord;
|
||||
Px: LongWord;
|
||||
R, G, B: Byte;
|
||||
begin
|
||||
if FSpectrumBitmap = nil then Exit;
|
||||
W := FSpectrumBitmap.Width;
|
||||
if X1 < 0 then X1 := 0;
|
||||
if X2 > W then X2 := W;
|
||||
if X2 <= X1 then Exit;
|
||||
R := Color and $FF; G := (Color shr 8) and $FF; B := (Color shr 16) and $FF;
|
||||
{$IFDEF DARWIN}
|
||||
// ARGB в памяти (см. BlendBand): байт 0 = альфа, дальше R,G,B.
|
||||
Px := LongWord($FF) or (LongWord(R) shl 8) or (LongWord(G) shl 16) or
|
||||
(LongWord(B) shl 24);
|
||||
{$ELSE}
|
||||
// BGRA в памяти: байты B,G,R,A.
|
||||
Px := LongWord(B) or (LongWord(G) shl 8) or (LongWord(R) shl 16) or $FF000000;
|
||||
{$ENDIF}
|
||||
FSpectrumBitmap.BeginUpdate(False);
|
||||
try
|
||||
for Y := 0 to H - 1 do
|
||||
begin
|
||||
Row := PLongWord(FSpectrumBitmap.ScanLine[Y]);
|
||||
if Row = nil then Continue;
|
||||
Inc(Row, X1);
|
||||
FillDWord(Row^, X2 - X1, Px);
|
||||
end;
|
||||
finally
|
||||
FSpectrumBitmap.EndUpdate(False);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Маркер фильтра каждого слайса (B+) на спектре — полупрозрачная полоса
|
||||
// пропускания + края + центральная несущая. Янтарный цвет, как в GL-вьюхе
|
||||
// (SpectrumViewOpengl.DrawSliceFilterMarkers). Полосы (raw ScanLine-блендинг)
|
||||
@@ -1224,7 +1188,7 @@ begin
|
||||
CalcSliceBandX(O, W, SX1, SX2, SVfoX);
|
||||
if SX2 > SX1 then
|
||||
BlendBand(SX1, SX2, H, Clr and $FF, (Clr shr 8) and $FF, (Clr shr 16) and $FF,
|
||||
IfThen(O.TxActive, 100, 60));
|
||||
IfThen(O.TxActive, SPEC_BAND_ALPHA_TX, SPEC_BAND_ALPHA));
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -1789,7 +1753,14 @@ begin
|
||||
end else
|
||||
if X2 > X1 then BlendBand(X1, X2, H, $E0, $30, $30, 100);
|
||||
end else
|
||||
if X2 > X1 then FillBandRaw(X1, X2, H, FTheme.SpecFilter);
|
||||
// Полупрозрачная заливка тем же способом, что у слайсов (SPEC_BAND_ALPHA):
|
||||
// раньше главная полоса заливалась НЕПРОЗРАЧНО и выглядела плотным блоком
|
||||
// рядом с просвечивающими слайсовыми. Цвет — SpecFilterBand (свой, не
|
||||
// подложка подписей AGC): см. комментарий в AppTheme.
|
||||
if X2 > X1 then
|
||||
BlendBand(X1, X2, H, FTheme.SpecFilterBand and $FF,
|
||||
(FTheme.SpecFilterBand shr 8) and $FF,
|
||||
(FTheme.SpecFilterBand shr 16) and $FF, SPEC_BAND_ALPHA);
|
||||
|
||||
// Полосы фильтра слайсов (B+) — под градиентом/кривой, как в GL-вьюхе.
|
||||
DrawSliceFilterBands(W, H);
|
||||
@@ -1800,16 +1771,34 @@ begin
|
||||
DrawSpectrumGradient(FSpPts, W, H);
|
||||
|
||||
|
||||
// ★ Кромки, несущая и буква ГЛАВНОГО фильтра — здесь, ДО кривой спектра,
|
||||
// ровно как у слайсов ниже и как в GL-вьюхе (там весь блок фильтров идёт
|
||||
// перед DrawSpectrumCurve). Раньше этот кусок стоял ПОСЛЕ кривой, и на
|
||||
// CPU-пути главный фильтр единственный лез поверх сигнала — с виду толще и
|
||||
// ярче слайсовых, хотя цвета и толщина те же.
|
||||
RawVLine(X1, 0, H - 1, FTheme.SpecFilterEdge);
|
||||
RawVLine(X2, 0, H - 1, FTheme.SpecFilterEdge);
|
||||
// Буква главного флага (A) на его полосе — только когда есть слайсы,
|
||||
// иначе одиночный приём не засоряем. Букву запоминаем: под неё ниже
|
||||
// иначе одиночный приём не засоряем. Букву запоминаем: под неё
|
||||
// подстраиваются вертикаль несущей и её треугольник.
|
||||
MainLetter := #0;
|
||||
if (FSliceOverlays <> nil) and (FSliceOverlays.Count > 0) and
|
||||
(FActiveVfo = 0) and Assigned(FVfoOverlay) then
|
||||
begin
|
||||
MainLetter := FVfoOverlay.SliceLetter;
|
||||
DrawBandLetterRaw(X1, X2, MainLetter, SliceColor(MainLetter));
|
||||
CarrY := CarrierTopY(X1, X2, VfoX, MainLetter);
|
||||
RawVLine(VfoX, CarrY, H - 13, FTheme.SpecVfoCursor, 2);
|
||||
RawTriangleDown(VfoX, CarrY, 5, 8, FTheme.SpecVfoCursor);
|
||||
if FTXOverlay and (FTXVfoIndex <> FActiveVfo) then
|
||||
begin
|
||||
RawVLine(TXX1, 0, H - 1, TColor($002030E0));
|
||||
RawVLine(TXX2, 0, H - 1, TColor($002030E0));
|
||||
// Буква нарисована на RX-полосе (X1..X2) — с ней и сверяемся.
|
||||
CarrY := CarrierTopY(X1, X2, TXVfoX, MainLetter);
|
||||
RawVLine(TXVfoX, CarrY, H - 13, TColor($002030E0), 2);
|
||||
RawTriangleDown(TXVfoX, CarrY, 5, 8, TColor($002030E0));
|
||||
end;
|
||||
if MainLetter <> #0 then
|
||||
DrawBandLetterRaw(X1, X2, MainLetter, SliceColor(MainLetter));
|
||||
|
||||
// Края/несущие/буквы слайсов (полосы уже нарисованы выше).
|
||||
DrawSliceFilterLinesRaw(W, H);
|
||||
@@ -1845,22 +1834,7 @@ begin
|
||||
// Линия спектра
|
||||
RawCurve(W, FTheme.SpecLine);
|
||||
|
||||
// Края фильтра + VFO
|
||||
RawVLine(X1, 0, H - 1, FTheme.SpecFilterEdge);
|
||||
RawVLine(X2, 0, H - 1, FTheme.SpecFilterEdge);
|
||||
// Несущая и её треугольник — под буквой полосы, если она там есть.
|
||||
CarrY := CarrierTopY(X1, X2, VfoX, MainLetter);
|
||||
RawVLine(VfoX, CarrY, H - 13, FTheme.SpecVfoCursor, 2);
|
||||
RawTriangleDown(VfoX, CarrY, 5, 8, FTheme.SpecVfoCursor);
|
||||
if FTXOverlay and (FTXVfoIndex <> FActiveVfo) then
|
||||
begin
|
||||
RawVLine(TXX1, 0, H - 1, TColor($002030E0));
|
||||
RawVLine(TXX2, 0, H - 1, TColor($002030E0));
|
||||
// Буква нарисована на RX-полосе (X1..X2) — с ней и сверяемся.
|
||||
CarrY := CarrierTopY(X1, X2, TXVfoX, MainLetter);
|
||||
RawVLine(TXVfoX, CarrY, H - 13, TColor($002030E0), 2);
|
||||
RawTriangleDown(TXVfoX, CarrY, 5, 8, TColor($002030E0));
|
||||
end;
|
||||
// (кромки/несущая главного фильтра нарисованы выше — до кривой)
|
||||
|
||||
if FMarkerActive then DrawMarkerLineRaw(W, H);
|
||||
if FBeaconMarkActive or FBeaconDecActive then DrawBeaconMarkersRaw(W, H);
|
||||
|
||||
@@ -622,7 +622,10 @@ begin
|
||||
else if X2 > X1 then DrawRect(X1, 0, X2, H, CLR_TX_BAND, 100 / 255);
|
||||
end
|
||||
else if X2 > X1 then
|
||||
DrawRect(X1, 0, X2, H, FTheme.SpecFilter, 1);
|
||||
// Как у слайсов: полупрозрачная заливка (раньше здесь была alpha=1, и
|
||||
// главная полоса выглядела плотным блоком рядом с просвечивающими).
|
||||
// Цвет — SpecFilterBand, свой у полосы (см. AppTheme).
|
||||
DrawRect(X1, 0, X2, H, FTheme.SpecFilterBand, SPEC_BAND_ALPHA / 255);
|
||||
|
||||
// Буква главного флага (A) на его полосе — только когда есть слайсы. Саму
|
||||
// букву рисуем ниже, но знать о ней надо здесь: под неё уходит начало
|
||||
@@ -669,7 +672,8 @@ begin
|
||||
else Clr := SliceColor(O.SliceLetter);
|
||||
CalcSliceBandX(O, W, SX1, SX2, SVfoX);
|
||||
if SX2 > SX1 then
|
||||
DrawRect(SX1, 0, SX2, H, Clr, IfThen(O.TxActive, 100, 60) / 255);
|
||||
DrawRect(SX1, 0, SX2, H, Clr,
|
||||
IfThen(O.TxActive, SPEC_BAND_ALPHA_TX, SPEC_BAND_ALPHA) / 255);
|
||||
DrawLine(SX1, 0, SX1, H, Clr, 1, False);
|
||||
DrawLine(SX2, 0, SX2, H, Clr, 1, False);
|
||||
// Несущая — под буквой, если она приходится на неё (AM/FM/DSB).
|
||||
|
||||
+10
-1
@@ -38,7 +38,11 @@ const
|
||||
// бейджа-карточки во флаге и для буквы на полосе фильтра в спектре.
|
||||
SLICE_COLORS: array[0..7] of TColor = (
|
||||
TColor($0060E040), // A — зелёный
|
||||
TColor($0010A8FF), // B — оранжевый
|
||||
// B был оранжевым и спорил с янтарной полосой главного фильтра
|
||||
// (AppTheme.SpecFilterBand). Васильковый выбран по свободному месту в круге
|
||||
// оттенков: занято 0°(TX)/31°(полоса)/38/55/132/190/195/276/308, самый
|
||||
// широкий незанятый промежуток — 195..276°, середина ≈236°. RGB(97,118,255).
|
||||
TColor($00FF7661), // B — васильковый (indigo)
|
||||
TColor($00F0D030), // C — голубой
|
||||
TColor($00E070F0), // D — розовый/маджента
|
||||
TColor($0030E0F0), // E — жёлтый
|
||||
@@ -46,6 +50,11 @@ const
|
||||
TColor($00E0C060), // G — бирюзовый
|
||||
TColor($00C0C0C0)); // H — серый
|
||||
|
||||
// Прозрачность заливки полосы фильтра на спектре — одна на главный VFO и на
|
||||
// слайсы, чтобы полосы читались одинаково (и в CPU-, и в GL-вьюхе).
|
||||
SPEC_BAND_ALPHA = 60; // приём
|
||||
SPEC_BAND_ALPHA_TX = 100; // передающая полоса — плотнее
|
||||
|
||||
// Цвет слайса по его букве (A..). За пределами таблицы — по кругу.
|
||||
function SliceColor(L: Char): TColor;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user