loop: crossfade the Gate sustain seam, and unshadow the loop handles that made loop points look gone

This commit is contained in:
2026-07-31 17:36:36 -04:00
parent a90ccd9a00
commit 0fe4166d7d
25 changed files with 991 additions and 64 deletions
+12
View File
@@ -67,6 +67,18 @@ std::int64_t xToFrame(const OverlayArea& area, std::int64_t frameCount, int x) {
return clampFrame(num / static_cast<std::int64_t>(w), frameCount);
}
Rect markerHandleRect(const OverlayArea& area, std::int64_t frameCount, std::int64_t frame) {
const Rect& r = area.rect;
if (r.empty()) return Rect{};
const int mx = frameToX(area, frameCount, frame);
// Clip into the area: a marker at the last frame maps to right(), whose unclipped tab
// would claim pixels outside the band the caller already hit-tested.
const int left = std::max(r.x, mx - kMarkerHandleHalfWidth);
const int right = std::min(r.right(), mx + kMarkerHandleHalfWidth + 1);
if (right <= left) return Rect{};
return Rect{left, r.y, right - left, std::min(kMarkerHandleHeight, r.height)};
}
int markerAtPoint(const OverlayArea& area, std::int64_t frameCount, const std::int64_t* frames,
int count, int x, int y) {
if (count <= 0 || frames == nullptr) return -1;
+9
View File
@@ -65,6 +65,15 @@ int frameToX(const OverlayArea& area, std::int64_t frameCount, std::int64_t fram
// area.x yields 0; right of area.right() yields frameCount.
std::int64_t xToFrame(const OverlayArea& area, std::int64_t frameCount, int x);
// A marker's grab HANDLE: a tab riding the top of the overlay, centred on the marker's x and
// clipped into the area. Distinct from the full-height grab COLUMN markerAtPoint answers, so
// two markers that share a frame stay independently grabbable — the handle owns the top
// strip, the column owns everything below it. Without that split, first-in-draw-order wins
// every coincident tie and the loser can never be dragged apart again.
inline constexpr int kMarkerHandleHeight = 10;
inline constexpr int kMarkerHandleHalfWidth = 5;
Rect markerHandleRect(const OverlayArea& area, std::int64_t frameCount, std::int64_t frame);
// Which marker (index into the caller's parallel `frames` array, in draw order) a grab at
// (x, y) lands on, or -1 for a miss. A marker is grabbed when x is within kMarkerGrabWidth of
// its drawn x and y is inside `area`. First marker in draw order wins an overlapping tie.