Commit Graph
19 Commits
Author SHA1 Message Date
ew8bakandClaude Opus 4.8 c986232891 ui(vfo): колесо мыши прокручивает список устройств в AUD
VfoOverlay запоминает прямоугольник списка (FAudListRect) и обрабатывает
колесо над ним (HandleMouseWheel): шаг = одна строка. Если курсор в этой
зоне, событие считается обработанным и не уходит в спектр — частота не
съезжает даже когда список целиком помещается и крутить нечего.

PanafallPanel.DispatchFlagsMouseWheel перебирает главный флаг и флаги
слайсов (как остальные Dispatch*), MainForm.FormMouseWheel зовёт его по
всем панам первым делом после дисплеев VFO; координаты берутся через
PbSpectrum.ScreenToClient(Mouse.CursorPos), поэтому работает и в pop-out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:29:32 +03:00
ew8bakandClaude Opus 4.8 4aa180e7b2 wip(audio): выбор устройства ВВОДА на каждом слайсе + вкладки OUT/IN в AUD
Паритет с уже существующим выбором вывода: на каждом слайсе своё устройство
входа (микрофон/виртуальный кабель).

- RadioController: TCtrlSlice += InDeviceIndex/InDevName/AudioIn (ссылка, не
  владение); mic-пул FMicPool с refcount (Acquire/ReleaseMicInput) — один
  открытый TAudioInput на уникальное PA-устройство, смена TX-слайса не
  переоткрывает поток; ActiveMicInput/ActiveMicInDevName для PullSoundCardMic,
  Flush и DefaultMicSource; SetMainMicDevice перепривязывает ссылки слайсов.
- VfoOverlay: во fly-out AUD ряд вкладок OUT | IN, событие OnAudioInDevice.
- PanafallPanel: проброс списка входных устройств во флаги слайсов и главный.
- Settings: персист in_dev_name.

НЕ ГОТОВО: зависание GUI при выборе на слайсе того же входа, что в настройках
(пул открывает поток вместо шортката на общий FAudioIn). В коде оставлена
временная диагностика [MIC] в stderr. Также подозрение на замедление потока
данных от радио — проверяем сравнением с main.

Со мной в коммите временные тестовые программы PortAudio (other/pa*.lpr).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:52:24 +03:00
ew8bakandClaude Opus 4.8 28ae832b71 feat(slices): per-pan tuning wheel and per-slice RX mute on TX
Mouse wheel over an extra panadapter now retunes that pan's primary
slice (first created on that receiver) instead of the main VFO; a slice
flag under the cursor still wins, pan 0 keeps driving the VFO.

Slice flags get a clickable RXM badge: RX audio of the slice is muted
while transmitting (default), so the operator no longer hears himself on
every slice in full duplex. State persists with the workspace.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:35:19 +03:00
ew8bak fa5a95ca5d fix(dmr): avoid stale and mislabeled talkgroups 2026-07-14 21:30:41 +03:00
ew8bak 7c4b024186 feat(dmr): show stable status on receiver slices 2026-07-14 21:23:24 +03:00
ew8bakandClaude Opus 4.8 2474821739 feat(slices): SPLIT только у главного флага
У слайса нет своего VFO B — кросс-частотный TX делается TX-бейджем слайса.
Бейдж SPLIT (и его хит-зона) рисуется лишь при IsMain; «×» флага слайса
переехал вплотную к TX. SPLIT главного гаснет, пока TX-источник — слайс
(ActiveTXFreqHz берёт частоту слайса, а не VFO B).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:32:54 +03:00
ew8bakandClaude Opus 4.8 8d65f4d6e8 feat(slices): мультислайс-TX — выбор TX-слайса, кросс-банд (Flex-паритет)
- RadioController: FTxSliceId (0=главный VFO, >0=слайс), SetTxSlice
  эксклюзивно; ActiveTXFreqHz/ActiveTXMode с TX-слайса, режим применяется
  в SetMOX(True) перед SetTXRun; TxBandIdx для PA-кал и safety DoNotTx
  при кросс-банде; RemoveSlice сбрасывает TX-слайс.
- HPSDRNetwork: TX-антенна выбиралась по RX-бэнду → по TX-частоте
  (TxAnt[FreqToBandIndex(TXFreqHz)]).
- MainForm/PanafallPanel: клик TX на флаге слайса → SetTxSlice, TX-бейджи
  (янтарь=выбран, красный=передаёт), RefreshTxIndicators по rfTransmitting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 18:15:52 +03:00
