Files
reasampler/src/shell/panel/CLAUDE.md
T
daniel faa513cafb Fix SWELL drag guard, channel-fork the VST editor window class, dedupe own-module match
Panel drag no longer misfires on SWELL's always-zero wParam; stable/beta VST editors register distinct window classes against their own module instead of colliding on REAPER's; own-module basename matching moves to a tested pure helper.
2026-09-25 14:11:22 -04:00

8.2 KiB

src/shell/panel — the docked bank-panel shell + the shared LICE draw kit

Scope

The REAPER-facing shell for the docked bank panel: the nine bank_panel split TUs (panel_window / panel_layout / panel_render / panel_input / panel_drag / panel_drag_os / panel_thumbnails / panel_audition / panel_bank_ops, sharing state via panel_state.h), plus draw_kit, the shared LICE draw shell also consumed by the VST3 editor (shell/instrument/).

Pure layout/hit-test/palette modules the panel draws through (theme, component_geometry, bank_grid, tab_strip, mode_switch, action_bar, footer_bar, overflow_menu, prune_button, mode_enable, insert_fx_enable, tooltip, card_drag, card_meta) live in core/ui / core/model and are documented there — this directory consumes them but does not own them. The promptless bank-mutation verbs (bankOpCreate/Rename/Delete/… + persistBankOp) that panel_bank_ops skins live in shell/bank_ops, a sibling directory, not here.

Invariants

  • Draw through the kit, by palette ROLE, not hardcoded hue. The shared LICE-based drawing kit is the one source of drawing for the whole system — a button, row, slider, or waveform looks identical in the bank panel, the embed strip, and the VST editor because it is the same kit function, drawn against palette roles (bg/base, bg/panel, bg/cell, accent/primary, accent/secondary, accent/tertiary, accent/hot, text/primary, text/dim, line/hairline, warn) rather than a literal color. The kit palette stays abstract (role→color, one constants block), so a whole visual direction is a single-file change (Phase L, DS-1/DS-2).
  • Dock-panel layout is a thorough redesign, not a light re-skin (DS-3). The panel lays out the full button/affordance inventory intuitively and uncluttered, then applies the kit — but this does not restructure the panel bones: the vertical-split / grid / tab structure is sound and stays as-is; a redesign designs the layout of the button inventory around it, not through it.
  • What Phase L does not change (Precision / invariant implications):
    • The pure/shell split holds — all layout/hit-test stays in pure CTest-covered geometry modules; the kit's draw half is shell, its geometry half is pure, even where a WDL piece is reused. No hit-test math moves into untestable code.
    • RT discipline is untouched — the kit is draw-thread only; nothing here touches process or any off-thread reload handoff (a VST3-instrument concern).
    • Read-only-over-bank is untouched — this is look-and-feel; no data-ownership change.
    • The capture/placement load-bearing principle is untouched — Phase L draws; it does not capture, place, or mutate the bank.
    • VST3 class UID / component-state contract is unchanged.
    • Windows-only (D5) — font/GDI/HFONT choices assume Windows; no cross-platform font-fallback concern.

