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>
Клик по «NNN kHz · DDCn» в шапке пана — кроме сетки rate теперь есть пункты
«→ DDC N»: пан переезжает на другой аппаратный DDC (MovePanDDC), при этом
движок, анализатор и слайсы не пересоздаются — перепрошивается только
hw-индекс. Пригодилось при отладке: конкретный DDC платы может вести себя
хуже соседей, и пан можно просто увести на другой.
Диапазон ограничен реальными DDC железа: MaxDDCIndex = 7 (DDC8+ openHPSDR
enable-бит принимает, но поток не отдаёт). Ограничение действует и в меню,
и в DDCFree, и в самом MovePanDDC.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ApplyAntPorts брал оба разъёма по центру приёма, поэтому при мультислайс-TX
(или split на другой диапазон) передача могла уйти в разъём RX-диапазона.
Теперь RX-разъём — по FCenterFreq, TX — по ActiveTXFreqHz (TX-слайс/TX-VFO);
TX вне VU-плана падает обратно на диапазон приёма. Пересчёт добавлен в
SetTxSlice, SetSplit и в SetMOX(True) как страховка перед выходом в эфир.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- шапка колонок: «RX»/«TX» по центру своей пары, номера разъёмов отдельной
строкой ниже (не налезают на рамку группы);
- строки трансвертеров пакуются подряд (раньше выключенные слоты занимали
место → дыра между ADS-B и QO-100), высота группы — по последней видимой;
- RX- и TX-пары разнесены, шире колонка названий, крупнее шаг строки;
- дим-заголовок «Transverters» над секцией слотов.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Второй разъём у AD936x-плат — это второй КАНАЛ чипа (не порт B первого), и в
1R1T-образе он выбирается мультиплексором AD9361: debug-параметры
adi,1rx-1tx-mode-use-rx-num/-tx-num + биты RX1/RX2, TX1/TX2 регистров 0x3/0x2
(как switch_rfinput.sh/switch_rfoutput.sh прошивки). rf_port_select тут ни при
чём — прошивка его к тому же блокирует.
- IIOBindings: debug-атрибуты + прямой доступ к регистрам.
- PlutoBackend: детект второго разъёма (2R2T-каналы либо мультиплексор + модель
платы), SetAntPorts(RxPort,TxPort), ApplyRxMux/ApplyTxMux; Caps.HasAntSwitch.
⚠ApplyGain(Force): драйвер пропускает запись gain_control_mode, если считает
режим неизменным, — а у нового канала AGC-регистры не запрограммированы (в
железе крутится auto-AGC, hardwaregain отвергается EOPNOTSUPP). Форсируем
перепрог через другой режим после смены разъёма и после ad9361_set_bb_rate.
- RadioBackend: TBackendCaps.HasAntSwitch + virtual SetAntPorts (HPSDR — no-op,
там антеннами рулит Alex).
- Settings: секция ant936x (разъём RX/TX на диапазон и на слот трансвертера);
hw-AGC (режим + manual gain) переехал в TBandSettings/TXvtrEntry — теперь он
свой на каждом диапазоне и трансвертере.
- RadioController: FAnt936x + ApplyAntPorts (RestoreBand/ActivateXvtr/
StartRunning); ApplyBandDSP восстанавливает hw-AGC диапазона.
- SettingsForm: вкладка Antenna — Alex-таблица (openHPSDR) либо таблица
разъёмов AD936x по диапазонам/трансвертерам.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- MainForm: TXOverlay главной вьюхи взводился по FTransmitting без учёта
источника TX → красной становилась полоса главного VFO даже при передаче
со слайса. Теперь TXOverlay = FTransmitting and (FTxSliceId = 0).
- VfoOverlay: публичный TxActive (FTx) — вьюхи знают, какой слайс передаёт.
- SpectrumView/SpectrumViewOpengl: полоса/края/несущая передающего слайса
красные (alpha 100, как у главного при TX), иначе цвет бейджа слайса.
- Фикс цвета TX-полосы в GL: $00E03030 при ColorToRGB (младший байт = R)
давал синий вместо красного; общая константа CLR_TX_BAND = $003030E0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
У слайса нет своего VFO B — кросс-частотный TX делается TX-бейджем слайса.
Бейдж SPLIT (и его хит-зона) рисуется лишь при IsMain; «×» флага слайса
переехал вплотную к TX. SPLIT главного гаснет, пока TX-источник — слайс
(ActiveTXFreqHz берёт частоту слайса, а не VFO B).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 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>
Селекторы диапазона/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>
Кликабельный бейдж диапазона («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>
Сохранение и восстановление панадаптеров, слайсов и раскладки 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>
Частота пана хранится ВИДИМОЙ (как FVfoA/FCenterFreq) и транслируется в
IF через XvtrTranslate только на границе с железом (AddPanDDC,
SetPanDDCFreq, SetPanDDCRate, SetPanADC) — раньше DDC пана получал
видимую частоту сырьём, а drag водопада пана N клампился пределами АЦП
(~61 МГц) вместо диапазона трансвертера.
Новое: controller.VisibleFreqBounds (диапазон активного XVTR | пределы
железа) для UI-клампа драга; RefreshPanDDCs — на входе/выходе XVTR и
правке LO/LOError клампит видимые центры живых панов, перешивает
freq-слова DDC и прижимает выпавшие слайсы к краям полосы захвата.
Подтверждено юзером на трансвертере.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Грид: пан 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>
Движок: 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>
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>
ChangeSampleRate больше не делает полный Close/Open движка (стоп DSP-потока,
разрушение всех анализаторов, сброс общей IQ-очереди): гейт FMainGated+FMainLock
дропает только main-пакеты, пересоздаются только RXA_CHAN и слайсы пана 0,
анализаторы панов живут. Контроллер не сбрасывает FWDSPReady на время смены
(OnDDCIQ продолжает кормить паны). Общий код RXA — Open/CloseMainRXChannel.
Бонус: SetChannelState dmode=1 на idle-каналах зря ждал флаш ~130мс → dmode=0
в CloseSliceChannel/CloseMainRXChannel (каналы всегда idle по локам).
Итог: смена 331→120мс, пауза аудио пан-слайса 137→40мс. Смоук ratetest ALL PASS,
подтверждено на экране.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>