ew8bakandClaude Opus 4.8 9bb86b59b8 feat(slices): кастомные тематизированные popup-меню панов + фиксы позиционирования
Селекторы диапазона/samplerate панов N переведены с нативного TPopupMenu на
своё меню в стиле приложения (одинаково на всех платформах, в цветовой теме).

- FlatPopupMenu.pas (new): TFlatPopupMenu — owner-draw меню как ДОЧЕРНИЙ контрол
  формы (не top-level окно: Wayland центрирует свои top-level окна). Hover,
  галка текущего, клавиатура (↑↓/Enter/Esc), закрытие по клику-вне (MouseCapture)
  и потере фокуса. Позиционируется под лейблом-якорем в клиентских координатах.
- PanDisplayPopup: поповер «◑» тоже переведён с top-level формы на дочерний
  контрол (центрировался на Wayland) — открывается под кнопкой, закрытие «×»
  или повторным «◑».
- MainForm: band/rate-селекторы на FlatPopupMenu; свёртка повторяющегося
  выбора темы (9 инлайнов) в CurrentAppTheme.
- PanafallPanel: курсор-«палец» кликабельных лейблов шапки переприменяется в
  конце Build (флаги *Clickable могли выставляться до создания лейблов —
  samplerate-лейбл не получал crHandPoint).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 15:02:08 +03:00
ew8bakandClaude Opus 4.8 3ee996154a feat(slices): выбор КВ-диапазона на панах N (Flex-style band-селектор)
Кликабельный бейдж диапазона («20m») в шапке пана N → popup-меню КВ-бандов.
На выбор — по-флексовому: ретюн DDC на VfoA диапазона (из общего band-кэша,
как пан 0), активный приёмник садится на VfoA с mode/filter/AGC + zoom/pan
этого диапазона, прочие слайсы пана убираются (вне новой полосы). Только на
настоящих КВ (не XVTR, не Pluto).

- TPanafallPanel: FHeaderBandLabel + OnBandClick/BandClickable/SetHeaderBand;
  каскад left-лейблов шапки вынесен в LayoutHeaderLabels (band/rate/adc без
  дыр при скрытии).
- MainForm: OnPanBandClick/PanBandMenuItemClick/ApplyPanBand +
  PanBandSelectorVisible (гейт КВ); band-лейбл в UpdatePanHeaders (по
  FreqToBandIdx частоты DDC), тема в ApplyPanHeaderTheme.

Ограничение: per-slice AGC-Top в движке нет — подтягиваются
mode/filter/AGC-mode/zoom/pan, но не индивидуальный AGC-Top диапазона.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 14:27:17 +03:00
ew8bakandClaude Opus 4.8 3566f10191 feat(slices): per-pan дисплей — палитра/gamma/уровни на пан («◑»-поповер)
Кнопка «◑» в шапке каждого пана открывает компактный поповер настроек
отображения (палитра, gamma, ref/range спектра, авто-уровень водопада +
offset/ручные min-max). Модель «глобальный дефолт + override на пан»: пан 0
правит глобальные поля рендера (зеркалятся в контроллер), паны N ставят
DisplayOverride и персистятся в воркспейс раздельно КВ/трансвертер.

- PanDisplayPopup.pas (new): borderless fsStayOnTop форма, гаснет по
  OnDeactivate; Flat*-контролы; крестик «×» закрытия; дим-хинт «правки
  применяются и сохраняются сами»; кнопки «⟳ Reset»/«⇄ Copy to all».
- TPanafallPanel: FBtnDisplay + OnDisplayClick + DisplayOverride;
  PositionHeaderChildren каскадит [×][⧉][◑] справа по Visible.
- MainForm: OnPanDisplayClick/Applied/Reset/ApplyAll + ApplyGlobalRenderToView
  + MarkPanDisplayDirty. При смене палитры/сбросе чистим историю GL-водопада
  (TSpectrumView.ClearWaterfall) — GL хранит уже раскрашенные пиксели.
- Settings/TPanCfg: под-объект 'display' (палитра/gamma/ref/range/wf-уровни),
  пишется только при override.

Глобальными осознанно оставлены разрешение анализатора, MSAA, скорость
водопада, детектор/усреднение (движок/перф, не косметика).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 13:49:19 +03:00
ew8bakandClaude Opus 4.8 543453007e feat(slices): персист панов+слайсов, раздельно КВ/трансвертеры
Сохранение и восстановление панадаптеров, слайсов и раскладки per-device,
раздельно по контексту: КВ ('hf') и каждый трансвертер ('xvtr_N') — паны
одного контекста не имеют смысла в другом.

