mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
feat(slices): этап 3.3 — UI стек панадаптеров
Несколько панадаптеров в главном окне (кнопка «⊞», до MAX_PANS): - TPanafallPanel: регион в стеке (StackTop/Height), шапка с «×», pan-aware ViewWindow, FirstSliceId; явный crArrow GL-канвам (WA_NativeWindow-поверхность на Wayland навсегда наследует курсор момента создания — прилипала «рука» кнопки «⊞») - MainForm: FPans[]/LayoutPanStack (доли + межпанные сплиттеры с живым призраком), создание/закрытие панов (DDC+слайс+вьюха), пиксели панов из display-потока под FPanCbLock, рендер по dirty в тике - Мышь панов N: Ctrl+ЛКМ = слайс, drag маркера = ретюн слайса, drag фона = live-ретюн DDC (гистерезис 4px), клик = тюн слайса пана (PanClickTune, снап 100 Гц), флаг-диспетчер только на спектре - Сплиттер спектр/водопад: drag-математика от региона пана (FSplitTopOff/FSplitAvailH из Layout), OnSplitterMoved у панов N - Паны живут в Run-сессии, умирают на STOP Проверено юзером на экране (3 раунда фидбека) + e2e против hpsdrsim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+99
-8
@@ -89,7 +89,8 @@ SmartSDR НЕ умеет — наш pop-out будет улучшением по
|
||||
один слайс в его центре (поведение Flex).
|
||||
3. ADC-источник — свойство **панадаптера**, не слайса (бейдж `A1`/`A2` в шапке).
|
||||
В отличие от Flex показываем именно АЦП, а не антенну: на HPSDR-платах
|
||||
маппинг «вход→АЦП» жёсткий, антенная абстракция не нужна.
|
||||
маппинг «вход→АЦП» жёсткий. Антенны ADC0 (Alex ANT1/2/3) — отдельная
|
||||
ГЛОБАЛЬНАЯ ручка, общая для всех панов этого АЦП (детали в 3.4).
|
||||
4. Буквы слайсов — глобальный пул A..G через все паны (как во Flex A-H):
|
||||
буква = личность слайса, пан = место жительства.
|
||||
5. Возможности бэкенда описывает запись capabilities (см. таблицу) — UI по ней
|
||||
@@ -342,14 +343,99 @@ ChangeSampleRate).
|
||||
независим от DDC, TX-частота = частота слайса. (Полный мультислайс-TX —
|
||||
отдельная старая задача, тут ничего нового не ломаем.)
|
||||
|
||||
### 3.4 — ADC-селектор панадаптера
|
||||
**СТАТУС 3.3 (2026-07-11): БАЗОВЫЙ UI РЕАЛИЗОВАН, собирается (GUI+демон),
|
||||
бэкенд-тракт проверен END-TO-END против эмулятора hpsdrsim -hermes -P2
|
||||
(scratchpad pantest2: DDC1 включается, IQ течёт, спектр/водопад пана рисуются,
|
||||
слайс живой S-метр −95дБм, ретюн/снятие чистые, seq-ошибок нет). НА ЭКРАНЕ
|
||||
НЕ ПРОВЕРЕНО.** Что сделано:
|
||||
|
||||
- `TPanafallPanel`: `PanId`, регион в стеке (`StackTop/StackHeight`, Layout
|
||||
считает внутри региона), шапка (TPanel+TLabel+«×»→OnPanClose; видна при
|
||||
панах ≥2), кнопка «⊞» в ряду пан/зума (`AddPanEnabled`, только пан 0),
|
||||
`ShowZoomRow=False` у панов N (их зум позже), pan-aware `ViewWindow`
|
||||
(SliceAtPixel/LayoutFlags от окна СВОЕГО пана), `FOnFlagsInvalidate(Self)`.
|
||||
- MainForm: `FPans[0..MAX_PANS-1]` (пан 0 = FPan), `LayoutPanStack` (доли
|
||||
`FPanShare` + межпанные сплиттеры, пересчёт по MouseUp), «⊞» →
|
||||
`OnAddPanClick` (AddPanDDC на частоте активного VFO, rate 384к, автослайс
|
||||
в центре, копия display-параметров view, ApplyDarkTheme), «×» шапки →
|
||||
отложенное `ClosePanadapter` в тике (нельзя free из своей кнопки).
|
||||
- Пиксели: `engine.OnPanSpectrum/OnPanWaterfall` → MainForm напрямую
|
||||
(display-поток, `FPanCbLock` закрывает гонку с созданием/закрытием пана);
|
||||
рендер в SpectrumTimerTick по dirty-флагам, `SyncPanViews` держит
|
||||
центр/span вьюх и текст шапок.
|
||||
- Мышь панов N (НОВЫЕ простые обработчики, VFO/CTUN/маяк/оверлеи главного
|
||||
сюда не переносились — решение по B2 выполнено): Ctrl+ЛКМ = слайс в этом
|
||||
пане, ЛКМ по маркеру = drag слайса (кламп полосой пана), ЛКМ по фону =
|
||||
drag ЦЕНТРА пана (live-ретюн DDC), колесо над флагом любого пана = тюн
|
||||
того слайса; флаги/CurSliceId/инвалидции обобщены на все панели
|
||||
(PanOfOverlay/PushFlagStateAllPans/LayoutFlagsAllPans).
|
||||
- Паны живут только в Run-сессии: на STOP UI убирает их вместе с контроллером.
|
||||
- Отложено: пан-зум панов N, per-pan детектор/усреднение, персист (после 3.3),
|
||||
wideband при маленьком регионе пана 0 может вылезти за регион (редкий кейс),
|
||||
колесо над фоном пана N крутит главный VFO (как везде вне слайсов).
|
||||
|
||||
**ФИКСЫ ПО ПЕРВОМУ ЭКРАННОМУ ТЕСТУ (2026-07-11, фидбек юзера):**
|
||||
|
||||
1. **Сплиттер спектр/водопад был сломан при ≥2 панах**: drag-математика
|
||||
(`SplitterMouseMove/Up`) считала доступную высоту от ВСЕГО родителя
|
||||
(`FParent.ClientHeight`, `TopOff=0`), игнорируя регион пана в стеке,
|
||||
шапку и wideband. Симптомы: у пана 0 ratio занижался (спектр сжимался
|
||||
при тяге вниз), у пана 1 сплиттер прыгал в регион пана 0. Фикс: Layout
|
||||
запоминает `FSplitTopOff/FSplitAvailH` (геометрия «спектр+водопад»
|
||||
СВОЕГО региона), drag использует только их.
|
||||
2. **Межпанный сплиттер** не давал обратной связи до отпускания — теперь
|
||||
живой «призрак» (сам сплиттер едет за мышью, клампится 15%-минимумом
|
||||
обоих панов, подсветка при захвате), доли пересчитываются по MouseUp
|
||||
от финального положения призрака.
|
||||
3. **Клик по фону пана N не перестраивал частоту** (только drag центра).
|
||||
Теперь пресс без движения (<4px) = клик-тюн `PanClickTune`: слайс пана
|
||||
(активный, если он этого пана, иначе первый; нет — создаётся) на частоту
|
||||
клика со снапом 100 Гц и клампом полосой пана. Drag центра включается
|
||||
после гистерезиса 4px, курсор `crSizeWE` — только с этого момента
|
||||
(раньше менялся на голый пресс).
|
||||
4. **Диспетчер флагов/маркеров на панах N** получал координаты ВОДОПАДА
|
||||
(прямоугольники флагов — в системе спектра): клики в верхней части
|
||||
водопада могли молча съедаться невидимым флагом. Теперь флаги/hover —
|
||||
только для событий спектра, курсор на водопаде не трогаем.
|
||||
5. **(2-й раунд фидбека)** У панов N сплиттер спектр/водопад «залипал
|
||||
призраком» (спектр не пересчитывался, при следующем drag прыжок к
|
||||
старому ratio): в `OnAddPanClick` не был подвешен `OnSplitterMoved`
|
||||
(у пана 0 = `RightPanelResize` → полный re-layout). Подвешен тот же
|
||||
обработчик. Пан 0 и межпанные сплиттеры юзер подтвердил рабочими.
|
||||
6. **Курсор-«рука» на всей площади панов N (разгадан, 3-й раунд)**: юзер
|
||||
заметил, что рука = курсор кнопки «⊞». Механизм: GL-канвы — QOpenGLWidget
|
||||
с `WA_NativeWindow` = отдельная Wayland-поверхность; `crDefault` в LCL
|
||||
означает «курсор не задан», и поверхность НАВСЕГДА наследует курсор,
|
||||
бывший под мышью в момент создания виджета. Пан N создаётся кликом по
|
||||
«⊞» (`crHandPoint` у TFlatButton) → рука прилипает; пан 0 создаётся на
|
||||
старте (мышь нигде) → норм. Фикс: `Build` ставит спектру/водопаду ЯВНЫЙ
|
||||
`crArrow` (реальный push), обработчики панов N восстанавливают `crArrow`,
|
||||
не `crDefault`. ⚠Урок на 3.5 (pop-out) и вообще: любой динамически
|
||||
создаваемый нативный GL-виджет должен получать явный курсор при создании.
|
||||
|
||||
Статус: собирается (GUI+демон), НА ЭКРАНЕ НЕ ПРОВЕРЕНО (юзер проверяет).
|
||||
Открыто из фидбека: юзер видел курсор-«палец» на водопаде пана N — в коде
|
||||
панов N `crHandPoint` нигде не ставится (подозрение: артефакт сломанной
|
||||
раскладки, перекрытие чужим контролом); перепроверить после фиксов.
|
||||
|
||||
### 3.4 — ADC-селектор панадаптера (+ антенны Alex, уточнено 2026-07-11)
|
||||
|
||||
Источник сигнала пана — ДВЕ независимые ручки, не одна:
|
||||
|
||||
1. **АЦП (per-pan)**: `TPanafall.ADCSource: 0/1`; в шапке пана селектор/бейдж
|
||||
`A1`/`A2`. Показывается только при `NumADCs=2` (детект платы уже есть —
|
||||
`NumADCs` в ConfigureDDCs-пути). Переключение = `ConfigureDDCs` с новым
|
||||
ADCSource для DDC этого пана. Пан 0 тоже можно перекинуть на ADC1 — это
|
||||
закрывает сценарий старой ветки `feature/rx2-support` как частный случай.
|
||||
2. **Антенна первого АЦП (глобальная, НЕ per-pan)**: у плат с Alex на ADC0
|
||||
уже есть аппаратный селектор RX-антенны **ANT1/ANT2/ANT3** (+ EXT-входы) —
|
||||
реализован per-band в Antenna/Alex-табе (`Alex.RxAnt[band]`, XVTR-override).
|
||||
Селектор один на весь ADC0 ⇒ антенну нельзя сделать свойством пана: смена
|
||||
антенны меняет её для ВСЕХ панов, сидящих на ADC0. В UI пана максимум —
|
||||
бейдж текущей антенны (например `A1·ANT2`) и/или шорткат к глобальному
|
||||
переключателю с явным пониманием, что это общая ручка. ADC1 (RX2-вход) —
|
||||
отдельный разъём без Alex-коммутации.
|
||||
|
||||
- `TPanafall.ADCSource: 0/1`; в шапке пана селектор/бейдж `A1`/`A2`.
|
||||
Показывается только при `NumADCs=2` (детект платы уже есть — `NumADCs`
|
||||
в ConfigureDDCs-пути).
|
||||
- Переключение = `ConfigureDDCs` с новым ADCSource для DDC этого пана.
|
||||
- Пан 0 тоже можно перекинуть на ADC1 — это закрывает сценарий старой ветки
|
||||
`feature/rx2-support` (вторая антенна) бесплатно, как частный случай.
|
||||
- Diversity (sync-DDC, оба АЦП когерентно в один канал) — НЕ здесь; протокол
|
||||
умеет, дизайну панов не мешает, отдельная будущая фича.
|
||||
|
||||
@@ -437,6 +523,11 @@ ChangeSampleRate).
|
||||
осознанно: только явное создание пана (решение «сначала статика» остаётся).
|
||||
- Настройки водопада (палитра/AGC/avg) per-pan или глобально — стартуем с
|
||||
наследования глобальных, разделим по запросу.
|
||||
- **Компоновка панов сеткой** (запрос юзера 2026-07-11): не только вертикальный
|
||||
стек — например, пан 0 сверху во всю ширину, паны B и C ниже бок о бок
|
||||
(пол-ширины каждый), и т.п. Идея на после 3.3/3.5: обобщить `LayoutPanStack`
|
||||
до грид-раскладки (регион пана = прямоугольник, а не полоса; `StackTop/Height`
|
||||
→ `Rect`), сплиттеры по обеим осям. Не блокер текущего этапа.
|
||||
|
||||
## Отвергнутые альтернативы (для истории)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user