Files
reasampler/src/core/ui/drag_out.h
T

73 lines
3.6 KiB
C++

#pragma once
#include "core/ui/rect.h"
// drag_out — decision logic behind the bank_panel's native OS drag-out. OLE/SWELL initiation and
// the panel gesture hook stay in the shell (drag_out_win.* + shell/panel/panel_drag.cpp).
//
// Gesture boundary: the panel's own internal drag (press a selected cell, drop onto a pool/bank
// region or tab) lives entirely inside the panel client rect. The moment the pointer LEAVES that
// rect while a drag is armed with samples, the gesture becomes OS-bound — dragged out to another
// window/Explorer/DAW. A single-capture drag that leaves the rect but is still over REAPER's own
// UI is instead an InstrumentDrop (heading for a track's FX button); do not regress this boundary.
//
// Path-list assembly: turns armed sample ids into the absolute path list the OS drop carries
// (Windows CF_HDROP / macOS file-list pasteboard) — set algebra only; the shell resolves each id
// to its on-disk bank file. No temp files; copy-only is enforced at the OS layer (drag_out_win).
#include <string>
#include <vector>
namespace reasampler::ui {
// --- Gesture boundary ---------------------------------------------------------
// The panel's client rect, own client coords, top-left origin. Half-open: [x, x+width) x
// [y, y+height).
using PanelClientRect = Rect;
// Live drag state reduced to what the boundary decision needs. Pre-threshold "armed but not yet
// dragging" is not a drag for this decision.
struct DragState {
bool dragging = false; // threshold crossed; a drag is in progress
bool hasArmedSamples = false; // payload holds >= 1 sample id
bool singleCapture = false; // payload holds EXACTLY one sample (arms InstrumentDrop)
bool overReaperUi = false; // pointer is over REAPER's own UI (shell-supplied)
};
// What the shell should do with the drag given the current pointer position.
enum class DragGesture {
None, // no drag under way, or an empty payload
Internal, // dragging inside the panel — bank-to-bank move/copy
InstrumentDrop, // single-capture drag left the panel but is over REAPER's UI — shell
// hover-tracks the TCP FX button; on release adds a preloaded instance
OsDrag, // dragging with samples, pointer left REAPER entirely — hand to the OS
};
// Decides the gesture for a drag at pointer (px, py) over `client`, given `state`. Position-only
// + state-only (no hidden state), so re-entry back inside always returns Internal.
DragGesture decideGesture(int px, int py, const PanelClientRect& client,
const DragState& state);
// --- Path-list assembly -------------------------------------------------------
// One armed sample reduced to what path assembly needs: the shell-resolved absolute path (empty
// if unresolvable) and whether it exists on disk.
struct ResolvedSample {
std::string absolutePath;
bool fileExists = false;
};
// Outcome of assembling the drag's path list. An empty `paths` means nothing draggable — do not
// start a drag.
struct PathList {
std::vector<std::string> paths; // de-duped, existing files, first-seen order
int skippedMissing = 0; // resolved but file doesn't exist (stale index entry)
int skippedUnresolved = 0; // shell couldn't resolve a path at all
int skippedDuplicate = 0; // same absolute path seen more than once
};
// Assembles the drag path list from the resolved samples (selection order). Comparison is
// exact-string — the shell normalizes case/slashes upstream if it wants Windows-style dedup.
PathList assemblePathList(const std::vector<ResolvedSample>& resolved);
} // namespace reasampler::ui