Cut shell/panel comment bloat ~47% (comments only, zero code change)
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
// panel_bank_ops.cpp — the bank-CRUD-UX + menus seam of the docked bank panel
|
||||
// (Q-W2 split of the former bank_panel god-module; Phase B4/B5). Since Q-W6 the
|
||||
// promptless bank verbs live in shell/bank_ops (model op + persistBankOp, taking
|
||||
// ReaSamplerSession&); this TU is the panel's THIN UX SKIN over them — the menu
|
||||
// handlers (prompts / confirms / message boxes / panel-state nudges / repaint),
|
||||
// the book/bank accessors, the popup menus that drive them, and the selection-id /
|
||||
// OS-drag path resolvers. The bindable bank_actions family is the sibling skin.
|
||||
// panel_bank_ops.cpp — the bank-CRUD-UX + menus seam of the docked bank panel. The
|
||||
// promptless bank verbs live in shell/bank_ops (bankOp* + persistBankOp); this TU is
|
||||
// the panel's THIN UX SKIN over them — menu handlers, book/bank accessors, popup
|
||||
// menus, and the selection-id / OS-drag path resolvers. `bank_actions` is the
|
||||
// sibling bindable-action skin.
|
||||
//
|
||||
// Compiled into the reaper_reasampler MODULE. Includes reaper_plugin_functions.h
|
||||
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp owns the API pointers; here they are
|
||||
// extern (CLAUDE.md §contract). DAW-verified, not unit tested.
|
||||
// WITHOUT REAPERAPI_IMPLEMENT — main.cpp owns the API pointers. DAW-verified, not
|
||||
// unit-tested.
|
||||
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
@@ -18,7 +16,7 @@
|
||||
#include "shell/panel/panel_state.h"
|
||||
#include "shell/panel/panel_bank_ops.h"
|
||||
|
||||
#include "shell/bank_ops/bank_ops.h" // bankOp* promptless verbs (the Q-W6 non-UI seam)
|
||||
#include "shell/bank_ops/bank_ops.h" // bankOp* promptless verbs
|
||||
#include "shell/persist/session.h" // ReaSamplerSession — the live session the ops mutate
|
||||
|
||||
#define REAPERAPI_MINIMAL
|
||||
@@ -32,7 +30,7 @@ namespace reasampler::panel {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// --- Current-project directory (mirrors the persist shell's derivation, ext_state_io.cpp)
|
||||
// Mirrors the persist shell's derivation (ext_state_io.cpp).
|
||||
std::string currentProjectDir() {
|
||||
std::vector<char> buf(4096, '\0');
|
||||
EnumProjects(-1, buf.data(), static_cast<int>(buf.size()));
|
||||
@@ -41,8 +39,6 @@ std::string currentProjectDir() {
|
||||
return normalizeSlashes(fs::path(rpp).parent_path().string());
|
||||
}
|
||||
|
||||
// --- Book / bank accessors ----------------------------------------------------
|
||||
|
||||
BankBook* book() { return g_panel.session ? &g_panel.session->book() : nullptr; }
|
||||
|
||||
// The BankModel a region currently displays. Pool region -> the pool; banks region ->
|
||||
@@ -72,17 +68,9 @@ std::vector<const Bank*> namedBanks() {
|
||||
return out;
|
||||
}
|
||||
|
||||
// --- Bank management ops (id-keyed; THIN UX SKINS over the bankOp* verbs) ------
|
||||
//
|
||||
// Q-W4/Q-W6: each handler here owns only the panel's UX (prompts / confirms /
|
||||
// message boxes / panel-state nudges / repaint); the model op + persist is the
|
||||
// shared bankOp* inner verb (shell/bank_ops), which takes the live session by
|
||||
// reference — the book() check answers the one session-liveness question per
|
||||
// handler. After a STRUCTURAL mutation (create/delete/evacuate) any
|
||||
// Bank*/BankModel& is invalid — we resolve fresh, pass ids, and let the next
|
||||
// refreshFingerprint repaint. On an unsaved project the empty-close discard in
|
||||
// persistBankOp ensures no stale state survives (matches the capture/B3
|
||||
// quiet-persist idiom).
|
||||
// Bank management ops (id-keyed; THIN UX SKINS over the bankOp* verbs). After a
|
||||
// STRUCTURAL mutation (create/delete/evacuate) any Bank*/BankModel& is invalid — we
|
||||
// resolve fresh, pass ids, and let the next refreshFingerprint repaint.
|
||||
|
||||
void doCreateBank() {
|
||||
if (!book()) return;
|
||||
@@ -116,9 +104,9 @@ void doRenameBank(const std::string& bankId) {
|
||||
invalidatePanel();
|
||||
}
|
||||
|
||||
// Delete with the RICHER confirm-on-non-empty affordance (B4): the confirm names the
|
||||
// member count AND offers evacuate as the one-click alternative (Yes=delete anyway,
|
||||
// No=evacuate-then-keep, Cancel=abort) — richer than B3's basic YESNO.
|
||||
// Delete with a confirm-on-non-empty affordance: the confirm names the member count
|
||||
// and offers evacuate as the one-click alternative (Yes=delete anyway,
|
||||
// No=evacuate-then-keep, Cancel=abort).
|
||||
void doDeleteBank(const std::string& bankId) {
|
||||
if (!book()) return;
|
||||
const Bank* bk = book()->bank(bankId);
|
||||
@@ -144,13 +132,10 @@ void doDeleteBank(const std::string& bankId) {
|
||||
}
|
||||
// r == 6 (Yes) falls through to a plain delete (drops members).
|
||||
}
|
||||
// S9: bump when the bank held samples (either the Yes-drop path or the No-evacuate-then-
|
||||
// delete path moved/dropped members) — both change what a live instance could play. An
|
||||
// empty-bank delete is purely organizational, no bump. The ORIGINAL member count decides
|
||||
// (the No-path evacuated them moments ago, but the membership still changed).
|
||||
// Bump generation when the bank held samples — an empty-bank delete is purely
|
||||
// organizational. The ORIGINAL member count decides (the No-path already evacuated them).
|
||||
if (!bankOpDelete(*g_panel.session, bankId, /*bumpGeneration=*/members > 0)) return;
|
||||
// shownBankId is reconciled by the next fingerprint pass. If no named banks remain,
|
||||
// nudge focus to the pool so the selection has a valid home.
|
||||
// If no named banks remain, nudge focus to the pool so the selection has a valid home.
|
||||
if (namedBanks().empty()) g_panel.focusedRegion = Region::Pool;
|
||||
invalidatePanel();
|
||||
}
|
||||
@@ -172,40 +157,33 @@ void doActivateBank(const std::string& bankId) {
|
||||
} // namespace
|
||||
|
||||
// Move or copy `sampleIds` from `srcBankId` to `destBankId` (index-only). Thin panel
|
||||
// skin over bankOpTransfer (the one-home verb owns the loop, the verb-aware no-op
|
||||
// guardrail, and the undo-batched persist); this layer clears the stale selection
|
||||
// and repaints on an actual mutation.
|
||||
// skin over bankOpTransfer; clears the stale selection and repaints on an actual mutation.
|
||||
void transferSamples(const std::vector<std::string>& sampleIds,
|
||||
const std::string& srcBankId, const std::string& destBankId,
|
||||
bool copy) {
|
||||
if (!book()) return; // no live session — nothing to transfer within
|
||||
if (!bankOpTransfer(*g_panel.session, sampleIds, srcBankId, destBankId, copy))
|
||||
return; // nothing changed — no persist, no undo point
|
||||
// The selection indexed into the source; after a move those indices are stale, so
|
||||
// clear it (the fingerprint pass will also clear, but do it now for immediacy).
|
||||
// Selection indexed into the source; after a move those indices are stale.
|
||||
g_panel.selection = Selection{};
|
||||
invalidatePanel();
|
||||
}
|
||||
|
||||
// Remove `sampleIds` from `srcBankId` (index-only, this-bank scope). Thin panel skin
|
||||
// over bankOpRemove — see the verb for the never-deletes-bytes / silent-remove /
|
||||
// one-Ctrl-Z contract. Clears the stale selection and repaints on an actual removal.
|
||||
// over bankOpRemove. Clears the stale selection and repaints on an actual removal.
|
||||
void removeSamples(const std::vector<std::string>& sampleIds,
|
||||
const std::string& srcBankId) {
|
||||
if (!book()) return; // no live session — nothing to remove from
|
||||
if (!bankOpRemove(*g_panel.session, sampleIds, srcBankId))
|
||||
return; // nothing changed — no persist, no undo point
|
||||
// The selection indexed into the source; after a remove those indices are stale, so
|
||||
// clear it (the fingerprint pass will also clear, but do it now for immediacy).
|
||||
g_panel.selection = Selection{};
|
||||
invalidatePanel();
|
||||
}
|
||||
|
||||
// The selection's sample ids resolved against the FOCUSED region's bank (source of a
|
||||
// move/copy). Returns ids in bank order; empty when nothing selected.
|
||||
// move/copy). Selection ordinals index the DISPLAY (slot) order, not BankModel
|
||||
// insertion order. Returns ids in bank order; empty when nothing selected.
|
||||
std::vector<std::string> focusedSelectionIds() {
|
||||
// L7: selection ordinals index the DISPLAY (slot) order, not BankModel insertion order.
|
||||
// orderedIds[i] is the id at selection ordinal i.
|
||||
std::vector<std::string> ids;
|
||||
const RegionDisplay disp = focusedDisplay();
|
||||
const int count = disp.occupiedCount();
|
||||
@@ -214,14 +192,11 @@ std::vector<std::string> focusedSelectionIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
// Resolves the ARMED drag payload (g_panel.dragSampleIds, from g_panel.dragSourceBankId) to
|
||||
// the absolute, existing-file path list for a native OS drag-out (M11). Reuses the SAME M4
|
||||
// path machinery the panel uses for audition/insert (resolveBankFile over the current
|
||||
// project dir) — no temp copies; the drag points straight at the on-disk bank files. Each
|
||||
// id is looked up in its SOURCE bank's index (the payload's origin, not the focused region,
|
||||
// which can differ once the pointer roams), resolved, stat'd, then handed to the pure
|
||||
// drag_out::assemblePathList for dedupe + skip-missing/unresolved policy. Read-only: no
|
||||
// mutation of sample / index / selection (invariant #2).
|
||||
// Resolves the ARMED drag payload to the absolute, existing-file path list for a native
|
||||
// OS drag-out. Reuses resolveBankFile (audition/insert's path machinery) — no temp
|
||||
// copies. Each id is looked up in its SOURCE bank's index (not the focused region, which
|
||||
// can differ once the pointer roams), then handed to drag_out::assemblePathList for
|
||||
// dedupe + skip-missing/unresolved policy. Read-only.
|
||||
std::vector<std::string> resolveDragPathsForOs() {
|
||||
std::vector<ResolvedSample> resolved;
|
||||
BankBook* b = book();
|
||||
@@ -242,19 +217,13 @@ std::vector<std::string> resolveDragPathsForOs() {
|
||||
return assemblePathList(resolved).paths;
|
||||
}
|
||||
|
||||
// --- Popup menus --------------------------------------------------------------
|
||||
//
|
||||
// SWELL/Win32 both expose CreatePopupMenu / InsertMenu (SWELL aliases SWELL_InsertMenu
|
||||
// -> InsertMenu) / TrackPopupMenu(TPM_RETURNCMD) / DestroyMenu. We build a menu of
|
||||
// (label -> small int command), track it at screen coords, and switch on the return.
|
||||
// Menu command ids are LOCAL to the popup (not REAPER action ids) — TPM_RETURNCMD
|
||||
// hands the chosen id straight back, so no hookcommand routing is involved.
|
||||
// SWELL/Win32 both expose CreatePopupMenu / InsertMenu / TrackPopupMenu(TPM_RETURNCMD) /
|
||||
// DestroyMenu. Menu command ids below are LOCAL to the popup (not REAPER action ids) —
|
||||
// TPM_RETURNCMD hands the chosen id straight back, so no hookcommand routing is involved.
|
||||
|
||||
namespace {
|
||||
|
||||
// Appends a string item (id) to `menu` at its end. Portable over Win32/SWELL: both
|
||||
// accept InsertMenu(menu, pos, MF_BYPOSITION|MF_STRING, id, text) with a negative
|
||||
// position appending. Win32 and SWELL both treat pos < 0 as an append.
|
||||
// Win32 and SWELL both treat pos < 0 as append.
|
||||
void menuAppend(HMENU menu, unsigned int id, const char* text, bool grayed = false) {
|
||||
UINT flags = MF_BYPOSITION | MF_STRING;
|
||||
if (grayed) flags |= MF_GRAYED;
|
||||
@@ -272,7 +241,7 @@ enum : unsigned int {
|
||||
kMenuDelete,
|
||||
kMenuEvacuate,
|
||||
kMenuCreate,
|
||||
kMenuRemove, // remove selected sample(s) from the source bank (B5)
|
||||
kMenuRemove, // remove selected sample(s) from the source bank
|
||||
kMenuMoveBase = 1000, // move-to-bank: kMenuMoveBase + destination index
|
||||
kMenuCopyBase = 2000, // copy-to-bank: kMenuCopyBase + destination index
|
||||
};
|
||||
@@ -313,11 +282,10 @@ void showTabMenu(int screenX, int screenY, const std::string& bankId) {
|
||||
}
|
||||
}
|
||||
|
||||
// Opens the top-toolbar overflow ("⋯" More) popup at the button's screen position and fires the
|
||||
// chosen rare-capture variant's command (L5 refinement 1). Menu ids are LOCAL to the popup
|
||||
// (1-based ordinal into overflowMenuRows); TPM_RETURNCMD hands the chosen id back, then we
|
||||
// resolve + fire the corresponding registered command id via the SAME contract the visible
|
||||
// buttons use. Defined here (after menuAppend/menuSeparator); forward-declared above.
|
||||
// Opens the top-toolbar overflow ("⋯" More) popup and fires the chosen rare-capture
|
||||
// variant's command. Menu ids are LOCAL to the popup (1-based ordinal into
|
||||
// overflowMenuRows); we resolve + fire the corresponding registered command id via
|
||||
// the same contract the visible buttons use.
|
||||
void showMoreMenu() {
|
||||
if (!g_panel.hwnd) return;
|
||||
const std::vector<ActionBarRow> rows = overflowMenuRows();
|
||||
@@ -349,9 +317,8 @@ void showMoreMenu() {
|
||||
}
|
||||
|
||||
// Shows the move/copy menu for the current selection (the SOURCE is the focused
|
||||
// region's bank). Lists every OTHER bank (pool + named) as a move destination, then a
|
||||
// copy submenu-free flat list (copy entries follow the move block). Move is the
|
||||
// default (listed first); copy is the deliberate secondary act.
|
||||
// region's bank). Lists every OTHER bank as a move destination, then the same list
|
||||
// as a copy destination. Move is the default (listed first); copy is secondary.
|
||||
void showSelectionMenu(int screenX, int screenY) {
|
||||
const std::vector<std::string> sel = focusedSelectionIds();
|
||||
if (sel.empty()) return;
|
||||
@@ -401,18 +368,14 @@ void showSelectionMenu(int screenX, int screenY) {
|
||||
|
||||
} // namespace reasampler::panel
|
||||
|
||||
// --- Public API (panel_bank_ops.h) ---------------------------------------------
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
// One home (Q-W4) for the former actions/panel byte-identical twins.
|
||||
// COMMA GUARD: GetUserInputs splits returned values on a separator defaulting to ',',
|
||||
// so the return separator is overridden to \x1f (un-typeable) via the documented
|
||||
// `separator=X` trailing pseudo-caption (SDK ~3806) — any printable name round-trips.
|
||||
// GetUserInputs splits returned values on a separator defaulting to ',', so the
|
||||
// separator is overridden to \x1f (un-typeable) via the documented `separator=X`
|
||||
// trailing pseudo-caption — any printable name round-trips.
|
||||
bool promptBankName(const char* title, const char* caption, const std::string& initial,
|
||||
std::string& out) {
|
||||
std::vector<char> buf(512, '\0');
|
||||
// Pre-fill: GetUserInputs seeds the field from the retvals buffer's initial value.
|
||||
std::snprintf(buf.data(), buf.size(), "%s", initial.c_str());
|
||||
const std::string captions = std::string(caption) + ",separator=\x1f";
|
||||
if (!GetUserInputs(title, 1, captions.c_str(), buf.data(),
|
||||
@@ -424,8 +387,6 @@ bool promptBankName(const char* title, const char* caption, const std::string& i
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- Selection read seam --------------------------------------------------------
|
||||
|
||||
std::vector<std::string> bankPanelSelectedSampleIds() {
|
||||
return panel::focusedSelectionIds();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user