Settings: секция "pans"/<ctx> под MAC (grid-режим/доли, на пан —
freq/rate/adc/zoom/pan/доли стека+колонки+сплиттер спектр/водопад, на слайс —
freq/mode/фильтр/agc/vol/mute/squelch/аудиоустройство). TSliceCfg/TPanCfg/
TPansConfig + Default/Save/LoadPans(Ctx).

MainForm: CreatePanCore (вынос ядра из OnAddPanClick), SavePanWorkspaceCtx/
RestorePanWorkspaceCtx/TearDownWorkspace, PanContextKey. Хук контроллера
OnBeforeStop (снимок до гашения DDC в StopRunning). Переходы ActivateXvtrBand/
DeactivateXvtr обёрнуты save-старого/teardown/restore-нового (гейт FRunning);
restore XVTR-панов после ActivateXvtr (FCurrentXvtr целевой ⇒ XvtrTranslate
верный). PanafallPanel.DestroyAllSliceFlags. Смена КВ-банда контекст не меняет.

Round-trip сериализации и разделения контекстов проверены автономно; на
экране не проверено.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 23:06:12 +03:00
ew8bakandClaude Fable 5 eac66100a8 feat(slices): грид-раскладка панов + фиксы минимумов стека, утечки кнопок, CPU
Грид: пан 0 сверху во всю ширину, доп. паны колонками снизу; тумблер
«▦/▤» в ряду зума пана 0, вертикальные сплиттеры-призраки колонок
(FPanColShare), доля ряда FPanGridRowShare; автоткат в стек при <2 доп.
панах. Регион пана обобщён до прямоугольника (StackLeft/StackWidth).

Фиксы по экранному тесту:
- наезд панов: раздача высот и драг сплиттеров клампятся минимумом
  содержимого пана (MinLayoutHeight/PanMinHeight, пан 0 += wideband);
- «блуждающие» кнопки после STOP: MakeFlatBtn даёт Owner=контейнер,
  TPanafallPanel.Destroy теперь явно освобождает −/⌂/+/⊞/▦;
- жор CPU ~40%/пан: убран безусловный Invalidate зум-бара из тика
  (SyncPanZoomUI), инвалидация только при реальной смене значений;
- пропорция спектр/водопад пана 0 не восстанавливалась после закрытия
  панов: кламп ratio минимумами больше не пишется в FSplitterRatio.

Подтверждено юзером на экране: грид/стек/STOP/pop-out работают,
CPU со всеми панами 17-20%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 15:51:11 +03:00
ew8bakandClaude Fable 5 64edf9e289 feat(slices): пан-зум панов N — свой бар/кнопки, span-clip анализатора пана
Движок: TPanChan.ZoomFactor/PanSlider, span-clip в ApplyPanAnalyzerSettings
(математика главного, ZOOM_LIMIT 100), SetPanZoomPan с no-op guard (SetAnalyzer
сбрасывает FFT-историю). Зум переживает смену rate/ADC пана.
Контроллер: формула окна вынесена в ViewWindowFor (главный GetViewWindow тоже
через неё), GetPanViewWindow (PanId=0 делегирует), PanZoomIn/Out по лестнице
кратностей с якорем на центре окна, PanZoomDefault, геттеры.
UI: TPanZoomEvent получил Sender; у панов N включён ряд зума, бар
диспетчеризуется по объекту, кнопки −/⌂/+ общие через PanOfZoomButton (матч по
идентичности — MakeFlatBtn создаёт кнопки с Owner=контейнер, PanFromSender их
не видит); SyncPanZoomUI/RefreshPanZoom, вся мышь панов зум-корректна через
GetPanViewWindow. Темизация баров панов N.
Смоук panzoomtest ALL PASS (пик тона совпадает с формулой окна ±0.6%),
подтверждено на экране.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:35:13 +03:00
ew8bakandClaude Fable 5 209e490dfa fix(slices): pop-out при wideband + читаемость шапки; бейдж АЦП → RX1/RX2
1) LayoutPanStack прятал шапку пана 0 по числу застекованных панов, а wideband
ставится со сдвигом Pan0HeaderH по общему числу (вкл. плавающие) — спектр
накрывал линейку частот wideband. Теперь видимость шапки по PanCount.
2) Лейблы шапки наследовали шрифт формы (ParentFont) — в pop-out окне текст
был дефолтно-тёмным на тёмном. Темизация шапки вынесена в ApplyPanHeaderTheme
(зовётся из UpdatePanHeaders: создание пана/pop-out/dock), окну — шрифт формы.
3) Бейдж ADC-источника переименован A1/A2 → RX1/RX2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:05:10 +03:00
ew8bakandClaude Fable 5 8bf8bcfc76 feat(slices): этап 3.4 ADC-селектор панов + этап 3.5 pop-out в отдельное окно
3.4 ADC-селектор:
- Caps.NumADCs (HPSDR: 2 для ORION/ORION2/SATURN, как Pkt.NumADCs; Pluto: 1)
- controller.PanADC/SetPanADC: пан 0 = FMainADCSrc + ConfigureDDCs (ADC
  прокинут и в штатные вызовы — смена rate не сбрасывает выбор), паны N =
  FPanADC[] + SetPanDDC (RebuildDDCSpecific)
