Ψ-W1-T4 remediation: gate silent arrange drops, pin surface totality, hedge unverified SDK claims, close comment/exception-safety minors
This commit is contained in:
@@ -7,13 +7,24 @@
|
||||
// B. InsertMedia advances the edit cursor past the media it added. That advance IS the
|
||||
// multi-file layout: the cursor is deliberately not reset between files, so N captures
|
||||
// land end to end. If REAPER does not advance it, they stack at one position instead —
|
||||
// visible and one Ctrl-Z away, never silent.
|
||||
// visible and one Ctrl-Z away, never silent. insert.cpp does NOT share this assumption: it
|
||||
// resets the cursor before every track's insert specifically to stay independent of
|
||||
// cursor-advance behavior (insert.cpp:18-20, "this doesn't matter either way"). This call
|
||||
// site is the first in the tree to depend on it.
|
||||
// C. SnapToGrid honors the project's snap-enabled toggle. The header documents no
|
||||
// snap-enabled query for the arrange, so a drop taken with snapping OFF is the test that
|
||||
// settles it.
|
||||
// D. GetSet_ArrangeView2's one-pixel span [screenX, screenX+1) reads the time at that column.
|
||||
// The header documents only the all-zero span (screen_x_start==screen_x_end==0) as the
|
||||
// "whole view" special case; the per-column reading for any other span is inferred, not
|
||||
// documented.
|
||||
// E. InsertMedia's int return isn't SDK-documented; treated conservatively as 0=failure,
|
||||
// nonzero=success — performArrangeDrop counts only the latter.
|
||||
|
||||
#include "shell/actions/arrange_drop_win.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -43,8 +54,13 @@ using capture::InsertOptions;
|
||||
namespace {
|
||||
|
||||
// Selection snapshot/restore, so a drop leaves the user's track selection exactly as it found
|
||||
// it. Mirrors insert.cpp's pair; that TU belongs to the capture pillar and this one to the drag
|
||||
// chain, so they are kept separate rather than sharing a helper across the seam.
|
||||
// it. Mirrors insert.cpp's pair; kept separate here because insert.cpp sits in the capture
|
||||
// pillar, outside this track's surface fence — not a ruling that the two should never share a
|
||||
// helper, just not this track's call to make.
|
||||
//
|
||||
// CountSelectedTracks/GetSelectedTrack both skip the master track (SDK header), so a user with
|
||||
// the master selected loses that selection across the drop — pre-existing behavior inherited
|
||||
// from insert.cpp's identical pair, not fixed here.
|
||||
std::vector<MediaTrack*> snapshotSelectedTracks() {
|
||||
const int n = CountSelectedTracks(nullptr); // nullptr = active project
|
||||
std::vector<MediaTrack*> tracks;
|
||||
@@ -63,9 +79,11 @@ void restoreSelectedTracks(const std::vector<MediaTrack*>& tracks) {
|
||||
|
||||
double arrangeTimeAtScreenX(int screenX) {
|
||||
double start = 0.0, end = 0.0;
|
||||
// isSet=false reads the arrange times spanned by [screen_x_start, screen_x_end); a
|
||||
// one-pixel span therefore reads the time at that column. (The all-zero span is the SDK's
|
||||
// documented "whole view" form, which is why the span here must not be empty.)
|
||||
// isSet=false with a one-pixel span [screenX, screenX+1) is assumed to read the time at
|
||||
// that column — inferred, not documented (assumption D in the file header). The SDK's ONLY
|
||||
// documented special form is screen_x_start==screen_x_end==0 (both zero) for "the whole
|
||||
// arrange view's start/end time"; a zero-width span at a nonzero column (e.g. screenX,
|
||||
// screenX) is NOT that special case, so the +1 here is precautionary rather than required.
|
||||
GetSet_ArrangeView2(nullptr, false, screenX, screenX + 1, &start, &end);
|
||||
return start < 0.0 ? 0.0 : start;
|
||||
}
|
||||
@@ -87,18 +105,24 @@ int performArrangeDrop(MediaTrack* track, double time,
|
||||
|
||||
int inserted = 0;
|
||||
for (const std::string& path : absolutePaths) {
|
||||
// No cursor reset between files — see assumption B in the file header.
|
||||
InsertMedia(path.c_str(), mode);
|
||||
++inserted;
|
||||
// No cursor reset between files — see assumption B in the file header. InsertMedia's
|
||||
// return isn't SDK-documented (assumption E); treated conservatively as 0=failure, so a
|
||||
// REAPER-side refusal is reflected in the count and in the undo label, not silent.
|
||||
if (InsertMedia(path.c_str(), mode) != 0) ++inserted;
|
||||
}
|
||||
|
||||
// A fixed stack buffer, not std::string concatenation: the prior shape built the label with
|
||||
// std::to_string + `+` between the restore below and Undo_EndBlock2, so a bad_alloc there
|
||||
// would leave an unbalanced undo block open. snprintf here removes the allocation outright.
|
||||
char label[64];
|
||||
std::snprintf(label, sizeof(label), "ReaSampler: drop %d %s onto arrange", inserted,
|
||||
inserted == 1 ? "capture" : "captures");
|
||||
|
||||
restoreSelectedTracks(priorSelection);
|
||||
SetEditCurPos(priorCursor, /*moveview=*/false, /*seekplay=*/false);
|
||||
|
||||
// extraflags -1 = UNDO_STATE_ALL, matching the insert action's own block.
|
||||
const std::string label = "ReaSampler: drop " + std::to_string(inserted) +
|
||||
(inserted == 1 ? " capture" : " captures") + " onto arrange";
|
||||
Undo_EndBlock2(nullptr, label.c_str(), -1);
|
||||
Undo_EndBlock2(nullptr, label, -1);
|
||||
return inserted;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user