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,125 @@
|
||||
// editor_paint_curve.cpp — the velocity->amp curve surfaces: the chrome band's mini
|
||||
// preview button and the modal popup sheet that hosts the full editor. Band-independent
|
||||
// (the popup floats over the whole face). Windows-only.
|
||||
|
||||
#include "shell/instrument/reasampler_editor.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "core/instrument/ui/curve_popup.h" // centered curve-popup sheet geometry
|
||||
#include "shell/instrument/editor_internal.h" // kit adapters + curveBoxFromRect
|
||||
#include "shell/instrument/reasampler_processor.h"
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
using namespace reasampler::ui; // kit vocabulary
|
||||
using namespace reasampler::instrument::ui; // popup geometry
|
||||
|
||||
void ReaSamplerEditor::paintCurveButton(LICE_IBitmap* bmp, const Rect& r) {
|
||||
if (r.width <= 0 || r.height <= 0) return;
|
||||
// A hairline-bordered bg/cell square with the live velocity curve traced in miniature
|
||||
// (no node markers at this scale). Hover lifts it; it draws Active (accent-primary
|
||||
// border) while its popup is open, and re-renders live as the popup edits the curve.
|
||||
const bool hov = isHovered(HoverKind::kCurveButton, -1);
|
||||
fillSurface(bmp, toKitBox(r), Role::BgCell,
|
||||
hov ? InteractionState::Hover : InteractionState::Rest);
|
||||
const KitColor border = curvePopupOpen_ ? roleColor(Role::AccentPrimary)
|
||||
: roleColor(Role::LineHairline);
|
||||
LICE_DrawRect(bmp, r.x, r.y, r.width - 1, r.height - 1, toLice(border), 1.0f, 0);
|
||||
const VelocityCurve& curve = params_.velocityCurve;
|
||||
const int inset = 3;
|
||||
const VelocityCurve::Box mini{r.x + inset, r.y + inset, r.width - 2 * inset,
|
||||
r.height - 2 * inset};
|
||||
if (mini.width > 1 && mini.height > 1) {
|
||||
const LICE_pixel trace = toLice(roleColor(Role::AccentSecondary));
|
||||
int prevX = 0, prevY = 0;
|
||||
for (int px = 0; px <= mini.width; ++px) {
|
||||
const int mx = mini.left + px;
|
||||
const double vel = VelocityCurve::pointFromPixel(mini, mx, mini.top).velocity;
|
||||
const int my = VelocityCurve::pixelFromPoint(mini, {vel, curve.eval(vel)}).y;
|
||||
if (px > 0) LICE_Line(bmp, prevX, prevY, mx, my, trace, 1.0f, 0, true);
|
||||
prevX = mx;
|
||||
prevY = my;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::paintCurvePopup(LICE_IBitmap* bmp, int w, int h) {
|
||||
// The 0.50-alpha bg/base wash (lighter than Browse's 0.82 — a focused sub-editor; the
|
||||
// face stays legible behind it), then the centered sheet.
|
||||
LICE_FillRect(bmp, 0, 0, w, h, toLice(roleColor(Role::BgBase)), 0.50f, 0);
|
||||
const CurvePopupLayout pl = computeCurvePopup(w, h);
|
||||
fillSurface(bmp, toKitBox(pl.sheet), Role::BgPanel, InteractionState::Rest);
|
||||
LICE_DrawRect(bmp, pl.sheet.x, pl.sheet.y, pl.sheet.width - 1,
|
||||
pl.sheet.height - 1, toLice(roleColor(Role::LineHairline)), 1.0f, 0);
|
||||
kitText(bmp, pl.title, "VELOCITY -> AMP", Font::Micro, Role::TextDim);
|
||||
{
|
||||
const KitButtonBox box{toKitBox(pl.close)};
|
||||
const InteractionState st = isHovered(HoverKind::kPopupClose, -1)
|
||||
? InteractionState::Hover
|
||||
: InteractionState::Rest;
|
||||
drawButton(bmp, box, "x", st, /*warn=*/false);
|
||||
}
|
||||
// The full-size editor: one draw path + the one curveBoxFromRect mapping formula, so
|
||||
// trace/handles/drag-off cues cannot drift from the hit-test.
|
||||
paintVelocityCurve(bmp, pl.curveBox);
|
||||
}
|
||||
|
||||
void ReaSamplerEditor::paintVelocityCurve(LICE_IBitmap* bmp, const Rect& r) {
|
||||
if (r.width <= 0 || r.height <= 0) return; // defensive (degenerate rect)
|
||||
|
||||
// The bordered box: a panel surface + hairline border, drawn by palette role. No corner
|
||||
// caption — the popup sheet's own "VELOCITY -> AMP" title labels this context (the popup
|
||||
// is the only host).
|
||||
fillSurface(bmp, toKitBox(r), Role::BgPanel, InteractionState::Rest);
|
||||
LICE_DrawRect(bmp, r.x, r.y, r.width - 1, r.height - 1,
|
||||
toLice(roleColor(Role::LineHairline)), 1.0f, 0);
|
||||
|
||||
const VelocityCurve::Box box = curveBoxFromRect(r);
|
||||
if (box.width <= 0 || box.height <= 1) return;
|
||||
const VelocityCurve& curve = params_.velocityCurve;
|
||||
|
||||
// Trace the monotone spline — ONE eval per x column over the mapping box, in the categorical
|
||||
// secondary accent (the same grammar as the envelope trace over the waveform). The x ->
|
||||
// velocity and amp -> y mappings both go through the pure module so the trace, the node
|
||||
// handles, and the hit-test all share one coordinate system.
|
||||
const LICE_pixel line = toLice(roleColor(Role::AccentSecondary));
|
||||
int prevX = 0, prevY = 0;
|
||||
for (int px = 0; px <= box.width; ++px) {
|
||||
const int cx = box.left + px;
|
||||
const double vel = VelocityCurve::pointFromPixel(box, cx, box.top).velocity;
|
||||
const int cy = VelocityCurve::pixelFromPoint(box, {vel, curve.eval(vel)}).y;
|
||||
if (px > 0) LICE_Line(bmp, prevX, prevY, cx, cy, line, 1.0f, 0, true);
|
||||
prevX = cx;
|
||||
prevY = cy;
|
||||
}
|
||||
|
||||
// Draggable node handles (mirror of the envelope overlay's): accent-primary squares lifted
|
||||
// to accent-hot when grabbed or hovered, or warn when a drag-off delete is armed (cursor
|
||||
// has passed kCurveDragOffMargin outside the box — release will delete the node).
|
||||
const LICE_pixel handle = toLice(roleColor(Role::AccentPrimary));
|
||||
const LICE_pixel handleHot = toLice(roleColor(Role::AccentHot));
|
||||
const LICE_pixel handleWarn = toLice(roleColor(Role::Warn));
|
||||
// Drag-off check: during a kCurveNode drag on THIS box, is the live cursor beyond the margin?
|
||||
const bool dragOffArmed = (drag_ == DragKind::kCurveNode && dragCurveRect_.x == r.x &&
|
||||
dragCurveRect_.y == r.y) &&
|
||||
(dragCurX_ < r.x - kCurveDragOffMargin ||
|
||||
dragCurX_ > r.right() + kCurveDragOffMargin ||
|
||||
dragCurY_ < r.y - kCurveDragOffMargin ||
|
||||
dragCurY_ > r.bottom() + kCurveDragOffMargin);
|
||||
for (std::size_t i = 0; i < curve.points().size(); ++i) {
|
||||
const auto np = VelocityCurve::pixelFromPoint(box, curve.points()[i]);
|
||||
const bool grabbed = (drag_ == DragKind::kCurveNode &&
|
||||
curvePointIndex_ == static_cast<int>(i));
|
||||
const bool hot = grabbed || isHovered(HoverKind::kCurveNode, static_cast<int>(i));
|
||||
// A grabbed node in drag-off territory draws warn to signal "release will delete."
|
||||
const LICE_pixel col = (grabbed && dragOffArmed) ? handleWarn
|
||||
: (hot ? handleHot : handle);
|
||||
const int nr = 3;
|
||||
LICE_FillRect(bmp, np.x - nr, np.y - nr, 2 * nr, 2 * nr, col, 1.0f, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace reasampler::vst
|
||||
|
||||
#endif // _WIN32
|
||||
Reference in New Issue
Block a user