Cut shell/panel comment bloat ~47% (comments only, zero code change)
This commit is contained in:
+71
-112
@@ -1,18 +1,13 @@
|
||||
// panel_drag.cpp — the card-drag / hover state machine seam of the docked bank panel
|
||||
// (Q-W2 split of bank_panel.cpp; the T4-01 NEW seam; M11/L7/S17). Owns WM_MOUSEMOVE
|
||||
// (hover resolution + tooltip timing + the live drag), the drop-target/gesture
|
||||
// classification, the cursor cues, button-up drop dispatch (reorder / replace /
|
||||
// move / copy / instrument-drop / OS drag-out), and right-click menu routing. Its
|
||||
// PURE mirror is core/ui/card_drag (gesture precedence + slot hit-test) with
|
||||
// core/ui/drag_out owning the OS-drag boundary decision — this shell supplies only
|
||||
// the live rects, modifier state, and side effects.
|
||||
//
|
||||
// PER-MOUSE-MOVE GUARDRAIL (T4-28): everything on the move path stays plain
|
||||
// panel_drag.cpp — the card-drag / hover state machine seam of the docked bank panel:
|
||||
// WM_MOUSEMOVE (hover + tooltip timing + the live drag), drop-target/gesture
|
||||
// classification, cursor cues, button-up drop dispatch, and right-click menu routing.
|
||||
// Its PURE mirror is core/ui/card_drag (gesture precedence + slot hit-test), with
|
||||
// core/ui/drag_out owning the OS-drag boundary decision — this shell supplies only the
|
||||
// live rects, modifier state, and side effects. Per-mouse-move work stays plain
|
||||
// free-function calls — no interface, no virtual dispatch.
|
||||
//
|
||||
// Compiled into the reaper_reasampler MODULE. No REAPER API functions are called
|
||||
// directly here (the FX-hotspot / OS-drag / instrument-drop shells own theirs);
|
||||
// REAPER SDK types arrive via panel_state.h.
|
||||
// directly here; REAPER SDK types arrive via panel_state.h.
|
||||
|
||||
#include <cstdlib> // std::abs (drag threshold)
|
||||
#include <string>
|
||||
@@ -20,14 +15,12 @@
|
||||
|
||||
#include "shell/panel/panel_state.h"
|
||||
|
||||
#include "shell/bank_ops/bank_ops.h" // persistBankOp — shared undo-block wrapper (R-B)
|
||||
#include "shell/actions/drag_out_win.h" // OLE / SWELL drag-out initiation seam (M11)
|
||||
#include "shell/actions/instrument_drop_win.h" // resolveFxDropTarget / performInstrumentDrop (S17)
|
||||
#include "shell/bank_ops/bank_ops.h" // persistBankOp — shared undo-block wrapper
|
||||
#include "shell/actions/drag_out_win.h" // OLE / SWELL drag-out initiation seam
|
||||
#include "shell/actions/instrument_drop_win.h" // resolveFxDropTarget / performInstrumentDrop
|
||||
|
||||
namespace reasampler::panel {
|
||||
|
||||
// --- Drag (move between regions/onto a tab) -----------------------------------
|
||||
|
||||
constexpr int kDragThreshold = 5; // px the pointer must move to begin a drag
|
||||
|
||||
namespace {
|
||||
@@ -55,9 +48,7 @@ void updateDropTarget(int x, int y) {
|
||||
g_panel.dropBankId = tabs[static_cast<std::size_t>(hit.index)]->id;
|
||||
return;
|
||||
}
|
||||
// Tab takes precedence over the region; if the point is in the banks region but
|
||||
// not on a specific tab, treat the whole grid as a drop zone for the shown bank.
|
||||
// No valid target when there are no named banks or no shown bank.
|
||||
// Tab takes precedence; otherwise the whole grid is a drop zone for the shown bank.
|
||||
if (!g_panel.shownBankId.empty() && book() && book()->bank(g_panel.shownBankId)) {
|
||||
if (x >= br.left && x < br.right && y >= br.top && y < br.bottom) {
|
||||
g_panel.dropKind = DropKind::BanksRegion;
|
||||
@@ -76,9 +67,8 @@ void updateDropTarget(int x, int y) {
|
||||
}
|
||||
}
|
||||
|
||||
// The destination bank id under the current drop target (pool id for PoolRegion; the tab/
|
||||
// shown-bank id for Tab/BanksRegion; "" for no target). Derived from updateDropTarget's
|
||||
// dropKind/dropBankId — the single source of "what bank is under the pointer".
|
||||
// The destination bank id under the current drop target (pool id for PoolRegion; the
|
||||
// tab/shown-bank id for Tab/BanksRegion; "" for no target).
|
||||
std::string dropTargetBankId() {
|
||||
switch (g_panel.dropKind) {
|
||||
case DropKind::PoolRegion: return std::string(kPoolBankId);
|
||||
@@ -89,13 +79,12 @@ std::string dropTargetBankId() {
|
||||
return {};
|
||||
}
|
||||
|
||||
// L7: classifies the live in-grid drag into a pure CardGesture and (for a same-bank drop)
|
||||
// the target slot, updating g_panel.cardGesture / dragTargetSlot. Call AFTER updateDropTarget
|
||||
// so dropKind/dropBankId are current. The pure card_drag::decideCardGesture owns the
|
||||
// precedence (leave-client -> OS; other-bank -> move/copy; same-bank grid -> reorder/replace);
|
||||
// the shell only supplies the region verdict, the same-bank target slot + occupancy, and the
|
||||
// live modifier state. The OS-drag-out boundary is handled by the existing decideGesture path
|
||||
// in onMouseMove BEFORE this runs, so here the pointer is always inside the client.
|
||||
// Classifies the live in-grid drag into a pure CardGesture and (for a same-bank drop)
|
||||
// the target slot. Call AFTER updateDropTarget so dropKind/dropBankId are current.
|
||||
// card_drag::decideCardGesture owns the precedence (other-bank -> move/copy; same-bank
|
||||
// grid -> reorder/replace); this only supplies the region verdict, target slot +
|
||||
// occupancy, and modifier state (the OS-drag-out boundary is handled earlier, in
|
||||
// onMouseMove, so here the pointer is always inside).
|
||||
void classifyCardDrag(int x, int y) {
|
||||
g_panel.cardGesture = CardGesture::None;
|
||||
g_panel.dragTargetSlot = -1;
|
||||
@@ -111,10 +100,9 @@ void classifyCardDrag(int x, int y) {
|
||||
mods.alt = altDown();
|
||||
|
||||
if (!destBank.empty() && destBank == g_panel.dragSourceBankId) {
|
||||
// Same-bank grid: a reorder/replace target. Resolve the slot the pointer sits over
|
||||
// in the SOURCE bank's own region display + whether it is occupied.
|
||||
// Uses computeSlotRectsForDrop (one trailing row past maxSlot) so a drop beyond
|
||||
// the last occupied card resolves to a valid trailing slot, not a -1 miss.
|
||||
// Same-bank grid: a reorder/replace target. Resolve the slot + occupancy in the
|
||||
// SOURCE bank's display. computeSlotRectsForDrop adds one trailing row past
|
||||
// maxSlot so a drop beyond the last card resolves to a valid slot, not a -1 miss.
|
||||
mods.region = DropRegion::SameBankGrid;
|
||||
const bool isBanks = g_panel.dragSourceRegion == Region::Banks;
|
||||
const RECT region = isBanks ? banksRegionRect(w, h) : poolRegionRect(w, h);
|
||||
@@ -141,16 +129,11 @@ void classifyCardDrag(int x, int y) {
|
||||
g_panel.cardGesture = decideCardGesture(x, y, client, st, mods);
|
||||
}
|
||||
|
||||
// Maps the pure L7 cursor cue to a SWELL stock cursor and sets it. The cue DECISION is pure
|
||||
// (card_drag::cursorForGesture); the shell owns only this SetCursor call + the resource choice.
|
||||
// Stock SWELL cursors (vendor/WDL/WDL/swell/swell-types.h:1320-1329, mirroring the Win32 OCR_*
|
||||
// set): Reorder -> IDC_SIZEALL (four-way move, the file-manager reorder idiom); Move ->
|
||||
// IDC_HAND (grab-and-place to another bank/tab); Copy -> IDC_UPARROW (no stock copy cursor
|
||||
// exists cross-platform — this is the closest distinct stock cue; a bespoke copy cursor would
|
||||
// need a resource file, deliberately NOT added); Replace -> IDC_SIZEWE (a distinct "swap
|
||||
// occupant" cue, shown ONLY when the pure result is Replace, i.e. Alt over an occupied slot);
|
||||
// OsDragOut -> the OS drag loop owns the cursor once handed off, so leave it (arrow here is
|
||||
// never seen — the handoff happens before this runs); Default/None -> IDC_ARROW.
|
||||
// Maps the pure cursor cue to a SWELL stock cursor (vendor/WDL/WDL/swell/swell-types.h,
|
||||
// mirroring Win32 OCR_*) and sets it; the cue decision is pure (card_drag::cursorForGesture).
|
||||
// Copy has no stock cross-platform cursor, so IDC_UPARROW is the closest distinct stock cue
|
||||
// (a bespoke resource was deliberately not added). OsDragOut leaves the cursor alone — the
|
||||
// OS drag loop owns it once handed off, and this branch is never actually seen.
|
||||
void applyDragCursor(CardGesture g) {
|
||||
const char* idc = IDC_ARROW;
|
||||
switch (cursorForGesture(g)) {
|
||||
@@ -164,26 +147,23 @@ void applyDragCursor(CardGesture g) {
|
||||
SetCursor(LoadCursor(nullptr, idc));
|
||||
}
|
||||
|
||||
// Resolves the topmost INTERACTIVE element under client (x, y) for hover feedback, mirroring
|
||||
// handleClick's precedence exactly (so the element that lights on hover is the one a click
|
||||
// would hit). Returns HoverKind::None for the grid / dead space / a point outside the client
|
||||
// (the grid cells carry their own selection/focus chrome, not a kit hover surface). Pure
|
||||
// resolution over the same pure geometry the click path uses.
|
||||
// Resolves the topmost INTERACTIVE element under client (x, y) for hover feedback,
|
||||
// mirroring handleClick's precedence exactly (so the element that lights on hover is
|
||||
// the one a click would hit). Returns HoverKind::None for the grid / dead space (the
|
||||
// grid cells carry their own selection/focus chrome, not a kit hover surface).
|
||||
Hover resolveHover(int x, int y) {
|
||||
if (!g_panel.hwnd) return Hover{};
|
||||
RECT cr{};
|
||||
GetClientRect(g_panel.hwnd, &cr);
|
||||
const int w = cr.right - cr.left, h = cr.bottom - cr.top;
|
||||
|
||||
// TOP toolbar: the far-right More button, then the frequent buttons (matching the click
|
||||
// order — first zone top-to-bottom).
|
||||
// TOP toolbar, then footer, then BOTTOM toolbar, matching handleClick's precedence.
|
||||
{
|
||||
const MenuButtonRect mb = topMenuButtonRect(w);
|
||||
if (hitTestMenuButton(x, y, mb)) return Hover{HoverKind::MoreButton, -1};
|
||||
const int hit = toolbarHit(x, y, topToolbarActionRect(w), topBarRows());
|
||||
if (hit >= 0) return Hover{HoverKind::TopBarButton, hit};
|
||||
}
|
||||
// Footer: mode-toggle segments, Tail button, then Prune (matching the click order).
|
||||
{
|
||||
const int seg = footerToggleSegmentHit(x, y, w, h);
|
||||
if (seg >= 0) return Hover{HoverKind::ModeSegment, seg};
|
||||
@@ -192,12 +172,10 @@ Hover resolveHover(int x, int y) {
|
||||
const ButtonRect pb = pruneButtonRectFor(w, h);
|
||||
if (hitTestPruneButton(x, y, pb)) return Hover{HoverKind::PruneButton, -1};
|
||||
}
|
||||
// BOTTOM toolbar buttons.
|
||||
{
|
||||
const int hit = toolbarHit(x, y, bottomToolbarRect(w, h), bottomBarRows());
|
||||
if (hit >= 0) return Hover{HoverKind::BottomBarButton, hit};
|
||||
}
|
||||
// Region chrome: full-height toggles, create button, tabs.
|
||||
if (poolShown()) {
|
||||
const RECT pr = poolRegionRect(w, h);
|
||||
const RECT ftb = fullHtBtnRect(pr);
|
||||
@@ -222,10 +200,10 @@ Hover resolveHover(int x, int y) {
|
||||
}
|
||||
|
||||
// Updates the live hover element and repaints ONLY on a change (sub-frame feedback, no
|
||||
// per-move jank — the "speed is the selling point" repaint discipline). L5: a hover CHANGE also
|
||||
// resets the tooltip timer (hoverSinceTick) and hides any shown tooltip, so the tooltip only
|
||||
// appears after the pointer rests kTooltipDelayMs on ONE element (the delay is applied by the
|
||||
// poll tick in maybeShowTooltip). A move within the SAME element leaves the timer running.
|
||||
// per-move jank). A hover CHANGE also resets the tooltip timer (hoverSinceTick) and hides
|
||||
// any shown tooltip, so the tooltip only appears after the pointer rests kTooltipDelayMs
|
||||
// on ONE element (applied by the poll tick in maybeShowTooltip); a move within the SAME
|
||||
// element leaves the timer running.
|
||||
void updateHover(int x, int y) {
|
||||
const Hover next = resolveHover(x, y);
|
||||
if (next != g_panel.hovered) {
|
||||
@@ -239,10 +217,9 @@ void updateHover(int x, int y) {
|
||||
} // namespace
|
||||
|
||||
// Applies the tooltip hover-delay: if a tooltip-bearing element has been hovered past
|
||||
// kTooltipDelayMs and the tooltip is not yet shown, latch it and repaint once. Driven from the
|
||||
// OnTimer poll (bankPanelRefresh) so the tooltip appears after a rest with no dedicated timer;
|
||||
// WM_MOUSEMOVE's updateHover resets the timer, so a moving pointer never trips it. No-op when the
|
||||
// current hover has no tooltip (grid / chrome / the More button).
|
||||
// kTooltipDelayMs and the tooltip is not yet shown, latch it and repaint once. Driven from
|
||||
// the OnTimer poll (bankPanelRefresh) so the tooltip appears after a rest with no dedicated
|
||||
// timer; updateHover resets the timer on every move, so a moving pointer never trips it.
|
||||
void maybeShowTooltip() {
|
||||
if (g_panel.tooltipShown) return;
|
||||
const HoverKind k = g_panel.hovered.kind;
|
||||
@@ -255,9 +232,8 @@ void maybeShowTooltip() {
|
||||
}
|
||||
|
||||
void onMouseMove(int x, int y) {
|
||||
// Hover feedback (L2): resolve + repaint-on-change, but NOT during a drag (the drag owns
|
||||
// the visual feedback then — a drop-target highlight, not a hover). Cleared to None when
|
||||
// the pointer is over the grid / dead space.
|
||||
// Hover feedback: resolve + repaint-on-change, but NOT during a drag (the drag owns
|
||||
// the visual feedback then — a drop-target highlight, not a hover).
|
||||
if (!g_panel.dragging && !g_panel.dragArmed) updateHover(x, y);
|
||||
|
||||
if (g_panel.dragArmed && !g_panel.dragging) {
|
||||
@@ -267,9 +243,9 @@ void onMouseMove(int x, int y) {
|
||||
g_panel.dragging = true;
|
||||
g_panel.dragSourceBankId = bankIdForRegion(g_panel.dragSourceRegion);
|
||||
g_panel.dragSampleIds = focusedSelectionIds();
|
||||
// The single card actually grabbed = the focus ordinal's id. This is the L7
|
||||
// in-grid reorder/replace subject (see onLBtnUp) — "drag a card" is a single-card
|
||||
// gesture, distinct from the multi-select move/copy payload in dragSampleIds.
|
||||
// The single card actually grabbed = the focus ordinal's id — the in-grid
|
||||
// reorder/replace subject (see onLBtnUp), distinct from the multi-select
|
||||
// move/copy payload in dragSampleIds.
|
||||
{
|
||||
const RegionDisplay disp = focusedDisplay();
|
||||
const int f = g_panel.selection.focus;
|
||||
@@ -283,13 +259,9 @@ void onMouseMove(int x, int y) {
|
||||
}
|
||||
}
|
||||
if (g_panel.dragging) {
|
||||
// M11 gesture boundary, REFINED by S17. While a drag with samples is under way and the
|
||||
// pointer is INSIDE the client rect it stays the internal bank-to-bank drag (invariant
|
||||
// #4, byte-identical). Once it LEAVES the client rect the pure drag_out::decideGesture
|
||||
// splits the outside case three ways: a single-capture drag over REAPER's OWN UI is an
|
||||
// InstrumentDrop (hover-track the FX button, drop on release); a multi-capture drag OR a
|
||||
// pointer that has left REAPER entirely is the unchanged M11 OsDrag; inside stays
|
||||
// Internal. The shell supplies the "over REAPER's UI" predicate via GetThingFromPoint.
|
||||
// Inside the client rect it stays the internal bank-to-bank drag. Once it LEAVES,
|
||||
// drag_out::decideGesture splits three ways: single-capture over REAPER's OWN UI ->
|
||||
// InstrumentDrop; multi-capture or fully outside REAPER -> OsDrag; inside -> Internal.
|
||||
RECT cr{};
|
||||
GetClientRect(g_panel.hwnd, &cr);
|
||||
const PanelClientRect client{cr.left, cr.top, cr.right - cr.left, cr.bottom - cr.top};
|
||||
@@ -298,10 +270,8 @@ void onMouseMove(int x, int y) {
|
||||
DragState st{/*dragging=*/true, /*hasArmedSamples=*/!g_panel.dragSampleIds.empty()};
|
||||
st.singleCapture = (g_panel.dragSampleIds.size() == 1);
|
||||
|
||||
// Resolve the FX drop target only when OUTSIDE the client rect (the S17 middle case can
|
||||
// only arise there) and only for a single-capture payload — the SDK hit-test is skipped
|
||||
// on the common internal-drag path so it costs nothing there. The screen conversion is
|
||||
// Windows-only (D5); resolveFxDropTarget owns the REAPER hit query.
|
||||
// Only resolved OUTSIDE the client rect and for a single-capture payload, so the SDK
|
||||
// hit-test costs nothing on the common internal-drag path.
|
||||
FxDropTarget fx;
|
||||
if (!inside && st.singleCapture) {
|
||||
POINT sp{x, y};
|
||||
@@ -313,11 +283,9 @@ void onMouseMove(int x, int y) {
|
||||
const DragGesture gesture = decideGesture(x, y, client, st);
|
||||
|
||||
if (gesture == DragGesture::InstrumentDrop) {
|
||||
// Track the FX hotspot for the release; the highlight is REAPER's own FX-button
|
||||
// hover feedback under the pointer (the drop is driven on button-up). We keep the
|
||||
// internal-drag capture alive so we keep receiving moves (unlike OsDrag, this does
|
||||
// NOT hand off to a modal OS loop). Clear any internal drop-target highlight so the
|
||||
// panel does not also paint a bank-drop cue while the drag is out over a track.
|
||||
// Track the FX hotspot for the release. Unlike OsDrag this does NOT hand off to
|
||||
// a modal OS loop, so the internal-drag capture stays alive; clear any bank
|
||||
// drop-target highlight so the panel doesn't paint that cue too.
|
||||
g_panel.instrumentDropTrack = fx.valid() ? fx.track : nullptr;
|
||||
g_panel.dropKind = DropKind::None;
|
||||
g_panel.dropBankId.clear();
|
||||
@@ -333,11 +301,8 @@ void onMouseMove(int x, int y) {
|
||||
// drag state (the resolver reads dragSourceBankId / dragSampleIds).
|
||||
const std::vector<std::string> paths = resolveDragPathsForOs();
|
||||
|
||||
// Reset internal drag state and release capture NOW: DoDragDrop runs its own
|
||||
// modal loop and takes over mouse capture, so the internal drag must be fully
|
||||
// wound down first (no stale dragging/dropKind, no lingering SetCapture). A
|
||||
// cancelled/empty OS drag therefore leaves the panel in a clean, no-op state
|
||||
// (invariant #2 — nothing mutated).
|
||||
// DoDragDrop runs its own modal loop and takes over mouse capture, so the internal
|
||||
// drag must be fully wound down first.
|
||||
if (GetCapture() == g_panel.hwnd) ReleaseCapture();
|
||||
g_panel.dragArmed = false;
|
||||
g_panel.dragging = false;
|
||||
@@ -353,9 +318,9 @@ void onMouseMove(int x, int y) {
|
||||
initiateDragOut(g_panel.hwnd, paths); // COPY-ONLY; blocking on Windows
|
||||
return;
|
||||
}
|
||||
// Inside the client: classify the in-grid gesture (L7 reorder/replace vs the existing
|
||||
// move/copy) and reflect it as a cursor cue. updateDropTarget first so dropKind/
|
||||
// dropBankId are current for classifyCardDrag's same-vs-other-bank decision.
|
||||
// Inside the client: classify the in-grid gesture (reorder/replace vs move/copy) and
|
||||
// reflect it as a cursor cue. updateDropTarget first so dropKind/dropBankId are
|
||||
// current for classifyCardDrag's same-vs-other-bank decision.
|
||||
updateDropTarget(x, y);
|
||||
classifyCardDrag(x, y);
|
||||
applyDragCursor(g_panel.cardGesture);
|
||||
@@ -363,12 +328,10 @@ void onMouseMove(int x, int y) {
|
||||
}
|
||||
}
|
||||
|
||||
// L7 in-grid REORDER drop: move the grabbed card to targetSlot within its bank (gap-
|
||||
// preserving; onto a gap = place there, onto an occupant = insert-before-and-shift — the pure
|
||||
// BankBook::reorderSample owns the semantics). One drop = one Ctrl-Z (persistBankOp opens the
|
||||
// batched undo point + saves). A no-op reorder (already at the target, model returns false)
|
||||
// opens no undo point. Selection reasons over slot order, so it is cleared after — the
|
||||
// fingerprint pass rebuilds it against the new order.
|
||||
// In-grid REORDER drop: move the grabbed card to targetSlot within its bank (gap-
|
||||
// preserving; onto a gap = place there, onto an occupant = insert-before-and-shift — the
|
||||
// pure BankBook::reorderSample owns the semantics). One drop = one Ctrl-Z. A no-op reorder
|
||||
// opens no undo point. Selection reasons over slot order, so it is cleared after.
|
||||
namespace {
|
||||
|
||||
void doReorderDrop(const std::string& id, const std::string& bankId, int targetSlot) {
|
||||
@@ -379,10 +342,9 @@ void doReorderDrop(const std::string& id, const std::string& bankId, int targetS
|
||||
invalidatePanel();
|
||||
}
|
||||
|
||||
// L7 Alt-REPLACE drop: the grabbed card `newId` takes the occupant `oldId`'s slot; `oldId` is
|
||||
// removed from the bank's index (index-only, file untouched — pool guard enforced in the pure
|
||||
// BankBook::replaceSample). Rejected (pool guard / absent) = a true NO-OP: no fallback insert,
|
||||
// no undo point (per spec). One drop = one Ctrl-Z on success.
|
||||
// Alt-REPLACE drop: the grabbed card `newId` takes the occupant `oldId`'s slot; `oldId` is
|
||||
// removed from the bank's index (index-only, file untouched — pool guard enforced in the
|
||||
// pure BankBook::replaceSample). Rejected = a true NO-OP: no fallback insert, no undo point.
|
||||
void doReplaceDrop(const std::string& newId, const std::string& oldId,
|
||||
const std::string& bankId) {
|
||||
if (!book() || newId.empty() || oldId.empty() || bankId.empty()) return;
|
||||
@@ -409,24 +371,22 @@ void resetDragState() {
|
||||
}
|
||||
|
||||
// Commits (or abandons) a drag on button-up. The resolved pure CardGesture decides:
|
||||
// * Reorder / Replace -> in-grid, within the source bank (L7); one Ctrl-Z each.
|
||||
// * Move / Copy -> the EXISTING cross-bank transfer (unchanged; Ctrl = copy).
|
||||
// * Reorder / Replace -> in-grid, within the source bank; one Ctrl-Z each.
|
||||
// * Move / Copy -> the cross-bank transfer (Ctrl = copy).
|
||||
// * None -> a drop over dead space / the source-bank gap = no-op.
|
||||
// OsDragOut is never seen here: the pointer-left-client handoff happens live in onMouseMove.
|
||||
void onLBtnUp(int x, int y) {
|
||||
if (g_panel.dragging) {
|
||||
// S17 drop-and-load: a release while hover-tracking a valid FX hotspot instantiates a
|
||||
// Drop-and-load: a release while hover-tracking a valid FX hotspot instantiates a
|
||||
// ReaSampler 9000 on that track preloaded with the dragged capture — NOT a bank move,
|
||||
// NOT an OS drag, NEVER a timeline insert. Takes priority over the L7 in-grid / cross-bank
|
||||
// drop (the pointer is out over a track, not over a bank region). Single-capture only (the
|
||||
// gesture never armed for a multi payload), so dragSampleIds.front() is the capture.
|
||||
// NOT an OS drag, NEVER a timeline insert. Takes priority over the in-grid / cross-bank
|
||||
// drop. Single-capture only, so dragSampleIds.front() is the capture.
|
||||
if (g_panel.instrumentDropTrack && g_panel.dragSampleIds.size() == 1) {
|
||||
const std::string sampleId = g_panel.dragSampleIds.front();
|
||||
performInstrumentDrop(g_panel.instrumentDropTrack,
|
||||
buildInstrumentDropPreset(sampleId));
|
||||
// Read-only over the bank + arrange: the ONLY mutations are the new FX instance +
|
||||
// its state (both undoable in performInstrumentDrop). No book change, no ext-state,
|
||||
// no dirty-mark here.
|
||||
// Read-only over the bank + arrange: the only mutations are the new FX instance +
|
||||
// its state (both undoable in performInstrumentDrop).
|
||||
} else {
|
||||
updateDropTarget(x, y);
|
||||
classifyCardDrag(x, y); // re-resolve at the drop point (modifiers may have changed)
|
||||
@@ -481,7 +441,6 @@ void handleRightClick(int x, int y) {
|
||||
GetClientRect(g_panel.hwnd, &cr);
|
||||
const int w = cr.right - cr.left, h = cr.bottom - cr.top;
|
||||
|
||||
// Tab management menu.
|
||||
if (banksShown()) {
|
||||
const RECT br = banksRegionRect(w, h);
|
||||
const TabStripRect strip = banksTabStripRect(br);
|
||||
|
||||
Reference in New Issue
Block a user