S12: editor scale + S15/S16 control surfaces

Pure browser_scroll/note_entry/param_slider modules (+ CTest) for scroll,
type-to-filter search, numeric note entry, and the AHDSR/Trigger/pitch-engine/
pitch-env control panel. Editor shell draws + routes through them; params edit
the selected zone's ZonePlayParams via commitAndReload.
This commit is contained in:
2026-07-27 01:09:19 -04:00
parent ddc2ec1e75
commit 4f30124ef7
13 changed files with 1667 additions and 31 deletions
+66 -1
View File
@@ -31,6 +31,7 @@
#include "public.sdk/source/common/pluginview.h"
#include "editor_geometry.h" // Rect (the shell's sub-rect type, shared with the pure modules)
#include "param_slider.h" // ControlRow (the S12/S15/S16 control-surface geometry)
#include "peaks.h" // Envelope (the cached peak thumbnail)
#include "sample_map.h" // SampleChoice, BankChoice, PerformanceMap (the shell's snapshot)
@@ -70,7 +71,29 @@ private:
// flight. The zone-edit grabs mirror keyboard_strip::ZoneGrab; kRootMarker is the
// single-capture root drag on the setup strip; kWaveMarker is a draggable start/loop
// marker on the S11 waveform surface (which marker is in waveMarker_).
enum class DragKind { kNone, kRootMarker, kZoneLow, kZoneHigh, kZoneBody, kWaveMarker };
enum class DragKind { kNone, kRootMarker, kZoneLow, kZoneHigh, kZoneBody, kWaveMarker,
kScrollThumb, kParamSlider };
// The parameter controls on the setup surface (S12 AHDSR + the S15/S16 control surfaces).
// The int value is the ControlDesc id the pure param_slider hit-test returns; the shell
// maps it to the picked zone's play params. Order here is the panel's top-down stack order.
enum class ParamControl {
kPlayMode = 0, // Gate | Trigger toggle (S15)
kPitchEngine, // Varispeed | Preserve toggle (S16)
kAttack, // AHDSR attack (Gate) / —
kHold, // AHDSR hold (Gate, S15)
kDecay, // AHDSR decay (Gate)
kSustain, // AHDSR sustain (Gate)
kRelease, // AHDSR release (Gate)
kTrigLength, // Trigger %-length (Trigger, S15)
kTrigFadeIn, // Trigger fade-in (Trigger, S15)
kTrigFadeOut, // Trigger fade-out (Trigger, S15)
kPitchEnvEnable, // AD pitch envelope on|off (S16)
kPitchEnvAttack, // AD pitch attack (S16)
kPitchEnvDecay, // AD pitch decay (S16)
kPitchEnvDepth, // AD pitch depth in +/- semitones (S16)
kCount
};
// The waveform markers on the single-capture setup surface (S11). Order is the draw + hit
// order (start first). Named generically per the spec so S15 can repurpose the surface with
@@ -83,10 +106,13 @@ private:
void paintSetup(LICE_IBitmap* bmp, const Rect& area);
void paintZones(LICE_IBitmap* bmp, int w, int h);
void paintEmptyState(LICE_IBitmap* bmp, const Rect& area);
void paintControls(LICE_IBitmap* bmp, const Rect& panel); // S12/S15/S16 param surface
void onMouseDown(int x, int y);
void onMouseMove(int x, int y);
void onMouseUp(int x, int y);
void onMouseWheel(int delta); // S12 browser scroll (wheel)
void onSearchChar(unsigned int ch); // S12 type-to-filter search keystroke
// The S9/S8 change-detection tick (WM_TIMER on the child window — the UI thread, NEVER the
// audio thread). Polls the processor's bank-sync (generation change -> hands-free reload;
@@ -149,6 +175,25 @@ private:
// final commit. selectedId_ must be non-empty before calling.
void upsertPickedOverride(const SetupMarkers& m);
// --- S12/S15/S16 parameter surface (Zones panel, keyed to selectedZone_) ------
//
// The control panel edits the SELECTED zone's ZonePlayParams (S15 play mode + AHDSR; S16
// pitch engine + AD pitch envelope). Instrument-owned (D-B), never a bank fact.
// The control descriptors the panel shows for `play`'s CURRENT play mode: the two toggles +
// the mode-relevant sliders (AHDSR for Gate, %-length/fades for Trigger) + the pitch-envelope
// controls. The pure param_slider lays these out; this only picks the set. Static (a free
// choice of set from the mode) — kept a member for the ParamControl enum access.
std::vector<ControlDesc> controlDescs(const ZonePlayParams& play) const;
// The normalized [0,1] display value for control `id` given `play` (the shell's domain
// mapping: frames->0..1 over a fixed max, sustain 0..1 as-is, semitone depth centered at 0.5).
double controlValue(int id, const ZonePlayParams& play) const;
// Apply a committed control interaction to `play`: a slider's normalized `value` (mapped back
// into the control's engine domain) or a toggle's `segment` (0/1). Mutates `play` in place.
void applyControl(int id, ZonePlayParams& play, double value, int segment) const;
ReaSamplerProcessor* processor_ = nullptr;
// --- Snapshot of the live bank (drawn each paint; refreshed off the audio thread) ---
@@ -164,9 +209,22 @@ private:
std::string activeFilterBankId_; // "" = All; else a bank id from banks_
int selectedZone_ = -1; // highlighted zone in the Zones panel; -1 = none
// --- S12 browser scroll + search (transient UI state, never persisted) --------
int scrollOffset_ = 0; // vertical px offset into the card grid (clamped)
std::string searchQuery_; // type-to-filter narrow; "" = no search
bool searchFocused_ = false; // whether the search box has keyboard focus
// --- S12 numeric note entry (LICE text-entry idiom, transient) ----------------
// When >= 0, a low/high/root field is being typed; entryText_ accumulates the keystrokes
// and commits (parseNoteEntry) on Enter. -1 = no field editing. The field id is a
// ParamControl-independent small enum encoded inline (see the .cpp: 0=low,1=high,2=root).
int entryField_ = -1;
std::string entryText_;
// --- Drag-state machine ------------------------------------------------------
DragKind drag_ = DragKind::kNone;
int dragStartX_ = 0; // grab x (px), for the pixel-delta resolver
int dragStartY_ = 0; // grab y (px), for the vertical scrollbar-thumb drag
int dragStartLow_ = 0; // the grabbed field's note at grab time
int dragStartHigh_ = 0;
int dragStartRoot_ = 60;
@@ -179,6 +237,13 @@ private:
SetupMarkers dragStartMarkers_;
std::int64_t dragSampleFrames_ = 0; // decoded length of the sample under the drag
// S12 scrollbar-thumb drag: the offset held at grab time (the pixel-delta resolver shifts
// from it). S12/S15/S16 param-slider drag: which control id + the panel it lives in (the
// shell re-lays the panel each move to map x->value against the live control rect).
int dragStartScrollOffset_ = 0;
int dragParamId_ = -1;
Rect dragParamPanel_{};
// --- Peak-thumbnail cache (mirror of bank_panel; id -> envelope at a bin width) ------
// Keyed by "id|binCount" so a resize recomputes at the new width. Cleared on refresh so
// a bank edit (a re-captured or deleted sample) does not show a stale thumbnail.