Modules

  • bank_panel (shell/panel/: panel_window / panel_layout / panel_render / panel_input / panel_drag / panel_drag_os / panel_thumbnails / panel_audition / panel_bank_ops, sharing state via panel_state.h — Q-W2 split of the former god-module into nine TUs) — docked LICE-drawn grid with three-zone layout: top toolbar (Capture → Placement, frequent acts only, via action_bar, short labels; Maintenance and the rarer Placement/Capture variants sit in the More (⋯) overflow menu via overflow_menu), bottom toolbar (four opposite-mode tag buttons + Show Both), and footer ([Arrange|Design] toggle, Tail button, Prune via footer_bar). Grid renders in sparse slot order with gap cells, drop dispatch, metadata overlay, and selection via accent/tertiary purple border. Draws through the L1 kit by palette role; OS drag-out via drag_out + drag_out_win. panel_window owns the SWELL dialog lifecycle + dialog proc + drop-target opt-in; panel_layout the toolbar/footer/menu rects + vertical-split geometry (the one geometry source both paint and hit-test read); panel_render the WM_PAINT draw; panel_input click/wheel/keyboard routing + the new-content auto-tag timer; panel_drag the hover + card-drag state machine + drop dispatch; panel_drag_os the OS hand-off/resume seam split out of panel_drag; panel_thumbnails the PCM→envelope thumbnail cache + the bank-change fingerprint pass; panel_audition the preview-playback engine; panel_bank_ops the menu/prompt UX skin over the promptless shell/bank_ops verbs. draw_kit (shared with the VST3 editor) stays a separate TU.
    • panel_window — SWELL dialog lifecycle + dialog proc + drop-target opt-in. The drop splits by extension: a .rsbank is a whole bank and routes to the package-import action (one NEW bank each), everything else keeps the audio-ingest route.
    • panel_layout — toolbar/footer/menu rects + vertical-split geometry (the one geometry source both paint and hit-test read).
    • panel_render — the WM_PAINT draw.
    • panel_input — click/wheel/keyboard routing + the new-content auto-tag timer.
    • panel_drag — the hover + card-drag state machine + drop dispatch.
    • panel_drag_os — the OS hand-off/resume seam: the live re-ask the OS drag loop uses, the hand-off itself, and resuming the internal drag when the OS loop gives the gesture back.
    • panel_thumbnails — the PCM→envelope thumbnail cache + the bank-change fingerprint pass.
    • panel_audition — the preview-playback engine.
    • panel_bank_ops — the menu/prompt UX skin over the promptless shell/bank_ops verbs.
  • draw_kit — shared LICE draw shell: fillSurface, drawButton/drawSlider/drawListRow/drawWaveform, cached-font text(), full interaction-state model, double-buffer preserved. Consumes theme + component_geometry. Its antialiasing contract — which surfaces alias, which cannot, and the LICE primitive each answers with — is the disposition table in docs/product/visual-design-language.md §8, which governs drawWaveform as much as this doc does. drawWaveform's per-column vertical arithmetic is NOT here: it is the pure, unit-tested component_geometry::waveformBand/waveformColumnSpan pair, because this TU is DAW-verified and not unit-tested.

Gotchas

  • No external UI framework. iPlug2 / JUCE / VSTGUI are rejected (DS-1). LICE + reused WDL pieces are the toolkit; reject any path that pulls in a new framework.
  • The FX-drain indicator asks fxReclaimActivity() and decides nothing itself. panel_input polls it once per tick into g_panel.fxDrain; the footer readout and the WM_SETCURSOR busy cursor both read that cached state, so the two never disagree about the drain's own direction. The cursor additionally suppresses on dragArmed/dragging (a live card drag outranks it), so mid-drag the footer can still read "parking FX"/"restoring FX" while the cursor shows the drag cue — that is the one case where paint and cursor diverge, and it is deliberate. The transport gate, the park debounce and the open-undo-block stand-off are all already folded into that answer, against the reclaim queue's own pinned project — do not re-evaluate any of them here, and never drive this off fxReclaimPending (true throughout the debounce, when only the opposite direction is eligible). The indicator reaches only our own window: over REAPER's arrange or mixer the cursor is REAPER's, and the SDK exposes nothing host-wide. A global SetSystemCursor or a message hook would reach further and is rejected — do not reintroduce either. IDC_APPSTARTING is Windows-only (SWELL ships no equivalent), so on mac/Linux the readout is the whole indicator. [verify — DAW] whether REAPER's docker even routes WM_SETCURSOR to the docked child dialog at all — the whole Windows half of this rests on that.
  • No hit-test geometry in untestable shell code. Even when reusing a WDL piece (e.g. a vwnd control for a long scroll list), layout/hit-test math stays in pure CTest-covered modules — do not import a WDL control's retained-mode object model wholesale, since its controls own their hit-test internally and that would move geometry into untestable shell code.
  • Verify every LICE/WDL/SWELL API name/signature against vendor/WDL before use.