Q-W1 pt2: core/shell/app relocation + sub-namespaces; one concrete ui::Rect (LTRB fork retired); slot_map split from bank_book; BankIndex→BankModel; 59/59 green

This commit is contained in:
2026-07-28 20:48:56 -04:00
parent 67a41728f3
commit 847936f813
222 changed files with 2247 additions and 2079 deletions
+17 -16
View File
@@ -1,4 +1,4 @@
// Standalone tests for reasampler::vst::envelope_edit — no VST3, no REAPER, no framework.
// Standalone tests for reasampler::instrument::ui::envelope_edit — no VST3, no REAPER, no framework.
// Same fast assert loop as the sibling pure tests. Assert the S-VIEW-3 draggable-node INVERSE
// map: node hit-test + pixel-delta -> clamped/monotonic param set, HARD at the clamp + monotonic
// boundaries (the load-bearing "a drag can never produce a param a slider couldn't" invariant).
@@ -14,14 +14,15 @@
// pixel delta; zero-fade-out node grabbable at the right edge and draggable inward — FA2);
// degenerate area/duration + non-draggable node + cross-mode node -> no motion.
#include "../src/vst/envelope_edit.h"
#include "../src/core/instrument/ui/envelope_edit.h"
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <vector>
using namespace reasampler::vst;
using namespace reasampler;
using namespace reasampler::instrument::ui;
static int g_fail = 0;
#define CHECK(cond) do { if(!(cond)) { \
@@ -41,7 +42,7 @@ static bool findNode(const std::vector<EnvVertex>& poly, EnvNode node, EnvVertex
// scale (FA2 param-domain schematic — sample-length-free): (850-1-32)px over the 8.0s schematic
// domain => 102.125 px/s, each segment prefixed by the 8px separation base; the gateEnv() nodes
// draw at A x@28, H x@47, D x@85, RS x@235, RE x@284.
static Rect wideArea() { return Rect{20, 10, 1020, 110}; }
static Rect wideArea() { return Rect::ltrb(20, 10, 1020, 110); }
static constexpr double kTotal = 2.0;
static const double kGateSecPerPx = 1.0 / gatePxPerSecond(wideArea());
@@ -71,10 +72,10 @@ static void testHitGrabsDrawnHandle() {
const AmpEnvelope e = gateEnv();
const Rect a = wideArea();
// AttackEnd draws at x = left+28 (8px base + 0.2s * 102.125 px/s), y = top (level 1).
NodeHit h = nodeAtPoint(e, a, kTotal, a.left + 28, a.top);
NodeHit h = nodeAtPoint(e, a, kTotal, a.x + 28, a.y);
CHECK(h.hit && h.node == EnvNode::AttackEnd);
// The sustain node (DecayEnd) at left+85, level 0.5 -> ~top+50.
NodeHit s = nodeAtPoint(e, a, kTotal, a.left + 85, a.top + 50);
NodeHit s = nodeAtPoint(e, a, kTotal, a.x + 85, a.y + 50);
CHECK(s.hit && s.node == EnvNode::DecayEnd);
}
@@ -82,7 +83,7 @@ static void testHitMissesOffEveryNode() {
const AmpEnvelope e = gateEnv();
const Rect a = wideArea();
// A point far from any drawn handle (right of the release ramp, well away from a node).
NodeHit h = nodeAtPoint(e, a, kTotal, a.left + 700, a.top + 5);
NodeHit h = nodeAtPoint(e, a, kTotal, a.x + 700, a.y + 5);
CHECK(!h.hit);
}
@@ -90,11 +91,11 @@ static void testHitSkipsNonDraggableAnchors() {
const AmpEnvelope e = gateEnv();
const Rect a = wideArea();
// Origin draws at (left, bottom-1). Even a pixel-perfect grab there is NOT a draggable node.
NodeHit o = nodeAtPoint(e, a, kTotal, a.left, a.bottom - 1);
NodeHit o = nodeAtPoint(e, a, kTotal, a.x, a.bottom() - 1);
CHECK(!o.hit);
// ReleaseStart draws at (left+235, sustain level ~top+50) — the fixed plateau end. It is
// drawing-only -> not grabbable; no other node is within the radius, so this grab misses.
NodeHit rs = nodeAtPoint(e, a, kTotal, a.left + 235, a.top + 50);
NodeHit rs = nodeAtPoint(e, a, kTotal, a.x + 235, a.y + 50);
CHECK(!rs.hit);
}
@@ -106,7 +107,7 @@ static void testHitNearestNodeWinsOverDrawOrder() {
AmpEnvelope e = gateEnv();
e.holdSeconds = 0.01;
const Rect a = wideArea();
NodeHit h = nodeAtPoint(e, a, kTotal, a.left + 33, a.top);
NodeHit h = nodeAtPoint(e, a, kTotal, a.x + 33, a.y);
CHECK(h.hit && h.node == EnvNode::HoldEnd);
}
@@ -199,11 +200,11 @@ static void testGateTimeOnlyNodeIgnoresY() {
static void testGateReleaseEndGrabAndDrag() {
// The FA2 fix: ReleaseEnd is a drawn, IN-BOUNDS, grabbable handle (pre-FA2 it mapped past
// area.right and could never be grabbed). gateEnv() draws it at x@284, level 0 (bottom row).
// area.right() and could never be grabbed). gateEnv() draws it at x@284, level 0 (bottom row).
const AmpEnvelope e = gateEnv();
const Rect a = wideArea();
EnvClampBounds b;
NodeHit h = nodeAtPoint(e, a, kTotal, a.left + 284, a.bottom - 1);
NodeHit h = nodeAtPoint(e, a, kTotal, a.x + 284, a.bottom() - 1);
CHECK(h.hit && h.node == EnvNode::ReleaseEnd);
// Dragging it RIGHT lengthens the release at the gate timed scale; only release changes.
AmpEnvelope out = resolveNodeDrag(e, EnvNode::ReleaseEnd, a, kTotal, b, 85, 0);
@@ -289,14 +290,14 @@ static void testTriggerZeroFadeOutGrabbableAtRightEdge() {
e.fadeOutFraction = 0.0;
const Rect a = wideArea();
EnvClampBounds b;
NodeHit h = nodeAtPoint(e, a, kTotal, a.right - 1, a.top);
NodeHit h = nodeAtPoint(e, a, kTotal, a.right() - 1, a.y);
CHECK(h.hit && h.node == EnvNode::FadeOutStart);
// -100px = -0.2s on the 2.0s played span, applied OPPOSITE -> fadeOut 0.0 -> 0.1.
AmpEnvelope out = resolveNodeDrag(e, EnvNode::FadeOutStart, a, kTotal, b, -100, 0);
CHECK(near(out.fadeOutFraction, 0.1));
CHECK(near(out.lengthFraction, e.lengthFraction)); // length untouched
// LengthEnd sits at the same x but level 0 (bottom row) — grabbable at ITS drawn point.
NodeHit le = nodeAtPoint(e, a, kTotal, a.right - 1, a.bottom - 1);
NodeHit le = nodeAtPoint(e, a, kTotal, a.right() - 1, a.bottom() - 1);
CHECK(le.hit && le.node == EnvNode::LengthEnd);
}
@@ -327,7 +328,7 @@ static void testNonDraggableNodeNoMotion() {
static void testDegenerateAreaNoMotion() {
const AmpEnvelope e = gateEnv();
EnvClampBounds b;
const Rect zeroW = Rect{0, 0, 0, 100};
const Rect zeroW = Rect::ltrb(0, 0, 0, 100);
AmpEnvelope o1 = resolveNodeDrag(e, EnvNode::AttackEnd, zeroW, kTotal, b, 500, 0);
CHECK(near(o1.attackSeconds, e.attackSeconds));
AmpEnvelope o2 = resolveNodeDrag(e, EnvNode::AttackEnd, wideArea(), 0.0, b, 500, 0); // no time
@@ -347,7 +348,7 @@ static void testCrossModeNodeNoMotion() {
out = resolveNodeDrag(g, EnvNode::FadeInEnd, wideArea(), kTotal, b, 50, 0);
CHECK(near(out.fadeInFraction, g.fadeInFraction));
// And the zero-height baseline's ReleaseEnd is not even reported grabbable in Trigger mode.
const Rect flat = Rect{0, 0, 100, 0};
const Rect flat = Rect::ltrb(0, 0, 100, 0);
const NodeHit h = nodeAtPoint(t, flat, kTotal, 99, 0);
CHECK(!h.hit);
}