mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Merge feature/pan-grid-two-col: грид панов из двух колонок + FM-сетка на доп. панадаптерах
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+133
-34
@@ -189,11 +189,12 @@ type
|
|||||||
FPanSplitTop0: Integer;
|
FPanSplitTop0: Integer;
|
||||||
FPanSplitMinTop: Integer;
|
FPanSplitMinTop: Integer;
|
||||||
FPanSplitMaxTop: Integer;
|
FPanSplitMaxTop: Integer;
|
||||||
// Грид-раскладка: пан 0 сверху во всю ширину, доп. паны колонками снизу.
|
// Грид-раскладка: при >=2 доп. панах — пан 0 сверху во всю ширину, доп.
|
||||||
// Активна при FPanGridMode и >=2 доп. панах в стеке (иначе обычный стек).
|
// паны колонками снизу; при ОДНОМ доп. пане — две колонки бок о бок
|
||||||
|
// (пан 0 слева, доп. справа). Активна при FPanGridMode и >=1 доп. пане.
|
||||||
FPanGridMode: Boolean;
|
FPanGridMode: Boolean;
|
||||||
FPanGridRowShare: Double; // доля высоты верхнего ряда (пан 0), 0.15..0.85
|
FPanGridRowShare: Double; // доля высоты верхнего ряда (пан 0), 0.15..0.85
|
||||||
FPanColShare: array[1..MAX_PANS-1] of Double; // доли ширины колонок
|
FPanColShare: array[0..MAX_PANS-1] of Double; // доли ширины колонок
|
||||||
FPanVSplitters: array[1..MAX_PANS-1] of TPanel; // слева от колонки пана i
|
FPanVSplitters: array[1..MAX_PANS-1] of TPanel; // слева от колонки пана i
|
||||||
FPansRestored: Boolean; // персист панов восстановлен в этой Run-сессии
|
FPansRestored: Boolean; // персист панов восстановлен в этой Run-сессии
|
||||||
// Drag вертикального сплиттера (индекс пана справа; 0 = нет).
|
// Drag вертикального сплиттера (индекс пана справа; 0 = нет).
|
||||||
@@ -684,6 +685,8 @@ type
|
|||||||
procedure PanSplitMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
procedure PanSplitMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
||||||
procedure OnPanGridToggle(Sender: TObject); // «▦/▤» в ряду зума пана 0
|
procedure OnPanGridToggle(Sender: TObject); // «▦/▤» в ряду зума пана 0
|
||||||
function PanGridActive: Boolean; // грид реально применён
|
function PanGridActive: Boolean; // грид реально применён
|
||||||
|
function PanGridTwoCol: Boolean; // грид из 2 колонок (пан 0 + 1)
|
||||||
|
function ExtraPanCount: Integer; // доп. паны в раскладке
|
||||||
procedure PanVSplitMouseDown(Sender: TObject; Button: TMouseButton;
|
procedure PanVSplitMouseDown(Sender: TObject; Button: TMouseButton;
|
||||||
Shift: TShiftState; X, Y: Integer);
|
Shift: TShiftState; X, Y: Integer);
|
||||||
procedure PanVSplitMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
procedure PanVSplitMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
||||||
@@ -1172,6 +1175,7 @@ begin
|
|||||||
FPan.OnDisplayClick := OnPanDisplayClick; // «◑» дисплей-поповер (3.6)
|
FPan.OnDisplayClick := OnPanDisplayClick; // «◑» дисплей-поповер (3.6)
|
||||||
FPans[0] := FPan;
|
FPans[0] := FPan;
|
||||||
FPanShare[0] := 1.0;
|
FPanShare[0] := 1.0;
|
||||||
|
FPanColShare[0] := 1.0; // грид «две колонки»: пан 0 — тоже колонка
|
||||||
FPanGridMode := False;
|
FPanGridMode := False;
|
||||||
FPanGridRowShare := 0.5; // грид: пан 0 — верхняя половина
|
FPanGridRowShare := 0.5; // грид: пан 0 — верхняя половина
|
||||||
FPanCbLock := SyncObjs.TCriticalSection.Create;
|
FPanCbLock := SyncObjs.TCriticalSection.Create;
|
||||||
@@ -2700,7 +2704,7 @@ procedure TMainForm.ResizeSpectrumPanels;
|
|||||||
const
|
const
|
||||||
WB_H = 118;
|
WB_H = 118;
|
||||||
var
|
var
|
||||||
RW, RH, WideH, WideSpecH: Integer;
|
RW, RH, WideH, WideSpecH, WideTop: Integer;
|
||||||
RULER_H: Integer;
|
RULER_H: Integer;
|
||||||
PANZOOM_H: Integer;
|
PANZOOM_H: Integer;
|
||||||
begin
|
begin
|
||||||
@@ -2721,10 +2725,13 @@ begin
|
|||||||
WideH := Min(MulDiv(WB_H, Screen.PixelsPerInch, 96), Max(40, RH div 2));
|
WideH := Min(MulDiv(WB_H, Screen.PixelsPerInch, 96), Max(40, RH div 2));
|
||||||
if WideH > 0 then
|
if WideH > 0 then
|
||||||
WideSpecH := Max(1, WideH - RULER_H);
|
WideSpecH := Max(1, WideH - RULER_H);
|
||||||
|
// Wideband — всегда во всю ширину PanelRight, самой верхней полосой.
|
||||||
|
// В обычном стеке над ним стоит шапка пана 0; в гриде «две колонки» шапки
|
||||||
|
// панов уходят в свои колонки ПОД wideband, поэтому он начинается с нуля.
|
||||||
|
WideTop := IfThen(PanGridTwoCol, 0, Pan0HeaderH);
|
||||||
if PbWideband <> nil then
|
if PbWideband <> nil then
|
||||||
begin
|
begin
|
||||||
// При стеке панов над wideband стоит шапка пана 0.
|
PbWideband.SetBounds(0, WideTop, RW, WideSpecH);
|
||||||
PbWideband.SetBounds(0, Pan0HeaderH, RW, WideSpecH);
|
|
||||||
PbWideband.Visible := FController.FShowWideband and (WideSpecH > 0);
|
PbWideband.Visible := FController.FShowWideband and (WideSpecH > 0);
|
||||||
if FController.FShowWideband and (RW > 0) and (WideSpecH > 0) then
|
if FController.FShowWideband and (RW > 0) and (WideSpecH > 0) then
|
||||||
begin
|
begin
|
||||||
@@ -2734,7 +2741,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
if PbWidebandRuler <> nil then
|
if PbWidebandRuler <> nil then
|
||||||
begin
|
begin
|
||||||
PbWidebandRuler.SetBounds(0, Pan0HeaderH + WideSpecH, RW, IfThen(FController.FShowWideband and (WideH > 0), RULER_H, 0));
|
PbWidebandRuler.SetBounds(0, WideTop + WideSpecH, RW, IfThen(FController.FShowWideband and (WideH > 0), RULER_H, 0));
|
||||||
PbWidebandRuler.Visible := FController.FShowWideband and (WideH > 0);
|
PbWidebandRuler.Visible := FController.FShowWideband and (WideH > 0);
|
||||||
if FController.FShowWideband and (RW > 0) and (WideH > 0) then
|
if FController.FShowWideband and (RW > 0) and (WideH > 0) then
|
||||||
begin
|
begin
|
||||||
@@ -2748,6 +2755,14 @@ begin
|
|||||||
// Стек панов: регионы по долям, каждый пан раскладывает свой стек
|
// Стек панов: регионы по долям, каждый пан раскладывает свой стек
|
||||||
// спектр/линейка/сплиттер/водопад/пан-зум внутри своего региона.
|
// спектр/линейка/сплиттер/водопад/пан-зум внутри своего региона.
|
||||||
LayoutPanStack(WideH);
|
LayoutPanStack(WideH);
|
||||||
|
// Доп. панадаптер приходит со своим слайсом и сразу показывает его флаг —
|
||||||
|
// главный приёмник должен быть представлен флагом A с того же момента
|
||||||
|
// (раньше флаг A появлялся только от слайса, созданного на самом пане 0).
|
||||||
|
if FPan <> nil then
|
||||||
|
begin
|
||||||
|
FPan.MainFlagForced := PanCount > 1;
|
||||||
|
FPan.UpdateMainFlagVisibility;
|
||||||
|
end;
|
||||||
PositionSampleRateOverlay;
|
PositionSampleRateOverlay;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -2768,15 +2783,26 @@ begin
|
|||||||
Result := 0;
|
Result := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TMainForm.PanGridActive: Boolean;
|
function TMainForm.ExtraPanCount: Integer;
|
||||||
// Грид реально применён: включён юзером и в стеке >=2 доп. панов
|
// Доп. паны (без пана 0), участвующие в раскладке (плавающие не в счёт).
|
||||||
// (с одним доп. паном грид совпадает со стеком).
|
var i: Integer;
|
||||||
var i, N: Integer;
|
|
||||||
begin
|
begin
|
||||||
N := 0;
|
Result := 0;
|
||||||
for i := 1 to MAX_PANS - 1 do
|
for i := 1 to MAX_PANS - 1 do
|
||||||
if (FPans[i] <> nil) and not PanFloating(i) then Inc(N);
|
if (FPans[i] <> nil) and not PanFloating(i) then Inc(Result);
|
||||||
Result := FPanGridMode and (N >= 2);
|
end;
|
||||||
|
|
||||||
|
function TMainForm.PanGridActive: Boolean;
|
||||||
|
// Грид реально применён: включён юзером и есть хотя бы один доп. пан в стеке.
|
||||||
|
begin
|
||||||
|
Result := FPanGridMode and (ExtraPanCount >= 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TMainForm.PanGridTwoCol: Boolean;
|
||||||
|
// Частный случай грида: пан 0 + ОДИН доп. пан = две колонки бок о бок во всю
|
||||||
|
// высоту (верхнего ряда/горизонтального сплиттера нет).
|
||||||
|
begin
|
||||||
|
Result := FPanGridMode and (ExtraPanCount = 1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TMainForm.PanMinHeight(PanId: Integer): Integer;
|
function TMainForm.PanMinHeight(PanId: Integer): Integer;
|
||||||
@@ -2795,7 +2821,7 @@ const
|
|||||||
var
|
var
|
||||||
ActiveIds: array[0..MAX_PANS-1] of Integer;
|
ActiveIds: array[0..MAX_PANS-1] of Integer;
|
||||||
MinH: array[0..MAX_PANS-1] of Integer;
|
MinH: array[0..MAX_PANS-1] of Integer;
|
||||||
N, i, k, TotalH, TotalW, UsableH, UsableW, Y, X, Hi, Wi: Integer;
|
N, i, k, TotalH, TotalW, UsableH, UsableW, Y, X, Hi, Wi, MinW: Integer;
|
||||||
Row0H, RowTop, RowH, M, MinRest, RemainH, BotMin: Integer;
|
Row0H, RowTop, RowH, M, MinRest, RemainH, BotMin: Integer;
|
||||||
ShareSum: Double;
|
ShareSum: Double;
|
||||||
Grid: Boolean;
|
Grid: Boolean;
|
||||||
@@ -2809,14 +2835,15 @@ begin
|
|||||||
FPanWideH := AWideH; // для PanMinHeight (в т.ч. из сплиттер-драга)
|
FPanWideH := AWideH; // для PanMinHeight (в т.ч. из сплиттер-драга)
|
||||||
TotalH := PanelRight.ClientHeight;
|
TotalH := PanelRight.ClientHeight;
|
||||||
TotalW := PanelRight.ClientWidth;
|
TotalW := PanelRight.ClientWidth;
|
||||||
Grid := PanGridActive; // пан 0 + >=2 доп. панов колонками
|
Grid := PanGridActive; // 2 колонки (пан 0 + 1 доп.) либо ряд + колонки
|
||||||
|
|
||||||
// Тумблер «▦/▤» в ряду зума пана 0: есть смысл при >=2 доп. панах в стеке.
|
// Тумблер «▦/▤» в ряду зума пана 0: есть смысл уже при ОДНОМ доп. пане
|
||||||
|
// (грид = пан 0 и доп. пан бок о бок вместо «друг под другом»).
|
||||||
if FPans[0] <> nil then
|
if FPans[0] <> nil then
|
||||||
begin
|
begin
|
||||||
// Виден при >=2 доп. панах; при включённом гриде — всегда (выключить можно
|
// Виден при >=1 доп. пане; при включённом гриде — всегда (выключить можно
|
||||||
// даже когда паны закрылись и раскладка сама откатилась в стек).
|
// даже когда паны закрылись и раскладка сама откатилась в стек).
|
||||||
FPans[0].GridBtnEnabled := FPanGridMode or (N >= 3);
|
FPans[0].GridBtnEnabled := FPanGridMode or (N >= 2);
|
||||||
if FPans[0].BtnGrid <> nil then
|
if FPans[0].BtnGrid <> nil then
|
||||||
begin
|
begin
|
||||||
if FPanGridMode then FPans[0].BtnGrid.Caption := '▤'
|
if FPanGridMode then FPans[0].BtnGrid.Caption := '▤'
|
||||||
@@ -2885,6 +2912,47 @@ begin
|
|||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if PanGridTwoCol then
|
||||||
|
begin
|
||||||
|
// ---- Грид «две колонки»: пан 0 слева, единственный доп. пан справа ----
|
||||||
|
// Wideband остаётся сверху во всю ширину (его полосу кладёт
|
||||||
|
// ResizeSpectrumPanels), обе колонки начинаются ПОД ним и идут до низа;
|
||||||
|
// между ними вертикальный сплиттер (доли FPanColShare[0]/FPanColShare[доп]).
|
||||||
|
i := ActiveIds[1]; // единственный застекованный доп. пан
|
||||||
|
for k := 1 to MAX_PANS - 1 do
|
||||||
|
begin
|
||||||
|
if FPanSplitters[k] <> nil then FPanSplitters[k].Visible := False;
|
||||||
|
if (k <> i) and (FPanVSplitters[k] <> nil) then
|
||||||
|
FPanVSplitters[k].Visible := False;
|
||||||
|
end;
|
||||||
|
FPans[0].HeaderVisible := Pan0HeaderVisible;
|
||||||
|
FPans[i].HeaderVisible := True;
|
||||||
|
UsableW := TotalW - PAN_SPLIT_H;
|
||||||
|
ShareSum := FPanColShare[0] + FPanColShare[i];
|
||||||
|
if ShareSum <= 0 then ShareSum := 1;
|
||||||
|
MinW := Round(0.15 * TotalW); // = кламп драга вертикального сплиттера
|
||||||
|
Wi := Round(UsableW * FPanColShare[0] / ShareSum);
|
||||||
|
if Wi < MinW then Wi := MinW;
|
||||||
|
if Wi > UsableW - MinW then Wi := UsableW - MinW;
|
||||||
|
if Wi < 1 then Wi := 1;
|
||||||
|
RowTop := AWideH; // низ полосы wideband = верх обеих колонок
|
||||||
|
RowH := TotalH - RowTop;
|
||||||
|
FPans[0].StackTop := RowTop;
|
||||||
|
FPans[0].StackHeight := RowH;
|
||||||
|
FPans[0].StackLeft := 0;
|
||||||
|
FPans[0].StackWidth := Wi;
|
||||||
|
// ATopOffset=0: wideband вне региона пана 0 (он уже учтён в StackTop).
|
||||||
|
FPans[0].Layout(0, FController.FShowSpectrum, FController.FShowWaterfall);
|
||||||
|
FPanVSplitters[i].Visible := True;
|
||||||
|
FPanVSplitters[i].SetBounds(Wi, RowTop, PAN_SPLIT_H, RowH);
|
||||||
|
FPans[i].StackTop := RowTop;
|
||||||
|
FPans[i].StackHeight := RowH;
|
||||||
|
FPans[i].StackLeft := Wi + PAN_SPLIT_H;
|
||||||
|
FPans[i].StackWidth := TotalW - Wi - PAN_SPLIT_H;
|
||||||
|
FPans[i].Layout(0, FController.FShowSpectrum, FController.FShowWaterfall);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
// ---- Грид: пан 0 сверху во всю ширину, доп. паны колонками снизу ----
|
// ---- Грид: пан 0 сверху во всю ширину, доп. паны колонками снизу ----
|
||||||
FPanGridRowShare := EnsureRange(FPanGridRowShare, 0.15, 0.85);
|
FPanGridRowShare := EnsureRange(FPanGridRowShare, 0.15, 0.85);
|
||||||
Row0H := Round((TotalH - PAN_SPLIT_H) * FPanGridRowShare);
|
Row0H := Round((TotalH - PAN_SPLIT_H) * FPanGridRowShare);
|
||||||
@@ -3466,8 +3534,13 @@ begin
|
|||||||
// Важно: проверяем только видимые панели — когда спектр скрыт,
|
// Важно: проверяем только видимые панели — когда спектр скрыт,
|
||||||
// PbSpectrum.Height может быть ненулевым при FPan.SpectrumHeight=0,
|
// PbSpectrum.Height может быть ненулевым при FPan.SpectrumHeight=0,
|
||||||
// что вызвало бы сброс буфера водопада на каждом тике.
|
// что вызвало бы сброс буфера водопада на каждом тике.
|
||||||
|
// Wideband сверяем с шириной PanelRight, а НЕ со спектром пана 0: в гриде
|
||||||
|
// «две колонки» пан 0 — половина ширины, а wideband остаётся во всю (иначе
|
||||||
|
// условие вечно истинно и тик дёргает ResizeSpectrumPanels каждый кадр —
|
||||||
|
// раскладка пересчитывается под курсором и сплиттеры не тянутся).
|
||||||
if (FPan.SpectrumWidth = 0) or
|
if (FPan.SpectrumWidth = 0) or
|
||||||
(FController.FShowWideband and (PbWideband.Width <> FPan.SpectrumWidth)) or
|
(FController.FShowWideband and (PanelRight <> nil) and
|
||||||
|
(PbWideband.Width <> PanelRight.ClientWidth)) or
|
||||||
(FController.FShowSpectrum and ((PbSpectrum.Width <> FPan.SpectrumWidth) or
|
(FController.FShowSpectrum and ((PbSpectrum.Width <> FPan.SpectrumWidth) or
|
||||||
(PbSpectrum.Height <> FPan.SpectrumHeight))) or
|
(PbSpectrum.Height <> FPan.SpectrumHeight))) or
|
||||||
(FController.FShowWaterfall and not FController.FShowSpectrum and
|
(FController.FShowWaterfall and not FController.FShowSpectrum and
|
||||||
@@ -5910,12 +5983,24 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.SyncPanZoomUI(P: TPanafallPanel);
|
procedure TMainForm.SyncPanZoomUI(P: TPanafallPanel);
|
||||||
// Вьюха и зум-бар пана ← контроллер (после смены зума/центра/rate пана).
|
// Вьюха и зум-бар пана ← контроллер (после смены зума/центра/rate пана).
|
||||||
var VC, VS: Double;
|
var VC, VS, StepHz: Double;
|
||||||
begin
|
begin
|
||||||
if (P = nil) or (P.PanId = 0) then Exit;
|
if (P = nil) or (P.PanId = 0) then Exit;
|
||||||
FController.GetPanViewWindow(P.PanId, VC, VS);
|
FController.GetPanViewWindow(P.PanId, VC, VS);
|
||||||
P.View.CenterFreq := VC;
|
P.View.CenterFreq := VC;
|
||||||
P.View.SpanHz := VS;
|
P.View.SpanHz := VS;
|
||||||
|
// Сетка каналов по шагу FM — как на главном пане, но по режиму слайсов
|
||||||
|
// ЭТОГО пана (у доп. панов нет своего FMode).
|
||||||
|
if FController.PanHasFMSlice(P.PanId) then
|
||||||
|
StepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
|
else
|
||||||
|
StepHz := 0;
|
||||||
|
if Abs(P.View.FMGridStepHz - StepHz) > 0.5 then
|
||||||
|
begin
|
||||||
|
P.View.FMGridStepHz := StepHz; // сеттер сам сбросит кэши спектра/линейки
|
||||||
|
MarkPanDirty(P);
|
||||||
|
if P.PbRuler <> nil then P.PbRuler.Invalidate;
|
||||||
|
end;
|
||||||
P.ZoomBar.SetFreq(FController.PanDDCFreq(P.PanId),
|
P.ZoomBar.SetFreq(FController.PanDDCFreq(P.PanId),
|
||||||
FController.PanDDCRateKHz(P.PanId) * 1000.0);
|
FController.PanDDCRateKHz(P.PanId) * 1000.0);
|
||||||
P.ZoomBar.SetState(FController.PanZoomFactor(P.PanId),
|
P.ZoomBar.SetState(FController.PanZoomFactor(P.PanId),
|
||||||
@@ -6349,7 +6434,7 @@ procedure TMainForm.PanClickTune(P: TPanafallPanel; X, W: Integer);
|
|||||||
var
|
var
|
||||||
VC, VS, LoHz, HiHz: Double;
|
VC, VS, LoHz, HiHz: Double;
|
||||||
Hz, StepHz: Int64;
|
Hz, StepHz: Int64;
|
||||||
Id: Integer;
|
Id, ModeHere: Integer;
|
||||||
S: TCtrlSlice;
|
S: TCtrlSlice;
|
||||||
begin
|
begin
|
||||||
PanViewWindow(P, VC, VS);
|
PanViewWindow(P, VC, VS);
|
||||||
@@ -6359,11 +6444,18 @@ begin
|
|||||||
Id := FActiveSliceId
|
Id := FActiveSliceId
|
||||||
else
|
else
|
||||||
Id := P.FirstSliceId;
|
Id := P.FirstSliceId;
|
||||||
|
// Канальные режимы: клик садится на ту же сетку, что нарисована на пане.
|
||||||
|
if Id <> 0 then
|
||||||
|
begin
|
||||||
|
if FController.GetSlice(Id, S) then ModeHere := S.Mode
|
||||||
|
else ModeHere := FController.FMode;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ModeHere := FController.FMode;
|
||||||
|
if (ModeHere in [MODE_FM, MODE_DMR, MODE_FMRAW]) and FController.FFMStepOn then
|
||||||
|
StepHz := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
|
else
|
||||||
StepHz := 100;
|
StepHz := 100;
|
||||||
if ((Id <> 0) and FController.GetSlice(Id, S) and
|
|
||||||
(S.Mode in [MODE_DMR, MODE_FMRAW])) or
|
|
||||||
((Id = 0) and (FController.FMode in [MODE_DMR, MODE_FMRAW])) then
|
|
||||||
StepHz := 12500;
|
|
||||||
Hz := Round(VC + (X / W - 0.5) * VS);
|
Hz := Round(VC + (X / W - 0.5) * VS);
|
||||||
Hz := ((Hz + StepHz div 2) div StepHz) * StepHz;
|
Hz := ((Hz + StepHz div 2) div StepHz) * StepHz;
|
||||||
FController.CapturedSpan(LoHz, HiHz, P.PanId);
|
FController.CapturedSpan(LoHz, HiHz, P.PanId);
|
||||||
@@ -6714,6 +6806,7 @@ begin
|
|||||||
for i := 0 to MAX_PANS - 1 do
|
for i := 0 to MAX_PANS - 1 do
|
||||||
begin
|
begin
|
||||||
Cfg.Pans[i].StackShare := FPanShare[i];
|
Cfg.Pans[i].StackShare := FPanShare[i];
|
||||||
|
Cfg.Pans[i].ColShare := FPanColShare[i]; // пан 0 — колонка в гриде «2 колонки»
|
||||||
if FPans[i] <> nil then Cfg.Pans[i].SplitRatio := FPans[i].SplitterRatio;
|
if FPans[i] <> nil then Cfg.Pans[i].SplitRatio := FPans[i].SplitterRatio;
|
||||||
if i > 0 then
|
if i > 0 then
|
||||||
begin
|
begin
|
||||||
@@ -6724,7 +6817,6 @@ begin
|
|||||||
Cfg.Pans[i].ADC := FController.PanADC(i);
|
Cfg.Pans[i].ADC := FController.PanADC(i);
|
||||||
Cfg.Pans[i].Zoom := FController.PanZoomFactor(i);
|
Cfg.Pans[i].Zoom := FController.PanZoomFactor(i);
|
||||||
Cfg.Pans[i].PanSlider := FController.PanPanSlider(i);
|
Cfg.Pans[i].PanSlider := FController.PanPanSlider(i);
|
||||||
Cfg.Pans[i].ColShare := FPanColShare[i];
|
|
||||||
// Per-pan дисплей (3.6): пишем override только если пан его задал.
|
// Per-pan дисплей (3.6): пишем override только если пан его задал.
|
||||||
if (FPans[i] <> nil) and FPans[i].DisplayOverride then
|
if (FPans[i] <> nil) and FPans[i].DisplayOverride then
|
||||||
begin
|
begin
|
||||||
@@ -6823,6 +6915,7 @@ begin
|
|||||||
|
|
||||||
// Пан 0: восстановить его доп. слайсы (главный VFO — не слайс) + доли.
|
// Пан 0: восстановить его доп. слайсы (главный VFO — не слайс) + доли.
|
||||||
FPanShare[0] := Cfg.Pans[0].StackShare;
|
FPanShare[0] := Cfg.Pans[0].StackShare;
|
||||||
|
FPanColShare[0] := Cfg.Pans[0].ColShare;
|
||||||
FPan.SplitterRatio := Cfg.Pans[0].SplitRatio;
|
FPan.SplitterRatio := Cfg.Pans[0].SplitRatio;
|
||||||
for k := 0 to High(Cfg.Pans[0].Slices) do
|
for k := 0 to High(Cfg.Pans[0].Slices) do
|
||||||
RestoreSliceInto(FPan, 0, Cfg.Pans[0].Slices[k]);
|
RestoreSliceInto(FPan, 0, Cfg.Pans[0].Slices[k]);
|
||||||
@@ -7086,6 +7179,7 @@ var
|
|||||||
Split: TPanel;
|
Split: TPanel;
|
||||||
begin
|
begin
|
||||||
if Button <> mbLeft then Exit;
|
if Button <> mbLeft then Exit;
|
||||||
|
if PanGridTwoCol then Exit; // две колонки: горизонтальных сплиттеров нет
|
||||||
Split := TPanel(Sender);
|
Split := TPanel(Sender);
|
||||||
BelowId := Split.Tag;
|
BelowId := Split.Tag;
|
||||||
TotalH := PanelRight.ClientHeight;
|
TotalH := PanelRight.ClientHeight;
|
||||||
@@ -7148,7 +7242,7 @@ begin
|
|||||||
TPanel(Sender).Color := TColor($00303030);
|
TPanel(Sender).Color := TColor($00303030);
|
||||||
TotalH := PanelRight.ClientHeight;
|
TotalH := PanelRight.ClientHeight;
|
||||||
if TotalH <= 0 then Exit;
|
if TotalH <= 0 then Exit;
|
||||||
if PanGridActive then
|
if PanGridActive and not PanGridTwoCol then
|
||||||
begin
|
begin
|
||||||
// Грид: сплиттер задаёт долю высоты верхнего ряда (пан 0) напрямую.
|
// Грид: сплиттер задаёт долю высоты верхнего ряда (пан 0) напрямую.
|
||||||
FPanGridRowShare := EnsureRange(TPanel(Sender).Top / TotalH, 0.15, 0.85);
|
FPanGridRowShare := EnsureRange(TPanel(Sender).Top / TotalH, 0.15, 0.85);
|
||||||
@@ -7190,9 +7284,10 @@ begin
|
|||||||
if (Button <> mbLeft) or not PanGridActive then Exit;
|
if (Button <> mbLeft) or not PanGridActive then Exit;
|
||||||
Split := TPanel(Sender);
|
Split := TPanel(Sender);
|
||||||
RightId := Split.Tag;
|
RightId := Split.Tag;
|
||||||
// Колонка слева — ближайший застекованный доп. пан с меньшим PanId.
|
// Колонка слева — ближайший застекованный пан с меньшим PanId (в гриде из
|
||||||
|
// двух колонок левая колонка — сам пан 0, в ряду колонок — доп. пан).
|
||||||
LeftId := -1;
|
LeftId := -1;
|
||||||
for i := RightId - 1 downto 1 do
|
for i := RightId - 1 downto IfThen(PanGridTwoCol, 0, 1) do
|
||||||
if (FPans[i] <> nil) and not PanFloating(i) then begin LeftId := i; Break; end;
|
if (FPans[i] <> nil) and not PanFloating(i) then begin LeftId := i; Break; end;
|
||||||
if (LeftId < 0) or (FPans[RightId] = nil) then Exit;
|
if (LeftId < 0) or (FPans[RightId] = nil) then Exit;
|
||||||
TotalW := PanelRight.ClientWidth;
|
TotalW := PanelRight.ClientWidth;
|
||||||
@@ -7231,14 +7326,14 @@ begin
|
|||||||
FPanVSplitDrag := 0;
|
FPanVSplitDrag := 0;
|
||||||
TPanel(Sender).Color := TColor($00303030);
|
TPanel(Sender).Color := TColor($00303030);
|
||||||
LeftId := -1;
|
LeftId := -1;
|
||||||
for i := RightId - 1 downto 1 do
|
for i := RightId - 1 downto IfThen(PanGridTwoCol, 0, 1) do
|
||||||
if (FPans[i] <> nil) and not PanFloating(i) then begin LeftId := i; Break; end;
|
if (FPans[i] <> nil) and not PanFloating(i) then begin LeftId := i; Break; end;
|
||||||
if (LeftId < 0) or (FPans[RightId] = nil) then Exit;
|
if (LeftId < 0) or (FPans[RightId] = nil) then Exit;
|
||||||
TotalW := PanelRight.ClientWidth;
|
TotalW := PanelRight.ClientWidth;
|
||||||
if TotalW <= 0 then Exit;
|
if TotalW <= 0 then Exit;
|
||||||
// Доли колонок нормируются суммой (init 1.0 на пан) — пиксели → доли через неё.
|
// Доли колонок нормируются суммой (init 1.0 на пан) — пиксели → доли через неё.
|
||||||
ShareSum := 0;
|
ShareSum := 0;
|
||||||
for i := 1 to MAX_PANS - 1 do
|
for i := IfThen(PanGridTwoCol, 0, 1) to MAX_PANS - 1 do
|
||||||
if (FPans[i] <> nil) and not PanFloating(i) then
|
if (FPans[i] <> nil) and not PanFloating(i) then
|
||||||
ShareSum := ShareSum + FPanColShare[i];
|
ShareSum := ShareSum + FPanColShare[i];
|
||||||
if ShareSum <= 0 then ShareSum := 1;
|
if ShareSum <= 0 then ShareSum := 1;
|
||||||
@@ -7927,8 +8022,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
if (SliceId <> 0) and FController.GetSlice(SliceId, Sl) then
|
if (SliceId <> 0) and FController.GetSlice(SliceId, Sl) then
|
||||||
begin
|
begin
|
||||||
if (Sl.Mode in [MODE_DMR, MODE_FMRAW]) and
|
// Канальные режимы: шаг = выбранный шаг сетки (тот же, что рисуется на
|
||||||
not ((ssCtrl in Shift) or (ssShift in Shift)) then Step := 12500
|
// пане), как на главном панадаптере. Ctrl/Shift — обычные мелкие шаги.
|
||||||
|
if (Sl.Mode in [MODE_FM, MODE_DMR, MODE_FMRAW]) and
|
||||||
|
FController.FFMStepOn and
|
||||||
|
not ((ssCtrl in Shift) or (ssShift in Shift)) then
|
||||||
|
Step := FM_STEP_HZ[FController.FFMStepIdx]
|
||||||
else if (ssCtrl in Shift) and (ssShift in Shift) then Step := 1000000
|
else if (ssCtrl in Shift) and (ssShift in Shift) then Step := 1000000
|
||||||
else if ssCtrl in Shift then Step := 1000
|
else if ssCtrl in Shift then Step := 1000
|
||||||
else if ssShift in Shift then Step := 10
|
else if ssShift in Shift then Step := 10
|
||||||
|
|||||||
+11
-5
@@ -84,6 +84,7 @@ type
|
|||||||
FActiveFlag: TVfoOverlay; // чьё событие сейчас обрабатывается
|
FActiveFlag: TVfoOverlay; // чьё событие сейчас обрабатывается
|
||||||
FPendingSliceClose: Integer; // SliceId к удалению после мыши (0=нет)
|
FPendingSliceClose: Integer; // SliceId к удалению после мыши (0=нет)
|
||||||
FMainFlagPinned: Boolean; // True = левая панель хозяина скрыта
|
FMainFlagPinned: Boolean; // True = левая панель хозяина скрыта
|
||||||
|
FMainFlagForced: Boolean; // True = есть доп. панадаптеры
|
||||||
FLastSliceMeterMs: QWord; // троттлинг S-метра слайсов (~10 Гц)
|
FLastSliceMeterMs: QWord; // троттлинг S-метра слайсов (~10 Гц)
|
||||||
FLastSliceDMRMs: QWord; // семантический DMR-статус (~4 Гц)
|
FLastSliceDMRMs: QWord; // семантический DMR-статус (~4 Гц)
|
||||||
FOnWireFlag: TWireFlagEvent;
|
FOnWireFlag: TWireFlagEvent;
|
||||||
@@ -278,7 +279,8 @@ type
|
|||||||
function CursorOverDisplay: Boolean; // курсор над спектром/водопадом пана
|
function CursorOverDisplay: Boolean; // курсор над спектром/водопадом пана
|
||||||
// Единый packing всех флагов (A+B+) в один ряд, без наездов.
|
// Единый packing всех флагов (A+B+) в один ряд, без наездов.
|
||||||
procedure LayoutFlags;
|
procedure LayoutFlags;
|
||||||
// Флаг A виден: панель хозяина скрыта (MainFlagPinned) ИЛИ есть слайсы B+.
|
// Флаг A виден: панель хозяина скрыта (MainFlagPinned) ИЛИ есть слайсы B+
|
||||||
|
// ИЛИ хозяин требует его принудительно (MainFlagForced — доп. панадаптеры).
|
||||||
procedure UpdateMainFlagVisibility;
|
procedure UpdateMainFlagVisibility;
|
||||||
procedure PushSliceFlagState(SliceId: Integer);
|
procedure PushSliceFlagState(SliceId: Integer);
|
||||||
procedure PushAllSliceFlagStates; // все флаги панели (после смены rate и т.п.)
|
procedure PushAllSliceFlagStates; // все флаги панели (после смены rate и т.п.)
|
||||||
@@ -297,6 +299,9 @@ type
|
|||||||
property Controller: TRadioController read FController write FController;
|
property Controller: TRadioController read FController write FController;
|
||||||
property MainFlag: TVfoOverlay read FMainFlag;
|
property MainFlag: TVfoOverlay read FMainFlag;
|
||||||
property MainFlagPinned: Boolean read FMainFlagPinned write FMainFlagPinned;
|
property MainFlagPinned: Boolean read FMainFlagPinned write FMainFlagPinned;
|
||||||
|
// Хозяин форсит флаг A (есть доп. панадаптеры — их слайсы должны быть
|
||||||
|
// представлены флагом и на главном приёмнике).
|
||||||
|
property MainFlagForced: Boolean read FMainFlagForced write FMainFlagForced;
|
||||||
// Проводка семантических событий флага (MODE/DSP/AUD/…) — хозяин.
|
// Проводка семантических событий флага (MODE/DSP/AUD/…) — хозяин.
|
||||||
property OnWireFlag: TWireFlagEvent read FOnWireFlag write FOnWireFlag;
|
property OnWireFlag: TWireFlagEvent read FOnWireFlag write FOnWireFlag;
|
||||||
// Слайс закрыт «×» — хозяину сбросить активный слайс и т.п.
|
// Слайс закрыт «×» — хозяину сбросить активный слайс и т.п.
|
||||||
@@ -1286,15 +1291,16 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// Флаг главного приёмника (слайс A) виден, когда СКРЫТА левая панель хозяина
|
// Флаг главного приёмника (слайс A) виден, когда СКРЫТА левая панель хозяина
|
||||||
// (MainFlagPinned) ЛИБО есть доп. слайсы (B+): тогда A всегда представлен
|
// (MainFlagPinned) ЛИБО есть доп. слайсы (B+) ЛИБО живут доп. панадаптеры
|
||||||
// флагом рядом с B/C…, а сворачивание/раскрытие панели при живых слайсах не
|
// (MainFlagForced — их слайсы уже показаны флагами, главный приёмник должен
|
||||||
// дёргает его появление.
|
// быть представлен так же): тогда A всегда представлен флагом рядом с B/C…,
|
||||||
|
// а сворачивание/раскрытие панели при живых слайсах не дёргает его появление.
|
||||||
procedure TPanafallPanel.UpdateMainFlagVisibility;
|
procedure TPanafallPanel.UpdateMainFlagVisibility;
|
||||||
var
|
var
|
||||||
ShouldShow: Boolean;
|
ShouldShow: Boolean;
|
||||||
begin
|
begin
|
||||||
if (FMainFlag = nil) or (FController = nil) then Exit;
|
if (FMainFlag = nil) or (FController = nil) then Exit;
|
||||||
ShouldShow := FMainFlagPinned or (Length(FSliceFlags) > 0);
|
ShouldShow := FMainFlagPinned or FMainFlagForced or (Length(FSliceFlags) > 0);
|
||||||
if ShouldShow = FMainFlag.Visible then Exit;
|
if ShouldShow = FMainFlag.Visible then Exit;
|
||||||
if ShouldShow then
|
if ShouldShow then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -649,6 +649,7 @@ type
|
|||||||
procedure SetSliceMute(Id: Integer; Mute: Boolean);
|
procedure SetSliceMute(Id: Integer; Mute: Boolean);
|
||||||
procedure SetSliceRxMuteOnTx(Id: Integer; On_: Boolean); // self-monitor слайса на TX
|
procedure SetSliceRxMuteOnTx(Id: Integer; On_: Boolean); // self-monitor слайса на TX
|
||||||
function PanPrimarySliceId(PanId: Integer): Integer; // первый созданный слайс пана
|
function PanPrimarySliceId(PanId: Integer): Integer; // первый созданный слайс пана
|
||||||
|
function PanHasFMSlice(PanId: Integer): Boolean; // есть слайс в канальном режиме (FM/DMR/FMRAW)?
|
||||||
procedure SetSliceDSP(Id, NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
procedure SetSliceDSP(Id, NRMode, NBMode: Integer; SNBOn, ANFOn: Boolean);
|
||||||
procedure SetSliceFMSquelch(Id: Integer; On_: Boolean; Level: Integer);
|
procedure SetSliceFMSquelch(Id: Integer; On_: Boolean; Level: Integer);
|
||||||
function SliceSMeter(Id: Integer): Double; // dBm, из DSP-потока
|
function SliceSMeter(Id: Integer): Double; // dBm, из DSP-потока
|
||||||
@@ -2093,6 +2094,21 @@ begin
|
|||||||
Result := FSlices[i].Id;
|
Result := FSlices[i].Id;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TRadioController.PanHasFMSlice(PanId: Integer): Boolean;
|
||||||
|
// Пан «канальный», если хотя бы один его слайс сидит в FM/DMR/FMRAW: под это
|
||||||
|
// UI рисует сетку частот по шагу FFMStepIdx (как на главном панадаптере).
|
||||||
|
var i: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
for i := 0 to MAX_SLICES - 1 do
|
||||||
|
if FSlices[i].Active and (FSlices[i].PanId = PanId) and
|
||||||
|
(FSlices[i].Mode in [MODE_FM, MODE_DMR, MODE_FMRAW]) then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TRadioController.SetSliceDSP(Id, NRMode, NBMode: Integer;
|
procedure TRadioController.SetSliceDSP(Id, NRMode, NBMode: Integer;
|
||||||
SNBOn, ANFOn: Boolean);
|
SNBOn, ANFOn: Boolean);
|
||||||
var idx: Integer;
|
var idx: Integer;
|
||||||
|
|||||||
+21
-3
@@ -539,6 +539,7 @@ type
|
|||||||
procedure ApplySNBToChan(Chan: Integer; On_: Boolean);
|
procedure ApplySNBToChan(Chan: Integer; On_: Boolean);
|
||||||
procedure ApplyANFToChan(Chan: Integer; On_: Boolean);
|
procedure ApplyANFToChan(Chan: Integer; On_: Boolean);
|
||||||
procedure ApplyFMSQToChan(Chan: Integer; Enable: Boolean; Level: Integer);
|
procedure ApplyFMSQToChan(Chan: Integer; Enable: Boolean; Level: Integer);
|
||||||
|
procedure ApplySliceFMSQ(Idx: Integer); // squelch слайса с гейтом по режиму
|
||||||
procedure ApplyNoiseFilterState;
|
procedure ApplyNoiseFilterState;
|
||||||
procedure ProcessTXBlock; // вызывается из TTXDSPThread
|
procedure ProcessTXBlock; // вызывается из TTXDSPThread
|
||||||
procedure FeedTXDisplaySample(const I, Q: Double);
|
procedure FeedTXDisplaySample(const I, Q: Double);
|
||||||
@@ -2394,7 +2395,8 @@ begin
|
|||||||
ApplyNBToChan(Chan, FSlices[Idx].NBMode);
|
ApplyNBToChan(Chan, FSlices[Idx].NBMode);
|
||||||
ApplySNBToChan(Chan, FSlices[Idx].SNBOn);
|
ApplySNBToChan(Chan, FSlices[Idx].SNBOn);
|
||||||
ApplyANFToChan(Chan, FSlices[Idx].ANFOn);
|
ApplyANFToChan(Chan, FSlices[Idx].ANFOn);
|
||||||
ApplyFMSQToChan(Chan, FSlices[Idx].FMSQOn, FSlices[Idx].FMSQLevel);
|
ApplyFMSQToChan(Chan, FSlices[Idx].FMSQOn and (FSlices[Idx].Mode = MODE_FM),
|
||||||
|
FSlices[Idx].FMSQLevel);
|
||||||
// Decoder input must not disappear or change scale with speaker volume.
|
// Decoder input must not disappear or change scale with speaker volume.
|
||||||
if FSlices[Idx].Mode in [MODE_DMR, MODE_FMRAW] then
|
if FSlices[Idx].Mode in [MODE_DMR, MODE_FMRAW] then
|
||||||
SetRXAPanelGain1(Chan, 1.0)
|
SetRXAPanelGain1(Chan, 1.0)
|
||||||
@@ -2693,6 +2695,9 @@ begin
|
|||||||
SetRXAPanelGain1(FSlices[idx].Chan, 1.0)
|
SetRXAPanelGain1(FSlices[idx].Chan, 1.0)
|
||||||
else
|
else
|
||||||
SetRXAPanelGain1(FSlices[idx].Chan, FSlices[idx].Volume);
|
SetRXAPanelGain1(FSlices[idx].Chan, FSlices[idx].Volume);
|
||||||
|
// Ушли из FM — снять squelch (иначе слайс остаётся заглушенным, а
|
||||||
|
// шумодава в не-FM режимах нет); вернулись в FM — восстановить выбор.
|
||||||
|
ApplySliceFMSQ(idx);
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
FSliceLock.Leave;
|
FSliceLock.Leave;
|
||||||
@@ -2821,13 +2826,26 @@ begin
|
|||||||
idx := FindSliceIdx(Id); if idx < 0 then Exit;
|
idx := FindSliceIdx(Id); if idx < 0 then Exit;
|
||||||
FSlices[idx].FMSQOn := Enable;
|
FSlices[idx].FMSQOn := Enable;
|
||||||
FSlices[idx].FMSQLevel := Level;
|
FSlices[idx].FMSQLevel := Level;
|
||||||
if FSlices[idx].Opened then
|
ApplySliceFMSQ(idx);
|
||||||
ApplyFMSQToChan(FSlices[idx].Chan, Enable, Level);
|
|
||||||
finally
|
finally
|
||||||
FSliceLock.Leave;
|
FSliceLock.Leave;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Squelch слайса с гейтом по режиму — как у главного приёмника
|
||||||
|
// (ApplyModeFilter: включён только в MODE_FM). Блок fmsq WDSP стоит в тракте
|
||||||
|
// и глушит звук по шумовому выходу FM-дискриминатора: оставшись включённым
|
||||||
|
// после ухода из FM, он затыкает слайс намертво, а органов управления
|
||||||
|
// шумодавом в не-FM режимах нет. Пользовательский выбор при этом сохраняется
|
||||||
|
// в FMSQOn и возвращается вместе с режимом FM.
|
||||||
|
procedure TWDSPEngine.ApplySliceFMSQ(Idx: Integer);
|
||||||
|
begin
|
||||||
|
if (Idx < 0) or (Idx > High(FSlices)) or not FSlices[Idx].Opened then Exit;
|
||||||
|
ApplyFMSQToChan(FSlices[Idx].Chan,
|
||||||
|
FSlices[Idx].FMSQOn and (FSlices[Idx].Mode = MODE_FM),
|
||||||
|
FSlices[Idx].FMSQLevel);
|
||||||
|
end;
|
||||||
|
|
||||||
function TWDSPEngine.GetSliceSMeter(Id: Integer): Double;
|
function TWDSPEngine.GetSliceSMeter(Id: Integer): Double;
|
||||||
var idx: Integer;
|
var idx: Integer;
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
<UseVersionInfo Value="True"/>
|
<UseVersionInfo Value="True"/>
|
||||||
<AutoIncrementBuild Value="True"/>
|
<AutoIncrementBuild Value="True"/>
|
||||||
<MinorVersionNr Value="9"/>
|
<MinorVersionNr Value="9"/>
|
||||||
<BuildNr Value="278"/>
|
<BuildNr Value="285"/>
|
||||||
</VersionInfo>
|
</VersionInfo>
|
||||||
<MacroValues Count="110">
|
<MacroValues Count="117">
|
||||||
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
<Macro1 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
<Macro2 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
<Macro3 Name="LCLWidgetType" Value="qt6"/>
|
||||||
@@ -130,6 +130,13 @@
|
|||||||
<Macro108 Name="LCLWidgetType" Value="qt6"/>
|
<Macro108 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro109 Name="LCLWidgetType" Value="qt6"/>
|
<Macro109 Name="LCLWidgetType" Value="qt6"/>
|
||||||
<Macro110 Name="LCLWidgetType" Value="qt6"/>
|
<Macro110 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro111 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro112 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro113 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro114 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro115 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro116 Name="LCLWidgetType" Value="qt6"/>
|
||||||
|
<Macro117 Name="LCLWidgetType" Value="qt6"/>
|
||||||
</MacroValues>
|
</MacroValues>
|
||||||
<BuildModes>
|
<BuildModes>
|
||||||
<Item Name="Debug" Default="True"/>
|
<Item Name="Debug" Default="True"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user