deck: filter mod moves to FILTER ENV, cell runs centre in their reserves, two-segment toggles become single buttons, deck focuses its overlay
This commit is contained in:
@@ -29,10 +29,18 @@ bool ReaSamplerEditor::mouseDownDeck(const FaceLayout& fl, int x, int y) {
|
||||
|
||||
const DeckLayout dl = layoutDeck(fl.deckDescs, band.x, band.y, band.width);
|
||||
const DeckHit hit = hitTestDeck(dl, x, y);
|
||||
if (hit.kind == DeckHitKind::CaptionRadio) {
|
||||
overlayEnv_ = nextOverlaySelection(overlayEnv_, hit.id);
|
||||
invalidate(); // view state only: no parameter write, no reload
|
||||
return true;
|
||||
// The deck IS the overlay's click target: anywhere inside an envelope group — panel
|
||||
// background, knob or button — focuses that envelope, and any other group clears it. Set
|
||||
// BEFORE the kind switch and it consumes nothing, so every grab and commit below still
|
||||
// runs. A drag in flight owns the surface, so it refuses the change.
|
||||
// Repaints HERE rather than leaning on the branches below: a click on a group's bare
|
||||
// padding, or on an inert knob, changes the focus and reaches no other invalidate.
|
||||
if (drag_ == DragKind::kNone) {
|
||||
const OverlayEnv focus = overlayEnvForGroup(hit.group);
|
||||
if (focus != overlayEnv_) {
|
||||
overlayEnv_ = focus;
|
||||
invalidate(); // view state only: no parameter write, no reload
|
||||
}
|
||||
}
|
||||
if (hit.kind == DeckHitKind::CaptionToggle || hit.kind == DeckHitKind::RowToggle) {
|
||||
switch (static_cast<ParamControl>(hit.id)) {
|
||||
@@ -65,29 +73,29 @@ bool ReaSamplerEditor::mouseDownDeck(const FaceLayout& fl, int x, int y) {
|
||||
commitAndReload();
|
||||
break;
|
||||
case ParamControl::kLimiterEnable: {
|
||||
const bool on = (hit.segment == 1);
|
||||
if (on != params_.limiterEnabled) {
|
||||
params_.limiterEnabled = on;
|
||||
// Commits the audible state and the persisted state together, here, because
|
||||
// this is a control the user A/Bs. The funnel only ARMS the host's latency
|
||||
// restart — the sync tick delivers it — so nothing on this path calls into
|
||||
// the host from inside a mouse handler.
|
||||
processor_->setLimiterEnabled(on);
|
||||
}
|
||||
// One button, so its next state is the opposite of the current one — which is
|
||||
// also why the old "did it actually change" guard is gone: it always does.
|
||||
const bool on = !params_.limiterEnabled;
|
||||
params_.limiterEnabled = on;
|
||||
// Commits the audible state and the persisted state together, here, because
|
||||
// this is a control the user A/Bs. The funnel only ARMS the host's latency
|
||||
// restart — the sync tick delivers it — so nothing on this path calls into
|
||||
// the host from inside a mouse handler.
|
||||
processor_->setLimiterEnabled(on);
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Parameter-set toggles (play mode / pitch engine / pitch-env + filter enable,
|
||||
// and the three env-mode toggles).
|
||||
applyParamControl(hit.id, 0.0, hit.segment);
|
||||
// and the three env-mode selectors). A single button carries no segment, so
|
||||
// its next state is derived from the parameter set rather than read off the
|
||||
// click — deck_values owns that derivation.
|
||||
const int segment =
|
||||
hit.segment >= 0
|
||||
? hit.segment
|
||||
: nextToggleSegment(static_cast<ParamControl>(hit.id), params_.play);
|
||||
applyParamControl(hit.id, 0.0, segment);
|
||||
commitAndReload();
|
||||
// Flipping an EG's Staged|Spline toggle makes THAT envelope's overlay active,
|
||||
// so the contour (or the staged shape you just returned to) is what's drawn.
|
||||
// overlayEnvForModeToggle answers kNone for every other toggle this default
|
||||
// case handles, which is why the assignment is conditional.
|
||||
const OverlayEnv modeEnv = overlayEnvForModeToggle(hit.id);
|
||||
if (modeEnv != OverlayEnv::kNone) overlayEnv_ = modeEnv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +223,6 @@ HoverTarget ReaSamplerEditor::hoverDeck(const FaceLayout& fl, int x,
|
||||
// The meter reports its own state continuously; a hover on it would only mean "the clip
|
||||
// cap is clearable", which the cap's presence already says.
|
||||
if (dh.kind == DeckHitKind::Column) return {};
|
||||
if (dh.kind == DeckHitKind::CaptionRadio) return {HoverKind::kEnvRadio, dh.id};
|
||||
if (dh.kind == DeckHitKind::Knob && dh.inner &&
|
||||
curveParamFor(static_cast<ParamControl>(dh.id)) != ParamControl::kCount) {
|
||||
// Indexed by the OUTER cell id so the paint side can find the cell it belongs to.
|
||||
|
||||
Reference in New Issue
Block a user