- Бейдж «A1/A2» в шапке каждого пана (виден при NumADCs>1), клик = тумблер;
  пан 0 на ADC2 закрывает сценарий rx2-support

3.5 Pop-out:
- «⧉» в шапке панов N → PopOutPan: TForm.CreateNew + ReparentTo (перенос
  всех контролов панели), [×] окна = DockBackPan (возврат в стек), «×»
  шапки = закрыть пан; LayoutPanStack скипает плавающих; колесо окна =
  FormMouseWheel
- GL: reparent пересоздаёт контексты → ResetGLCache обеих канв без glDelete
  (по прецеденту MSAA); TWaterfallViewOpenGL.ResetGLCache новый, история
  водопада перезаливается из CPU-буфера

Проверено юзером на экране (беглый тест: селектор и pop-out работают).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 23:54:09 +03:00
ew8bakandClaude Fable 5 e5921b8196 feat(slices): независимый rate панадаптеров (селектор в шапке)
- Создание пана: rate наследуется от главного с клампом ≤768к
  (вне сетки → 384к); за сменой rate главного паны не следуют
- Клик по «NNN kHz» в шапке пана N → меню полной сетки железа
  (PanRateAllowed = Caps.RatePresets ∩ кратные 48 кГц; захардкоженный
  PAN_DDC_RATES удалён)
- WDSPEngine.SetPanRate: под FSliceLock пересбор аккумулятора/анализатора
  пана + переоткрытие слайс-каналов на новом rate (state сохраняется)
- RadioController.SetPanDDCRate: движок → реконфиг DDC (SetPanDDC) →
  кламп слайсов к новой полосе; FPanADC[] хранится (база под 3.4)
- Шапка: rate отдельным лейблом (у панов N кликабелен, акцент/рука)

Смоук-тест без железа ALL PASS (тон: спектр+аудио слайса живы через
384→192→768). Проверено юзером на экране.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 23:28:25 +03:00
ew8bakandClaude Fable 5 95b4f749be 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>
2026-07-11 22:56:49 +03:00
ew8bakandClaude Fable 5 cc9919c35a refactor(slices): этап 3.0B1 — флаги слайсов переехали в TPanafallPanel
Панель владеет коллекцией флагов B+ (создание/закрытие/заливка состояния из
контроллера), раскладкой LayoutFlags, диспетчером мыши флагов, тиком S-метров
(TickFlags) и видимостью флага A (UpdateMainFlagVisibility). Главный флаг A
создаёт MainForm (проводка семантических событий у него) и отдаёт через
AttachMainFlag; новые флаги проводятся через OnWireFlag. Роутинг по слайсу —
FPan.CurSliceId; закрытие «×» — RequestSliceClose/OnSliceClosed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:51:47 +03:00
ew8bakandClaude Fable 5 c125e5978e refactor(slices): этап 3.0A — панадаптер выделен в TPanafallPanel
PanafallPanel.pas: view (CPU/GL), контролы стека (спектр/линейка/сплиттер/
водопад/пан-зум/кнопки зума), геометрия Layout, drag сплиттера и мышь
пан/зум-полосы. MainForm работает через алиасы (FSpecView/PbSpectrum/… =
FPan.*), размеры областей — FPan.SpectrumWidth/SpectrumHeight/WaterfallHeight.
Семантика мыши/флаги/тик пока в MainForm (фаза B). GL-аудит per-instance
пройден (глобальных GL-ресурсов нет). План: doc/SLICES_PLAN.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 22:41:32 +03:00