FB2: Zone panel adopts the r11 knob deck + curve popup (R11-F2 parity) — slider rows and inline curve box retired, zone-authoring affordances kept
This commit is contained in:
+71
-58
@@ -33,8 +33,7 @@
|
||||
#include "editor_geometry.h" // Rect (the shell's sub-rect type, shared with the pure modules)
|
||||
#include "envelope_edit.h" // EnvClampBounds / NodeHit (S-VIEW-3 envelope node hit-test/edit)
|
||||
#include "envelope_overlay.h" // AmpEnvelope / EnvNode (S-VIEW-3 envelope overlay draw seam)
|
||||
#include "knob_deck.h" // DeckGroupDesc / DeckLayout (r11 Sample-face knob deck, FB1)
|
||||
#include "param_slider.h" // ControlRow + the FA4 radial-knob primitive (S12/S15/S16 + r11)
|
||||
#include "knob_deck.h" // DeckGroupDesc / DeckLayout (r11 knob deck — Sample FB1, Zone FB2)
|
||||
#include "peaks.h" // Envelope (the cached peak thumbnail)
|
||||
#include "sample_map.h" // SampleChoice, BankChoice, PerformanceMap (the shell's snapshot)
|
||||
#include "velocity_curve.h" // VelocityCurve (S-VIEW-10 transfer-curve editor state)
|
||||
@@ -82,14 +81,15 @@ private:
|
||||
// draggable envelope breakpoint on the Sample-view hero overlay (S-VIEW-3, which node in
|
||||
// envNode_); kCurveNode is a draggable velocity-curve control point in the S-VIEW-10
|
||||
// transfer-curve editor (which point in curvePointIndex_); kDeckKnob is a GRAB-ANCHORED
|
||||
// vertical radial-knob drag on the r11 Sample-face deck/cluster (which control in
|
||||
// dragParamId_; the value at grab in dragKnobStartValue_ — no jump on grab, FA4).
|
||||
// vertical radial-knob drag on an r11 knob deck — the Sample face's deck/cluster (FB1)
|
||||
// or the Zone panel's per-zone deck (FB2) — (which control in dragParamId_; the value at
|
||||
// grab in dragKnobStartValue_ — no jump on grab, FA4).
|
||||
enum class DragKind { kNone, kRootMarker, kZoneLow, kZoneHigh, kZoneBody, kWaveMarker,
|
||||
kScrollThumb, kParamSlider, kEnvNode, kCurveNode, kDeckKnob };
|
||||
kScrollThumb, kEnvNode, kCurveNode, kDeckKnob };
|
||||
|
||||
// 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.
|
||||
// The int value is the opaque control id the pure knob_deck hit-test returns; the shell
|
||||
// maps it to the picked zone's play params (or a processor-side per-instance setter).
|
||||
enum class ParamControl {
|
||||
kPlayMode = 0, // Gate | Trigger toggle (S15)
|
||||
kPitchEngine, // Varispeed | Preserve toggle (S16)
|
||||
@@ -162,14 +162,20 @@ private:
|
||||
void paintBrowse(LICE_IBitmap* bmp, int w, int h); // S-VIEW-5 modal picker overlay
|
||||
void paintZone(LICE_IBitmap* bmp, int w, int h); // S-VIEW-8 zone surface
|
||||
void paintEmptyState(LICE_IBitmap* bmp, const Rect& area);
|
||||
void paintControls(LICE_IBitmap* bmp, const Rect& panel, const PerformanceZone& zone); // S12/S15/S16 + keyTrack (Zone surface; the Sample face uses the r11 knob deck)
|
||||
|
||||
// --- r11 Sample-face recomposition (FB1) ---------------------------------------
|
||||
// The knob deck: the fenced task groups (AMP ENVELOPE / PITCH / PITCH ENV / VOICE /
|
||||
// MASTER) drawn through the L1 kit — group fence + caption + compact caption toggles +
|
||||
// radial knobs (param_slider's FA4 primitive) with label<->value swap on hover/drag.
|
||||
void paintKnobDeck(LICE_IBitmap* bmp, const Rect& deckArea, const PerformanceZone& zone);
|
||||
// The centered curve-popup sheet (wash + title + close + full-size curve editor).
|
||||
// --- r11 knob-deck rendering (FB1 Sample face; FB2 Zone panel) -------------------
|
||||
// The knob deck: the fenced task groups drawn through the L1 kit — group fence + caption +
|
||||
// compact caption toggles + radial knobs (param_slider's FA4 primitive) with label<->value
|
||||
// swap on hover/drag. `descs` picks the group set: the full Sample deck (deckGroupDescs)
|
||||
// or the Zone panel's per-zone groups (zoneDeckGroupDescs). Lays out from deckArea's
|
||||
// top-left; the caller anchors (Sample bottom-anchors, Zone top-anchors).
|
||||
void paintKnobDeck(LICE_IBitmap* bmp, const Rect& deckArea, const PerformanceZone& zone,
|
||||
const std::vector<DeckGroupDesc>& descs);
|
||||
// The mini curve-preview button (shared by the Sample cluster + the Zone panel, FB2): a
|
||||
// hairline bg/cell square tracing the zone's live curve; Active border while the popup is up.
|
||||
void paintCurveButton(LICE_IBitmap* bmp, const Rect& r, const PerformanceZone& zone);
|
||||
// The centered curve-popup sheet (wash + title + close + full-size curve editor). Edits
|
||||
// popupZone() — the Sample face's one-zone site or the Zone surface's selected zone (FB2).
|
||||
void paintCurvePopup(LICE_IBitmap* bmp, int w, int h);
|
||||
// Trace the S-VIEW-3 amp-envelope overlay + its draggable node handles over `waveArea` for
|
||||
// `zone`'s play params, at the sample's wall-clock duration. Shared by the Sample hero band.
|
||||
@@ -177,11 +183,10 @@ private:
|
||||
std::int64_t frames);
|
||||
// S-VIEW-10: the velocity->amp transfer-curve editor — a bordered box (X = velocity 0-127,
|
||||
// Y = amp 0-1), the monotone spline traced by eval, one draggable node handle per control
|
||||
// point. Shared by the Sample face (beside the hero) and the Zone param panel; all mapping /
|
||||
// hit-test / clamp math lives in the pure velocity_curve module. `r` empty -> draws nothing.
|
||||
// drawCaption: false suppresses the "Vel curve" corner label (the popup draws its own title).
|
||||
void paintVelocityCurve(LICE_IBitmap* bmp, const Rect& r, const PerformanceZone& zone,
|
||||
bool drawCaption = true);
|
||||
// point. Since FB2 its ONLY host is the r11 popup sheet (both surfaces summon it via the
|
||||
// mini preview button); all mapping / hit-test / clamp math lives in the pure
|
||||
// velocity_curve module. `r` empty -> draws nothing.
|
||||
void paintVelocityCurve(LICE_IBitmap* bmp, const Rect& r, const PerformanceZone& zone);
|
||||
|
||||
// Route a mouse-down inside curve-editor box `r` editing map_.zones[zoneIndex]: a node grab
|
||||
// starts a kCurveNode drag; Alt-click on an interior node deletes it (committed at once);
|
||||
@@ -189,23 +194,25 @@ private:
|
||||
// `zoneIndex` must be a valid index into map_.zones (callers materialize first).
|
||||
void handleCurveMouseDown(const Rect& r, int zoneIndex, int x, int y);
|
||||
|
||||
// Route a left-click while the curve popup is open (the popup is MODAL over the Sample
|
||||
// face AND the Zone surface, FB2): Close / outside-wash dismiss, in-box clicks into the
|
||||
// shared curve machinery against popupZoneIndex(), everything else on the sheet swallowed.
|
||||
// Returns true when the popup consumed the click (i.e. whenever it is open).
|
||||
bool handlePopupMouseDown(int w, int h, int x, int y);
|
||||
|
||||
void onMouseDown(int x, int y);
|
||||
void onMouseMove(int x, int y);
|
||||
void onMouseUp(int x, int y);
|
||||
// r11: right-click — the curve popup's PRIMARY node-delete affordance (issue 3c). Only
|
||||
// acts while the popup is open; a right-click on a popup curve node deletes it through
|
||||
// the same commit path as Alt-click (deletePoint's endpoint guard makes endpoint
|
||||
// right-clicks a safe no-op). Everything else ignores right-clicks.
|
||||
// acts while the popup is open (over the Sample face OR the Zone surface, FB2); a
|
||||
// right-click on a popup curve node deletes it through the same commit path as Alt-click
|
||||
// (deletePoint's endpoint guard makes endpoint right-clicks a safe no-op). Everything
|
||||
// else ignores right-clicks.
|
||||
void onMouseRDown(int x, int y);
|
||||
|
||||
// Route a click at (x,y) into the param control panel `panel` editing map_.zones[zoneIndex]:
|
||||
// a toggle segment commits immediately, a slider grab starts a live param-drag (kParamSlider),
|
||||
// the keyTrack slider likewise (against the zone's keyTrack scalar). Returns true when the
|
||||
// click landed on a control (handled). `zoneIndex` must be a valid index into map_.zones.
|
||||
bool handleControlClick(int zoneIndex, const Rect& panel, int x, int y);
|
||||
// Apply a slider/toggle interaction to map_.zones[zoneIndex] for control `id`: routes ordinary
|
||||
// Apply a knob/toggle interaction to map_.zones[zoneIndex] for control `id`: routes ordinary
|
||||
// controls through applyControl against the zone's play struct, and kKeyTrack against the
|
||||
// zone's keyTrack scalar (0..200% over the slider's 0..1). Used by both the click + drag paths.
|
||||
// zone's keyTrack scalar (0..200% over the knob's 0..1). Used by both the click + drag paths.
|
||||
void applyZoneControl(int zoneIndex, int id, double value, int segment);
|
||||
|
||||
// Resolve the interactive element under (x, y) into hover_ (Phase L, L3). Called from
|
||||
@@ -296,24 +303,18 @@ private:
|
||||
// (0-based) that was updated or appended, so callers can set selectedZone_.
|
||||
int upsertPickedOverride(const SetupMarkers& m);
|
||||
|
||||
// --- S12/S15/S16 parameter surface (Zones panel, keyed to selectedZone_) ------
|
||||
// --- S12/S15/S16 parameter value domains (both deck surfaces) ------------------
|
||||
//
|
||||
// The control panel edits the SELECTED zone's ZonePlaySeconds (S15 play mode + AHDSR; S16
|
||||
// pitch engine + AD pitch envelope). Wall-clock times are SECONDS (rate-free); the keymap
|
||||
// build resolves them to frames at the live rate. 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 ZonePlaySeconds& play) const;
|
||||
// The deck knobs edit a zone's ZonePlaySeconds (S15 play mode + AHDSR; S16 pitch engine +
|
||||
// AD pitch envelope). Wall-clock times are SECONDS (rate-free); the keymap build resolves
|
||||
// them to frames at the live rate. Instrument-owned (D-B), never a bank fact.
|
||||
|
||||
// The normalized [0,1] display value for control `id` given `play` (the shell's domain
|
||||
// mapping: seconds->0..1 over a fixed seconds ceiling, sustain 0..1 as-is, %-length/fade
|
||||
// frames->0..1, semitone depth centered at 0.5).
|
||||
double controlValue(int id, const ZonePlaySeconds& play) const;
|
||||
|
||||
// Apply a committed control interaction to `play`: a slider's normalized `value` (mapped back
|
||||
// Apply a committed control interaction to `play`: a knob's normalized `value` (mapped back
|
||||
// into the control's stored domain) or a toggle's `segment` (0/1). Mutates `play` in place.
|
||||
void applyControl(int id, ZonePlaySeconds& play, double value, int segment) const;
|
||||
|
||||
@@ -364,18 +365,31 @@ private:
|
||||
// needs a concrete zone to write. Returns -1 if selectedId_ is empty.
|
||||
int ensureSampleZone();
|
||||
|
||||
// --- r11 knob-deck plumbing (FB1) ---------------------------------------------
|
||||
// --- Curve-popup target resolution (r11 FB1 + FB2) -----------------------------
|
||||
//
|
||||
// The deck is the r11 replacement for the Sample face's slider control strip: the pure
|
||||
// knob_deck module lays out the fenced groups, param_slider's FA4 primitive owns the
|
||||
// value<->needle map, and these members own the control-id <-> value binding (the same
|
||||
// division of labor paintControls/applyControl use for the Zone surface's sliders).
|
||||
// The popup edits ONE zone per open: the Zone surface's SELECTED zone (FB2) or the Sample
|
||||
// face's picked one-zone site. popupZone is the read-only resolve (paint/hover/right-click
|
||||
// hit-test); popupZoneIndex is the edit target — it materializes the Sample-face zone via
|
||||
// ensureSampleZone but NEVER materializes on the Zone surface (the button only shows for
|
||||
// an explicit selection). Returns -1 when there is no valid target (callers guard).
|
||||
PerformanceZone popupZone() const;
|
||||
int popupZoneIndex();
|
||||
|
||||
// The deck group descriptors for the current mode: AMP ENVELOPE (Gate: A/H/D/S/R;
|
||||
// Trigger: Fade In / Length % / Fade Out + two RESERVED blanks so a mode flip never
|
||||
// reflows the neighbours) / PITCH (Key Track) / PITCH ENV (P.Attack/P.Decay/P.Depth) /
|
||||
// VOICE (Voices knob + Poly|Mono caption toggle + Retrig|Legato row toggle) / MASTER
|
||||
// (the FB1 post-mixer Gain knob).
|
||||
// --- r11 knob-deck plumbing (FB1 Sample face; FB2 Zone panel) -------------------
|
||||
//
|
||||
// The deck is the r11 replacement for the slider control strips on BOTH surfaces: the pure
|
||||
// knob_deck module lays out the fenced groups, param_slider's FA4 primitive owns the
|
||||
// value<->needle map, and these members own the control-id <-> value binding.
|
||||
|
||||
// The PER-ZONE deck groups (FB2 — the set both surfaces share): AMP ENVELOPE (Gate:
|
||||
// A/H/D/S/R; Trigger: Fade In / Length % / Fade Out + two RESERVED blanks so a mode flip
|
||||
// never reflows the neighbours) / PITCH (Key Track) / PITCH ENV (P.Attack/P.Decay/P.Depth).
|
||||
// The Zone panel renders exactly these — per-instance state stays off it.
|
||||
std::vector<DeckGroupDesc> zoneDeckGroupDescs(const ZonePlaySeconds& play) const;
|
||||
|
||||
// The full Sample-face deck: the shared per-zone groups + the per-instance VOICE (Voices
|
||||
// knob + Poly|Mono caption toggle + Retrig|Legato row toggle) and MASTER (the FB1
|
||||
// post-mixer Gain knob) groups.
|
||||
std::vector<DeckGroupDesc> deckGroupDescs(const ZonePlaySeconds& play) const;
|
||||
|
||||
// The normalized [0,1] value a deck knob shows for `zone` — zone params route through
|
||||
@@ -480,12 +494,10 @@ private:
|
||||
std::int64_t dragStartFrame_ = 0; // zone startPoint at grab time (0 if absent); for env-node 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).
|
||||
// from it). kDeckKnob drag: which control id + the zone it edits.
|
||||
int dragStartScrollOffset_ = 0;
|
||||
int dragParamId_ = -1; // ControlDesc id under a kParamSlider drag; -2 = preview-vel knob
|
||||
int dragParamZone_ = -1; // the zone index a kParamSlider drag edits (Sample or Zone face)
|
||||
Rect dragParamPanel_{};
|
||||
int dragParamId_ = -1; // control id under a kDeckKnob drag; -2 = preview-vel knob
|
||||
int dragParamZone_ = -1; // the zone index a kDeckKnob drag edits; -1 = processor-side
|
||||
|
||||
// S-VIEW-3 envelope-node drag: which node is grabbed + the AmpEnvelope snapshotted at grab
|
||||
// (so the pixel delta is absolute, per envelope_edit's grabEnv contract). The overlay rect +
|
||||
@@ -506,9 +518,10 @@ private:
|
||||
// the vertical pixel delta from this anchor, so a grab never jumps the value (FA4).
|
||||
double dragKnobStartValue_ = 0.0;
|
||||
|
||||
// r11 curve popup (FB1): open flag — editor-local, never persisted. The popup edits the
|
||||
// picked capture's one-zone site (effectiveSampleZone / ensureSampleZone), re-resolved
|
||||
// each paint so a sync-tick refresh mid-open stays coherent.
|
||||
// r11 curve popup (FB1 + FB2): open flag — editor-local, never persisted. The popup edits
|
||||
// popupZone() — the picked capture's one-zone site on the Sample face, the SELECTED zone
|
||||
// on the Zone surface — re-resolved each paint so a sync-tick refresh mid-open stays
|
||||
// coherent (a refresh that drops the target closes it; see refreshFromBank).
|
||||
bool curvePopupOpen_ = false;
|
||||
|
||||
// --- Peak-thumbnail cache (mirror of bank_panel; id -> envelope at a bin width) ------
|
||||
|
||||
Reference in New Issue
Block a user