Retire the zone system: one capture = one parameter set, and re-seam the engine and Sample face into bands
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// editor_input.cpp — the ReaSamplerEditor's input dispatch and drag-state machine: the
|
||||
// mouse-down routing (curve popup first, then Browse or the three bands in order), the
|
||||
// onMouseMove drag router, the release commit, and the hover resolver. The per-band
|
||||
// branches live in the editor_input_<band> TUs; this TU only sequences them.
|
||||
// Windows-only. All hit-test math is pure; this family routes and mutates editor state.
|
||||
|
||||
#include "shell/instrument/reasampler_editor.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "shell/instrument/editor_internal.h" // curveBoxFromRect + kCurveDragOffMargin
|
||||
#include "shell/instrument/reasampler_processor.h"
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
using namespace reasampler::ui;
|
||||
using namespace reasampler::instrument::ui;
|
||||
|
||||
void ReaSamplerEditor::onMouseDown(int x, int y) {
|
||||
if (!processor_) return;
|
||||
RECT cr{};
|
||||
GetClientRect(childHwnd_, &cr);
|
||||
const int w = cr.right - cr.left;
|
||||
const int h = cr.bottom - cr.top;
|
||||
|
||||
if (view_ == View::kBrowse) {
|
||||
mouseDownBrowse(w, h, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
// The curve popup is modal over the face — while open it owns every left-click.
|
||||
if (handlePopupMouseDown(w, h, x, y)) return;
|
||||
|
||||
// Band order matters only where bands can overlap on a degenerate window; each branch
|
||||
// reports whether it consumed the click so the next band gets a clean shot.
|
||||
const FaceLayout fl = faceLayout(w, h);
|
||||
if (mouseDownChrome(fl, x, y)) return;
|
||||
if (selectedId_.empty()) return; // empty state — chrome nav only
|
||||
if (mouseDownDeck(fl, x, y)) return;
|
||||
mouseDownWaveform(fl, x, y);
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::onMouseMove(int x, int y) {
|
||||
if (drag_ == DragKind::kNone) return;
|
||||
dragCurX_ = x; // keep the live cursor position for drag-state draw cues (e.g. drag-off warn)
|
||||
dragCurY_ = y;
|
||||
|
||||
// The three band-free drags resolve without a layout pass at all.
|
||||
switch (drag_) {
|
||||
case DragKind::kDeckKnob: dragDeck(x, y); return;
|
||||
case DragKind::kScrollThumb: dragBrowse(x, y); return;
|
||||
case DragKind::kCurveNode: dragCurve(x, y); return;
|
||||
default: break;
|
||||
}
|
||||
|
||||
RECT rc{};
|
||||
GetClientRect(childHwnd_, &rc);
|
||||
const FaceLayout fl = faceLayout(rc.right - rc.left, rc.bottom - rc.top);
|
||||
if (drag_ == DragKind::kRootMarker) {
|
||||
dragChrome(fl, x, y);
|
||||
} else {
|
||||
dragWaveform(fl, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::onMouseUp(int x, int y) {
|
||||
// Release a held preview note first (the preview button is a momentary key: note-off on up).
|
||||
// This runs regardless of drag state — the preview press does not start a drag.
|
||||
if (previewingNote_ >= 0) {
|
||||
if (processor_) processor_->previewNoteOff(previewingNote_);
|
||||
previewingNote_ = -1;
|
||||
invalidate();
|
||||
}
|
||||
if (drag_ == DragKind::kNone) return;
|
||||
const DragKind kind = drag_;
|
||||
const int paramId = dragParamId_;
|
||||
const int curveIdx = curvePointIndex_;
|
||||
const Rect curveRect = dragCurveRect_;
|
||||
drag_ = DragKind::kNone;
|
||||
dragParamId_ = -1;
|
||||
curvePointIndex_ = -1;
|
||||
// A scrollbar drag is transient UI (no parameter change), and the processor-side knobs
|
||||
// (the preview-velocity -2 sentinel, voice count, master gain) are per-instance settings
|
||||
// that don't reload the instrument. Master gain is an atomic the audio thread reads
|
||||
// directly. Voice count: the label/needle tracks live during the drag but the engine
|
||||
// rebuild (setVoiceCount) fires ONCE here on release — not per integer step.
|
||||
const bool deckTransient =
|
||||
kind == DragKind::kDeckKnob &&
|
||||
(paramId == -2 || paramId == static_cast<int>(ParamControl::kVoiceCount) ||
|
||||
paramId == static_cast<int>(ParamControl::kMasterGain));
|
||||
if (kind == DragKind::kScrollThumb || deckTransient) {
|
||||
// Commit the voice count now that the drag is complete (one rebuild per full drag).
|
||||
if (deckTransient && processor_ &&
|
||||
paramId == static_cast<int>(ParamControl::kVoiceCount))
|
||||
processor_->setVoiceCount(voiceCount_);
|
||||
invalidate();
|
||||
return;
|
||||
}
|
||||
// Drag-off delete: releasing a curve-node drag well outside the box removes the dragged
|
||||
// point (deletePoint refuses the two endpoints, so an endpoint drag-off is a plain move —
|
||||
// its amp keeps the last clamped drag value).
|
||||
if (kind == DragKind::kCurveNode && curveIdx >= 0) {
|
||||
const bool off = x < curveRect.x - kCurveDragOffMargin ||
|
||||
x > curveRect.right() + kCurveDragOffMargin ||
|
||||
y < curveRect.y - kCurveDragOffMargin ||
|
||||
y > curveRect.bottom() + kCurveDragOffMargin;
|
||||
if (off) {
|
||||
params_.velocityCurve.deletePoint(static_cast<std::size_t>(curveIdx));
|
||||
hover_ = HoverTarget{}; // stale kCurveNode index would light a shifted node
|
||||
}
|
||||
}
|
||||
commitAndReload();
|
||||
}
|
||||
|
||||
// Resolve the interactive element under (x, y) into hover_ and repaint only on change (an
|
||||
// idle move is free). Mirrors onMouseDown's routing order, but read-only.
|
||||
void ReaSamplerEditor::resolveHover(int x, int y) {
|
||||
RECT cr{};
|
||||
GetClientRect(childHwnd_, &cr);
|
||||
const int w = cr.right - cr.left;
|
||||
const int hgt = cr.bottom - cr.top;
|
||||
|
||||
HoverTarget h; // kNone by default
|
||||
if (view_ == View::kBrowse) {
|
||||
h = hoverBrowse(w, hgt, x, y);
|
||||
} else if (curvePopupOpen_) { // modal over the face
|
||||
h = hoverCurvePopup(w, hgt, x, y);
|
||||
} else {
|
||||
const FaceLayout fl = faceLayout(w, hgt);
|
||||
h = hoverChrome(fl, x, y);
|
||||
if (h.kind == HoverKind::kNone && !selectedId_.empty()) h = hoverDeck(fl, x, y);
|
||||
}
|
||||
|
||||
if (h != hover_) {
|
||||
hover_ = h;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace reasampler::vst
|
||||
|
||||
#endif // _WIN32
|
||||
Reference in New Issue
Block a user