Ψ-W1-T4: resolve drop targets per move, not once — every surface gets a defined outcome, a cue, and no silent no-op

This commit is contained in:
2026-08-01 19:43:37 -04:00
parent 8bf6841f7b
commit fe3ac79ab5
17 changed files with 842 additions and 398 deletions
+39 -8
View File
@@ -15,14 +15,45 @@ bool insideClient(int px, int py, const PanelClientRect& c) {
} // namespace
DragGesture decideGesture(int px, int py, const PanelClientRect& client,
const DragState& state) {
if (!state.dragging || !state.hasArmedSamples) return DragGesture::None;
if (insideClient(px, py, client)) return DragGesture::Internal;
// Outside the client: a single-capture drag still over REAPER's own UI is an instrument
// drop; anything else (multi-capture, or pointer off REAPER entirely) is an OS drag-out.
if (state.singleCapture && state.overReaperUi) return DragGesture::InstrumentDrop;
return DragGesture::OsDrag;
DropClass decideDropClass(int px, int py, const PanelClientRect& client,
const DropContext& ctx) {
if (!ctx.drag.dragging || !ctx.drag.hasArmedSamples) return DropClass::None;
if (insideClient(px, py, client)) return DropClass::Internal;
switch (ctx.surface) {
case ReaperSurface::OffReaper:
return DropClass::OsHandoff;
case ReaperSurface::TrackPanel:
case ReaperSurface::FxSurface:
// One instance holds one capture, so a multi payload names no instrument to build —
// it refuses with a cue rather than falling through to some other surface's outcome.
return (ctx.singlePayload && ctx.haveTrack) ? DropClass::InstrumentDrop
: DropClass::Refuse;
case ReaperSurface::Arrange:
// GetThingFromPoint may return a null track with a valid info string (the SDK says
// so): over the arrange that is the region below the last track, which names no lane
// to place on. Refuse rather than guess a track.
return ctx.haveTrack ? DropClass::ArrangeInsert : DropClass::Refuse;
case ReaperSurface::FxEmbed:
case ReaperSurface::Other:
return DropClass::Refuse;
}
return DropClass::Refuse; // an unclassifiable surface still refuses visibly, never silently
}
DropCue cueForDropClass(DropClass cls) {
switch (cls) {
case DropClass::Internal: return DropCue::Internal;
case DropClass::InstrumentDrop: return DropCue::Instrument;
case DropClass::ArrangeInsert: return DropCue::ArrangeInsert;
case DropClass::Refuse: return DropCue::Refuse;
case DropClass::OsHandoff: return DropCue::OsOwned;
case DropClass::None: return DropCue::None;
}
return DropCue::None;
}
PathList assemblePathList(const std::vector<ResolvedSample>& resolved) {