Cut shell/panel comment bloat ~47% (comments only, zero code change)
This commit is contained in:
+124
-241
@@ -1,36 +1,22 @@
|
||||
#pragma once
|
||||
// panel_state — INTERNAL shared state + cross-seam contract of the docked bank panel
|
||||
// (Q-W2: bank_panel.cpp split into eight TUs under shell/panel/). Included ONLY by the
|
||||
// panel's own translation units (panel_render / panel_thumbnails / panel_audition /
|
||||
// panel_input / panel_layout / panel_drag / panel_bank_ops / panel_window) — consumers
|
||||
// outside the panel use the per-seam public headers (panel_window.h / panel_input.h /
|
||||
// panel_bank_ops.h / panel_layout.h).
|
||||
// panel_state — INTERNAL shared state + cross-seam contract of the docked bank panel.
|
||||
// Included ONLY by the panel's own TUs; outside consumers use the per-seam public
|
||||
// headers (panel_window.h / panel_input.h / panel_bank_ops.h / panel_layout.h).
|
||||
// Cross-seam calls are plain free functions — direct call-through, no virtual dispatch
|
||||
// (audition and per-mouse-move paths must stay direct calls).
|
||||
//
|
||||
// What lives here:
|
||||
// * PanelState (the one shared state blob, defined in panel_window.cpp) + the small
|
||||
// enums/structs the seams speak (Region / DropKind / Hover / RegionDisplay /
|
||||
// ActionBarRow) and the shared layout constants.
|
||||
// * The cross-seam free-function declarations, grouped by OWNING TU. Everything is a
|
||||
// plain free function — direct call-through, no interface, no virtual dispatch
|
||||
// (T4-28: the audition path and the per-mouse-move path must stay direct calls).
|
||||
// * Explicit using-declarations pulling the pure modules' symbols into
|
||||
// reasampler::panel from their REAL namespace homes (Q-W1 sub-namespaces). The
|
||||
// interim core/namespaces.h shim is GONE (deleted in Q-W6 with the last split);
|
||||
// every symbol below names its true home.
|
||||
//
|
||||
// REFERENCE-INVALIDATION GUARDRAIL (CONTEXT.md §Multi-bank): a bank-structural
|
||||
// mutation (create/delete/evacuate/activate/move) can reallocate the book's vector,
|
||||
// so a BankModel& / Bank* must NEVER be cached across one. Every seam resolves fresh
|
||||
// AFTER any mutation and passes bank IDS (not references) into the model ops.
|
||||
// REFERENCE-INVALIDATION GUARDRAIL: a bank-structural mutation (create/delete/
|
||||
// evacuate/activate/move) can reallocate the book's vector, so a BankModel& / Bank*
|
||||
// must NEVER be cached across one. Every seam resolves fresh after any mutation and
|
||||
// passes bank IDS (not references) into the model ops.
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// SWELL / platform types (HWND, RECT, HMENU). On macOS/Linux SWELL is provided by the
|
||||
// host (SWELL_PROVIDED_BY_APP); on Windows we use native Win32 (windows.h first, then
|
||||
// swell.h no-ops on _WIN32).
|
||||
// On macOS/Linux SWELL is provided by the host (SWELL_PROVIDED_BY_APP); on Windows
|
||||
// we use native Win32 (windows.h first, then swell.h no-ops on _WIN32).
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
@@ -39,37 +25,35 @@
|
||||
#include "wdltypes.h"
|
||||
#include "swell/swell.h"
|
||||
|
||||
// REAPER SDK types only (preview_register_t, MediaTrack, ReaProject). The API function
|
||||
// POINTERS are declared per-TU (REAPERAPI_MINIMAL + per-TU WANT list) — main.cpp owns
|
||||
// the definitions (CLAUDE.md §contract).
|
||||
// REAPER API function pointers are declared per-TU; main.cpp owns the definitions.
|
||||
#include "reaper_plugin.h"
|
||||
|
||||
#include "core/audio/peaks.h" // audio::Envelope — thumbnail cache payload
|
||||
#include "core/capture/capture_paths.h" // capture::resolveBankFile / normalizeSlashes
|
||||
#include "core/capture/render_settings.h" // capture::CaptureActionDef / captureActionTable
|
||||
#include "core/capture/tail_control.h" // capture::TailSetting — the tail toggle state
|
||||
#include "core/model/bank_book.h" // BankBook / Bank / SlotMap (flat reasampler until its split wave)
|
||||
#include "core/model/bank_model.h" // model::BankModel / model::Sample
|
||||
#include "core/ui/action_bar.h" // ui::ActionBarRect / slots / clusters
|
||||
#include "core/ui/bank_grid.h" // ui::GridSpec / Selection / ThumbnailKey / CellRect
|
||||
#include "core/ui/card_drag.h" // ui::CardGesture / SlotCellRect / gesture decisions
|
||||
#include "core/ui/card_meta.h" // ui::MusicalLength / formatters
|
||||
#include "core/ui/component_geometry.h" // ui::KitBox / KitButtonBox / waveformColumnCount
|
||||
#include "core/ui/drag_out.h" // ui::DragState / PanelClientRect / decideGesture
|
||||
#include "core/ui/footer_bar.h" // ui::FooterBarLayout / computeFooterBar
|
||||
#include "core/ui/mode_enable.h" // ui::tagButtonEnabled / TagTarget
|
||||
#include "core/ui/overflow_menu.h" // ui::MenuButtonSpec / computeMenuButton
|
||||
#include "core/ui/prune_button.h" // ui::ButtonRect / computePruneButton
|
||||
#include "core/ui/tab_strip.h" // ui::TabStripSpec / layout / hit-test
|
||||
#include "core/ui/theme.h" // ui::Role / InteractionState / KitColor
|
||||
#include "core/ui/tooltip.h" // ui::TooltipBox / computeTooltip / stripActionPrefix
|
||||
#include "core/version/app_version.h" // version::channelCommandId / appVersion / dock identity
|
||||
#include "core/view/guid_diff.h" // view::GuidBaseline — new-content detection
|
||||
#include "core/view/lane_keys.h" // view::isOnManualLane
|
||||
#include "core/view/mode_switch.h" // view::SegmentRect / computeSegmentRects
|
||||
#include "core/wire/instrument_drop.h" // wire::buildInstrumentDropPreset (S17)
|
||||
#include "core/audio/peaks.h"
|
||||
#include "core/capture/capture_paths.h"
|
||||
#include "core/capture/render_settings.h"
|
||||
#include "core/capture/tail_control.h"
|
||||
#include "core/model/bank_book.h"
|
||||
#include "core/model/bank_model.h"
|
||||
#include "core/ui/action_bar.h"
|
||||
#include "core/ui/bank_grid.h"
|
||||
#include "core/ui/card_drag.h"
|
||||
#include "core/ui/card_meta.h"
|
||||
#include "core/ui/component_geometry.h"
|
||||
#include "core/ui/drag_out.h"
|
||||
#include "core/ui/footer_bar.h"
|
||||
#include "core/ui/mode_enable.h"
|
||||
#include "core/ui/overflow_menu.h"
|
||||
#include "core/ui/prune_button.h"
|
||||
#include "core/ui/tab_strip.h"
|
||||
#include "core/ui/theme.h"
|
||||
#include "core/ui/tooltip.h"
|
||||
#include "core/version/app_version.h"
|
||||
#include "core/view/guid_diff.h"
|
||||
#include "core/view/lane_keys.h"
|
||||
#include "core/view/mode_switch.h"
|
||||
#include "core/wire/instrument_drop.h"
|
||||
|
||||
#include "shell/panel/panel_layout.h" // BankPanelFullHeight — the split-state enum
|
||||
#include "shell/panel/panel_layout.h"
|
||||
|
||||
namespace reasampler {
|
||||
class ReaSamplerSession;
|
||||
@@ -77,14 +61,6 @@ class ReaSamplerSession;
|
||||
|
||||
namespace reasampler::panel {
|
||||
|
||||
// --- Real-namespace-home using-declarations -----------------------------------
|
||||
//
|
||||
// The panel's pre-split internals reference the pure modules' symbols unqualified;
|
||||
// these explicit per-symbol usings keep those references valid while documenting
|
||||
// each symbol's Q-W1 home. Flat-`reasampler` symbols (BankBook / ViewModeModel /
|
||||
// the draw_kit shell / the shell/bank_ops verbs / ...) resolve via the enclosing
|
||||
// namespace and need no using.
|
||||
|
||||
// core/ui
|
||||
using ui::ActionBarRect;
|
||||
using ui::ActionBarSlot;
|
||||
@@ -200,73 +176,46 @@ using version::dockTitle;
|
||||
// core/wire
|
||||
using wire::buildInstrumentDropPreset;
|
||||
|
||||
// --- Layout constants ---------------------------------------------------------
|
||||
//
|
||||
// L2: every panel COLOR comes from the pure `theme` module by ROLE (drawn through the
|
||||
// L1 kit — fillSurface / drawButton / kit text). Only the pixel LAYOUT metrics (band
|
||||
// heights, grid/tab specs, insets) live here, shared by the layout/render/input/drag
|
||||
// seams so draw and hit-test can never drift.
|
||||
// All color comes from `theme` by role, drawn through the kit. Only pixel layout
|
||||
// metrics live here, shared by layout/render/input/drag so draw and hit-test can
|
||||
// never drift.
|
||||
|
||||
inline const GridSpec kGrid{/*cellWidth=*/140, /*cellHeight=*/84, /*gap=*/10};
|
||||
|
||||
// --- Footer (Phase L, L4) -----------------------------------------------------
|
||||
// The footer carries a task-cluster of small persistent controls: the narrowed
|
||||
// [Arrange|Design] mode toggle, a compact per-mode count, the Tail BUTTON (L4 §4 —
|
||||
// a real kit button, no longer a click-zone), and the set-apart Prune button at the
|
||||
// right. Taller than the L2 footer to host the toggle segments + button chrome cleanly.
|
||||
// Layout is the pure footer_bar (left group) + prune_button (right); this is the band height.
|
||||
// Footer: [Arrange|Design] toggle, per-mode count, Tail button, Prune button
|
||||
// (footer_bar left group + prune_button right).
|
||||
inline constexpr int kFooterHeight = 30;
|
||||
|
||||
// --- Toolbars (Phase L, L4) ---------------------------------------------------
|
||||
// TWO task-grouped toolbars, both drawn through the pure action_bar module:
|
||||
// * kTopToolbarHeight — the TOP toolbar (capture + placement clusters) at the very top of
|
||||
// the client, where the eye lands (L4 §1). Replaces the L2 mode-switch header there.
|
||||
// * kBottomToolbarHeight — the BOTTOM toolbar (Design-View tag/switch verbs) directly above
|
||||
// the footer (L4 §2). This is the L2 action-bar band, repurposed.
|
||||
inline constexpr int kTopToolbarHeight = 28; // single-row label face (L6: keybinding sub-row removed)
|
||||
inline constexpr int kBottomToolbarHeight = 28; // same shape — both bars consistent
|
||||
// Two task-grouped toolbars drawn through action_bar: top = capture + placement,
|
||||
// bottom = Design-View tag/switch verbs, directly above the footer.
|
||||
inline constexpr int kTopToolbarHeight = 28;
|
||||
inline constexpr int kBottomToolbarHeight = 28;
|
||||
|
||||
// --- Tooltip (Phase L, L5) ----------------------------------------------------
|
||||
// The custom hover-delay tooltip's timing + approximate text metrics. The delay matches the
|
||||
// platform convention (~0.5 s) so the tooltip is deliberate, not twitchy; it is driven off the
|
||||
// OnTimer poll (bankPanelRefresh) + WM_MOUSEMOVE, so no dedicated timer is added. The kit font
|
||||
// is AA and proportional, so the width is estimated from a per-char average (the tooltip box is
|
||||
// generous — a slight over/under-estimate only pads the box, never clips the text).
|
||||
// Hover-delay tooltip timing, driven off the OnTimer poll (no dedicated timer). Kit
|
||||
// font is proportional, so char width is a generous estimate (pads, never clips).
|
||||
inline constexpr unsigned int kTooltipDelayMs = 500;
|
||||
inline constexpr int kTooltipCharPx = 7; // approx px per char at Font::Label (generous)
|
||||
inline constexpr int kTooltipTextH = 14; // approx line height at Font::Label
|
||||
inline constexpr int kTooltipCharPx = 7;
|
||||
inline constexpr int kTooltipTextH = 14;
|
||||
|
||||
// --- Vertical split + region headers + tab strip (Phase B4; L4 re-home) -------
|
||||
//
|
||||
// The client area, top to bottom (L4): TOP toolbar (kTopToolbarHeight, capture + placement) |
|
||||
// split body | BOTTOM toolbar (kBottomToolbarHeight, Design-View verbs) | footer
|
||||
// (kFooterHeight — mode toggle + count + Tail button + Prune). The split body holds the pool
|
||||
// region (top) and the named-banks region (bottom). Each region opens with a REGION HEADER
|
||||
// band: a title, the active-bank readout, and a full-height toggle button. The named-banks
|
||||
// region's header ALSO hosts the LICE tab strip and a "+" create button.
|
||||
inline constexpr int kRegionHeaderHeight = 24; // per-region title/toggle band
|
||||
inline constexpr int kTabStripHeight = 26; // the named-banks tab strip band
|
||||
inline constexpr int kSplitDividerHeight = 3; // the horizontal divider between regions
|
||||
inline constexpr int kFullHtBtnWidth = 22; // the square full-height toggle button
|
||||
inline constexpr int kCreateBtnWidth = 22; // the "+" create-bank button
|
||||
// Client area top to bottom: top toolbar | split body | bottom toolbar | footer.
|
||||
inline constexpr int kRegionHeaderHeight = 24;
|
||||
inline constexpr int kTabStripHeight = 26;
|
||||
inline constexpr int kSplitDividerHeight = 3;
|
||||
inline constexpr int kFullHtBtnWidth = 22;
|
||||
inline constexpr int kCreateBtnWidth = 22;
|
||||
|
||||
// Tab strip metrics (the pure tab_strip owns the math; these are its inputs).
|
||||
inline const TabStripSpec kTabSpec{/*tabWidth=*/96, /*chevronWidth=*/20};
|
||||
|
||||
// The spec for the far-right More ("⋯") overflow-menu button. One source of truth for its
|
||||
// geometry + the reserve the action_bar leaves for it (L5).
|
||||
// Far-right More ("...") overflow-menu button: one source of truth for its
|
||||
// geometry + the reserve action_bar leaves for it.
|
||||
inline const MenuButtonSpec kMenuBtnSpec{/*buttonWidth=*/28, /*rightInset=*/6,
|
||||
/*verticalInset=*/3, /*minLeftInset=*/40};
|
||||
|
||||
// The toolbar layout spec (the panel's 8px-grid density decision). One source of truth shared
|
||||
// by both toolbars' draw and hit-test (identical button shape top and bottom). L5 refinement 5:
|
||||
// clusterGap widened 16 -> 24 (a 6:1 inter/intra ratio) so semantic groups read AS groups. L6:
|
||||
// bindingHeight / minSplitHeight removed — buttons are single-row label-only faces now.
|
||||
// Shared by both toolbars' draw and hit-test (identical button shape top and
|
||||
// bottom). clusterGap is wider than buttonGap so semantic groups read as groups.
|
||||
inline const ActionBarSpec kBarSpec{/*buttonWidth=*/108, /*buttonGap=*/4, /*clusterGap=*/24,
|
||||
/*sidePad=*/8, /*verticalInset=*/3};
|
||||
|
||||
// --- Panel state --------------------------------------------------------------
|
||||
|
||||
struct CachedThumbnail {
|
||||
Envelope envelope;
|
||||
int width = 0;
|
||||
@@ -276,32 +225,28 @@ struct CachedThumbnail {
|
||||
// input. The move/copy source is the focused region's displayed bank.
|
||||
enum class Region { Pool, Banks };
|
||||
|
||||
// What a drag is dropping onto, resolved live under the pointer during a drag.
|
||||
// BanksRegion fires when the pointer is anywhere in the named-banks grid that is NOT
|
||||
// on a specific tab (tab takes precedence — more specific wins). The resolved bank is
|
||||
// always shownBankId.
|
||||
// What a drag is dropping onto, resolved live under the pointer. BanksRegion fires
|
||||
// when the pointer is anywhere in the named-banks grid that is NOT on a specific tab
|
||||
// (tab takes precedence); the resolved bank is always shownBankId.
|
||||
enum class DropKind { None, PoolRegion, Tab, BanksRegion };
|
||||
|
||||
// --- Hover model (Phase L, L2) ------------------------------------------------
|
||||
//
|
||||
// The hovered interactive element, resolved live in WM_MOUSEMOVE so the kit draws its
|
||||
// hover state on that element only (the "hover on every interactive element" + "sub-frame
|
||||
// feedback = the perception of speed" L2 constraint). SWELL exposes no WM_MOUSELEAVE (grep
|
||||
// of vendor/WDL/WDL/swell — none), so hover is cleared by a move that resolves to None
|
||||
// rather than a leave message; the panel is Windows-only (D5) but this stays portable-safe.
|
||||
// hover state on that element only. SWELL exposes no WM_MOUSELEAVE (confirmed: no hit in
|
||||
// vendor/WDL/WDL/swell), so hover is cleared by a move that resolves to None rather than a
|
||||
// leave message; the panel is Windows-only but this stays portable-safe.
|
||||
// `index` disambiguates within a kind (action-bar button index, tab index); -1 when N/A.
|
||||
enum class HoverKind {
|
||||
None,
|
||||
TopBarButton, // a button in the TOP toolbar (index = flat action index into topBarRows)
|
||||
BottomBarButton, // a button in the BOTTOM toolbar (index = flat action index into bottomBarRows)
|
||||
MoreButton, // the TOP toolbar's far-right "⋯" overflow-menu button (L5)
|
||||
TopBarButton, // index = flat action index into topBarRows
|
||||
BottomBarButton, // index = flat action index into bottomBarRows
|
||||
MoreButton,
|
||||
PruneButton,
|
||||
FullHtPool, // pool region full-height toggle
|
||||
FullHtBanks, // banks region full-height toggle
|
||||
CreateBank, // the "+" create-bank button
|
||||
Tab, // a named-bank tab (index = tab ordinal)
|
||||
TailButton, // the footer Tail button (L4 §4 — a real button, was a click-zone)
|
||||
ModeSegment, // a footer mode-toggle segment (index = segment ordinal)
|
||||
FullHtPool,
|
||||
FullHtBanks,
|
||||
CreateBank,
|
||||
Tab, // index = tab ordinal
|
||||
TailButton,
|
||||
ModeSegment, // index = segment ordinal
|
||||
};
|
||||
|
||||
struct Hover {
|
||||
@@ -312,9 +257,8 @@ struct Hover {
|
||||
bool operator!=(const Hover& o) const { return !(*this == o); }
|
||||
};
|
||||
|
||||
// The kit interaction state for an interactive element: Hover when this (kind,index) is the
|
||||
// live hovered element, else Rest. Active/Pressed are decided per-element by the caller (e.g.
|
||||
// an active tab draws Active regardless of hover); this is the base rest/hover resolver.
|
||||
// Base rest/hover resolver; Active/Pressed are decided per-element by the caller
|
||||
// (e.g. an active tab draws Active regardless of hover).
|
||||
inline InteractionState hoverState(const Hover& hovered, HoverKind kind, int index) {
|
||||
return (hovered.kind == kind && hovered.index == index) ? InteractionState::Hover
|
||||
: InteractionState::Rest;
|
||||
@@ -331,135 +275,83 @@ struct PanelState {
|
||||
|
||||
std::unordered_map<std::string, CachedThumbnail> cache;
|
||||
|
||||
// --- Selection (per focused region) ---------------------------------------
|
||||
// One live selection, scoped to `focusedRegion`. Switching regions moves the
|
||||
// selection with the focus (a click in the other region reseeds it there).
|
||||
// selection with the focus.
|
||||
Selection selection;
|
||||
int selItemCount = 0;
|
||||
Region focusedRegion = Region::Pool;
|
||||
|
||||
// --- Hover (Phase L, L2) --------------------------------------------------
|
||||
// The live hovered interactive element (WM_MOUSEMOVE resolves it; the kit draws its
|
||||
// hover state). Repaint fires only when this changes (sub-frame, no per-move jank).
|
||||
// Resolved on WM_MOUSEMOVE; repaint fires only when this changes.
|
||||
Hover hovered;
|
||||
|
||||
// --- Tooltip (Phase L, L5) ------------------------------------------------
|
||||
// A custom LICE-kit hover-delay tooltip (NOT the native Win32/SWELL tooltip control): when a
|
||||
// TOOLTIP-capable element (a toolbar button) stays hovered past kTooltipDelayMs, the panel
|
||||
// draws a small overlay carrying the full, prefix-stripped action name. hoverSinceTick is the
|
||||
// GetTickCount() at which the CURRENT hovered element was first entered (reset on every hover
|
||||
// change); tooltipShown latches once the delay elapses so the OnTimer poll repaints exactly
|
||||
// once when the tooltip appears. The last-seen pointer pos anchors nothing (the anchor is the
|
||||
// hovered button's rect), but is kept so the OnTimer path can re-resolve without a live event.
|
||||
// Custom hover-delay tooltip. hoverSinceTick resets on every hover change;
|
||||
// tooltipShown latches once the delay elapses so the OnTimer poll repaints once.
|
||||
unsigned int hoverSinceTick = 0;
|
||||
bool tooltipShown = false;
|
||||
|
||||
// --- Vertical-split state -------------------------------------------------
|
||||
BankPanelFullHeight fullHeight = BankPanelFullHeight::Split;
|
||||
|
||||
// The named bank whose grid the banks region shows (the SHOWN tab) — DISTINCT
|
||||
// from the active/capture-target bank (book().activeBankId()). Empty when there
|
||||
// are no named banks. Reconciled each fingerprint pass so it always names a live
|
||||
// named bank (or is empty).
|
||||
// The named bank the banks region shows — distinct from the active/capture-target
|
||||
// bank. Reconciled each fingerprint pass so it always names a live bank (or empty).
|
||||
std::string shownBankId;
|
||||
|
||||
// Tab-strip horizontal scroll offset (px), clamped to the strip's max each frame.
|
||||
int tabScroll = 0;
|
||||
|
||||
// --- Drag (sample move between regions/onto a tab) ------------------------
|
||||
// A drag begins only after the pointer moves past a threshold from a press that
|
||||
// landed on a SELECTED grid cell — this is how it is disambiguated from the M5
|
||||
// multi-select drag (which begins immediately on any grid press). See handleClick/
|
||||
// onMouseMove. dragging is true once the threshold is crossed.
|
||||
bool dragArmed = false; // pressed on a selected cell; watching for threshold
|
||||
bool dragging = false; // threshold crossed; a move-drag is in progress
|
||||
// A drag begins only after the pointer moves past a threshold from a press
|
||||
// that landed on a selected grid cell — disambiguates from the multi-select
|
||||
// drag (which begins immediately on any grid press).
|
||||
bool dragArmed = false;
|
||||
bool dragging = false;
|
||||
int dragStartX = 0, dragStartY = 0;
|
||||
Region dragSourceRegion = Region::Pool;
|
||||
std::string dragSourceBankId; // the bank the dragged samples come from
|
||||
std::vector<std::string> dragSampleIds;// snapshot of the selection at drag start
|
||||
std::string dragPrimaryId; // the single card grabbed (the focus) — the L7
|
||||
// reorder/replace subject (see onLBtnUp dispatch)
|
||||
DropKind dropKind = DropKind::None; // live drop target under the pointer
|
||||
std::string dragSourceBankId;
|
||||
std::vector<std::string> dragSampleIds;
|
||||
std::string dragPrimaryId; // the single card grabbed — the reorder/replace subject
|
||||
DropKind dropKind = DropKind::None;
|
||||
std::string dropBankId; // destination bank id when dropKind==Tab
|
||||
|
||||
// --- L7 in-grid reorder/replace drag --------------------------------------
|
||||
// The live card gesture resolved by the pure card_drag::decideCardGesture each mouse-
|
||||
// move (drives the cursor cue AND the drop dispatch), plus the same-bank target slot the
|
||||
// pointer sits over (>= 0 only for a Reorder/Replace over the source bank's own grid; -1
|
||||
// otherwise). A Reorder highlights dragTargetSlot's cell; Replace + a live cursor cue
|
||||
// signal the Alt-over-occupied case. Reset with the rest of the drag state on drop/cancel.
|
||||
// Resolved each mouse-move by card_drag::decideCardGesture. dragTargetSlot >= 0
|
||||
// only for a Reorder/Replace over the source bank's own grid.
|
||||
CardGesture cardGesture = CardGesture::None;
|
||||
int dragTargetSlot = -1;
|
||||
|
||||
// --- S17 drop-and-load (InstrumentDrop) -----------------------------------
|
||||
// While a SINGLE-capture drag is over REAPER's own UI outside the panel, the drag is an
|
||||
// InstrumentDrop heading for a track's TCP FX button. The shell hover-tracks the FX
|
||||
// hotspot; on release over a valid target it adds a ReaSampler 9000 preloaded with the
|
||||
// dragged capture (no OS drag, no timeline insert). instrumentDropTrack is the last
|
||||
// resolved FX-hotspot track (null when the pointer is not over an FX button) — read on
|
||||
// release. Only set/used on Windows (D5); the M11 OsDrag and internal drag are untouched.
|
||||
// While a single-capture drag is over REAPER's own UI, heading for a track's TCP FX
|
||||
// button: on release this adds a ReaSampler 9000 preloaded with the capture. Null
|
||||
// when the pointer is not over an FX button.
|
||||
MediaTrack* instrumentDropTrack = nullptr;
|
||||
|
||||
// --- Tail-mode toggle -----------------------------------------------------
|
||||
// The authoritative tail setting lives in ReaSamplerSession (session->tail()),
|
||||
// NOT in panel state, so it travels inside the .rpp (persist serializes it on save,
|
||||
// restores it on project load). The panel reads it for drawing and mutates it via
|
||||
// the footer click (cycle mode) and scroll-wheel (Manual fine-adjust), marking the
|
||||
// project dirty so the choice saves. bankPanelTailSetting is the read seam for the
|
||||
// capture actions. Held here only through the session pointer above.
|
||||
// Authoritative tail setting lives in ReaSamplerSession, not here; panel reads it for
|
||||
// drawing and mutates via footer click / scroll-wheel. bankPanelTailSetting is the
|
||||
// capture actions' read seam.
|
||||
|
||||
// --- Audition preview -----------------------------------------------------
|
||||
preview_register_t preview{};
|
||||
PCM_source* previewSrc = nullptr;
|
||||
bool previewActive = false;
|
||||
bool previewInited = false; // guards double init / deinit
|
||||
|
||||
// --- New-content detection (D2 Wave 2) ------------------------------------
|
||||
//
|
||||
// Each timer tick diffs the live track+item GUID set against the previous tick to
|
||||
// auto-tag content created SINCE the last tick into the then-active mode. The
|
||||
// baseline carries the first-poll-after-open guard (GuidBaseline self-arms on its
|
||||
// first observe()) so pre-existing content is never mass-tagged (it stays Arrange).
|
||||
//
|
||||
// Project-load re-arm is driven by persist's AUTHORITATIVE load lifecycle, NOT by a
|
||||
// pointer compare here. main.cpp calls bankPanelNotifyProjectLoaded() on the exact
|
||||
// tick persist restores a project's membership + active mode (the same tick it
|
||||
// reapplies the active mode); that sets reloadPending so the NEXT detect tick this
|
||||
// same tick re-baselines against the fully-loaded set and reports nothing new. This
|
||||
// replaces the former `proj != lastProject` re-arm, which used a WEAKER signal than
|
||||
// persist (pointer-only vs persist's GUID-primary identity) and so missed a load onto
|
||||
// a RECYCLED ReaProject* address — the just-loaded project's pre-existing tracks then
|
||||
// diffed against the previous project's stale baseline and were mass-tagged into the
|
||||
// active mode (the reload-mis-tag bug). Coordinating with persist's signal makes the
|
||||
// two identity checks agree by construction.
|
||||
//
|
||||
// Lives for the extension's lifetime alongside the session, independent of panel
|
||||
// open/close — detection must run whether or not the dock is visible (content is
|
||||
// created in the arrange, not the panel).
|
||||
// auto-tag new content. GuidBaseline self-arms on first observe() so pre-existing
|
||||
// content is never mass-tagged. Project-load re-arm is driven by persist's load
|
||||
// signal, not a ReaProject* compare — a recycled address previously mis-tagged tracks.
|
||||
GuidBaseline contentBaseline;
|
||||
bool reloadPending = false; // set by bankPanelNotifyProjectLoaded; drained next detect tick
|
||||
};
|
||||
|
||||
// The one shared panel state blob. Defined in panel_window.cpp (the lifecycle owner).
|
||||
// Defined in panel_window.cpp (the lifecycle owner).
|
||||
extern PanelState g_panel;
|
||||
|
||||
// --- L7 slot-order display bridge ---------------------------------------------
|
||||
//
|
||||
// L7 re-maps cell index <-> sample identity: the grid draws in the bank's persisted
|
||||
// SlotMap order (sparse, gap-preserving), NOT BankModel insertion order. regionDisplay
|
||||
// (panel_layout.cpp) is the single place that resolves a region's display, composed
|
||||
// purely from bank_book's slot order (orderedSampleIds) + card_drag's sparse slot rects
|
||||
// (computeSlotRects) — the shell adds no layout math of its own.
|
||||
// The grid draws in the bank's persisted SlotMap order (sparse, gap-preserving),
|
||||
// NOT BankModel insertion order. regionDisplay (panel_layout.cpp) is the single
|
||||
// place that resolves a region's display.
|
||||
//
|
||||
// TWO INDEX SPACES the whole panel must keep straight:
|
||||
// * SLOT — a display position 0..maxSlot; gaps are empty slots that draw as empty
|
||||
// cells and are valid drop targets. This is what pixels/hit-tests speak.
|
||||
// * SELECTION — the DENSE occupied-ordinal [0, occupied) space the pure Selection /
|
||||
// applyClick / navigate reason in. Selection index i <-> orderedIds[i].
|
||||
// Keyboard navigation therefore traverses ONLY occupied cells and SKIPS
|
||||
// gaps (spec: skip-vs-land-on-gap is unspecified -> skip, documented here).
|
||||
// RegionDisplay carries both plus the translation between them, resolved FRESH each call
|
||||
// (never cached across a mutation, per the reference-invalidation guardrail).
|
||||
// * SLOT — display position 0..maxSlot; gaps are empty, valid drop targets.
|
||||
// What pixels/hit-tests speak.
|
||||
// * SELECTION — the dense occupied-ordinal [0, occupied) space the pure
|
||||
// Selection/applyClick/navigate reason in. Selection index i <->
|
||||
// orderedIds[i]. Keyboard nav therefore skips gaps.
|
||||
// RegionDisplay carries both plus the translation, resolved fresh each call (never
|
||||
// cached across a mutation, per the reference-invalidation guardrail).
|
||||
struct RegionDisplay {
|
||||
std::vector<std::string> orderedIds; // occupied ids in slot order (selection space)
|
||||
std::vector<SlotCellRect> slotRects; // one rect per slot 0..maxSlot, viewport coords
|
||||
@@ -486,27 +378,18 @@ struct RegionDisplay {
|
||||
int occupiedCount() const { return static_cast<int>(orderedIds.size()); }
|
||||
};
|
||||
|
||||
// --- Toolbar row vocabulary (Phase L, L4/L5/L6) --------------------------------
|
||||
//
|
||||
// One action button: its channel-AGNOSTIC command-id suffix (composed with the channel prefix
|
||||
// at fire time — never a hardcoded numeric id), its terse on-button FACE label, its full action
|
||||
// NAME for the hover tooltip (already prefix-stripped — the "ReaSampler:" display prefix is
|
||||
// dropped at build), and the task cluster it belongs to. The order of a toolbar's row list IS
|
||||
// the flat action index the pure action_bar slots carry, so each list is built cluster-by-cluster
|
||||
// in its toolbar's cluster order. Built by panel_layout (topBarRows / bottomBarRows /
|
||||
// overflowMenuRows); consumed by the render draw, the input click routing, and the drag hover.
|
||||
// One action button. Row order IS the flat action index the pure action_bar slots
|
||||
// carry. Built by panel_layout; consumed by render, input, drag.
|
||||
struct ActionBarRow {
|
||||
std::string suffix;
|
||||
std::string shortLabel;
|
||||
std::string fullName;
|
||||
ActionCluster cluster = ActionCluster::Capture;
|
||||
bool enabled = true; // L5: opposite-mode gate for the bottom-bar tag buttons; always true
|
||||
// for the top bar (its actions are unconditional triggers).
|
||||
bool enabled = true; // opposite-mode gate for bottom-bar tag buttons; always true
|
||||
// for the top bar (unconditional triggers)
|
||||
};
|
||||
|
||||
// --- Shared one-liner helpers --------------------------------------------------
|
||||
|
||||
// Modifier state at event time. Alt = the L7 replace modifier.
|
||||
// Modifier state at event time. Alt = the replace modifier.
|
||||
inline bool ctrlDown() { return (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0; }
|
||||
inline bool shiftDown() { return (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0; }
|
||||
inline bool altDown() { return (GetAsyncKeyState(VK_MENU) & 0x8000) != 0; }
|
||||
@@ -515,7 +398,7 @@ inline void invalidatePanel() {
|
||||
if (g_panel.hwnd) InvalidateRect(g_panel.hwnd, nullptr, FALSE);
|
||||
}
|
||||
|
||||
// --- Cross-seam contract (grouped by OWNING TU; all plain free functions) ------
|
||||
// Cross-seam contract, grouped by owning TU; all plain free functions.
|
||||
|
||||
// panel_bank_ops.cpp — book/bank accessors + the bank-CRUD verbs + menus.
|
||||
BankBook* book();
|
||||
@@ -536,7 +419,7 @@ void showSelectionMenu(int screenX, int screenY);
|
||||
void showMoreMenu();
|
||||
|
||||
// panel_layout.cpp — toolbar/footer/menu rects, row/cluster builders, split geometry,
|
||||
// region rects, the L7 display bridge. Draw and hit-test both call these so they never drift.
|
||||
// region rects, the display bridge. Draw and hit-test both call these so they never drift.
|
||||
int modeCount();
|
||||
MenuButtonRect topMenuButtonRect(int w);
|
||||
ActionBarRect topToolbarActionRect(int w);
|
||||
@@ -579,8 +462,8 @@ const Envelope& thumbnailFor(const Sample& sample, int width, const std::string&
|
||||
bool refreshFingerprint();
|
||||
void reconcileShownBank();
|
||||
|
||||
// panel_audition.cpp — the preview engine (HOT PATH: direct call-through, never
|
||||
// virtual, no added header->TU indirection — T4-28 / Q-W2 guardrail).
|
||||
// panel_audition.cpp — the preview engine (hot path: direct call-through, never
|
||||
// virtual, no added header->TU indirection).
|
||||
void initPreview();
|
||||
void deinitPreview();
|
||||
void stopAudition();
|
||||
@@ -595,7 +478,7 @@ void registerAccel();
|
||||
void unregisterAccel();
|
||||
|
||||
// panel_drag.cpp — the card-drag/hover state machine (pure mirror: core/ui/card_drag).
|
||||
// Per-mouse-move work stays plain free-function calls (T4-28).
|
||||
// Per-mouse-move work stays plain free-function calls.
|
||||
void onMouseMove(int x, int y);
|
||||
void onLBtnUp(int x, int y);
|
||||
void handleRightClick(int x, int y);
|
||||
|
||||
Reference in New Issue
Block a user