fix(bank_panel): null-guard uniformity, stale comment/focus nudge on delete, dragArmed on capture-loss, menuAppend comment

This commit is contained in:
2026-07-25 17:10:46 -04:00
parent 960a649238
commit cca7380777
+20 -5
View File
@@ -991,6 +991,7 @@ std::string mintBankId() {
} }
void doCreateBank() { void doCreateBank() {
if (!book()) return;
std::string name; std::string name;
if (!promptText("ReaSampler: create bank", "Bank name:", "", name)) return; if (!promptText("ReaSampler: create bank", "Bank name:", "", name)) return;
const std::string id = mintBankId(); const std::string id = mintBankId();
@@ -1006,6 +1007,7 @@ void doCreateBank() {
} }
void doRenameBank(const std::string& bankId) { void doRenameBank(const std::string& bankId) {
if (!book()) return;
const Bank* bk = book()->bank(bankId); const Bank* bk = book()->bank(bankId);
if (!bk || bk->isPool()) return; if (!bk || bk->isPool()) return;
const std::string current = bk->displayName; // copy before any mutation const std::string current = bk->displayName; // copy before any mutation
@@ -1024,6 +1026,7 @@ void doRenameBank(const std::string& bankId) {
// member count AND offers evacuate as the one-click alternative (Yes=delete anyway, // 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. // No=evacuate-then-keep, Cancel=abort) — richer than B3's basic YESNO.
void doDeleteBank(const std::string& bankId) { void doDeleteBank(const std::string& bankId) {
if (!book()) return;
const Bank* bk = book()->bank(bankId); const Bank* bk = book()->bank(bankId);
if (!bk || bk->isPool()) return; if (!bk || bk->isPool()) return;
const std::size_t members = bk->index.size(); // read BEFORE any mutation const std::size_t members = bk->index.size(); // read BEFORE any mutation
@@ -1049,12 +1052,14 @@ void doDeleteBank(const std::string& bankId) {
} }
if (!book()->deleteBank(bankId)) return; if (!book()->deleteBank(bankId)) return;
persistBook(); persistBook();
// shownBankId is reconciled by the next fingerprint pass; nudge focus to pool if // shownBankId is reconciled by the next fingerprint pass. If no named banks remain,
// no named banks remain so the selection has a valid home. // nudge focus to the pool so the selection has a valid home.
if (namedBanks().empty()) g_panel.focusedRegion = Region::Pool;
invalidatePanel(); invalidatePanel();
} }
void doEvacuateBank(const std::string& bankId) { void doEvacuateBank(const std::string& bankId) {
if (!book()) return;
const Bank* bk = book()->bank(bankId); const Bank* bk = book()->bank(bankId);
if (!bk || bk->isPool()) return; if (!bk || bk->isPool()) return;
if (!book()->evacuate(bankId)) return; if (!book()->evacuate(bankId)) return;
@@ -1063,6 +1068,7 @@ void doEvacuateBank(const std::string& bankId) {
} }
void doActivateBank(const std::string& bankId) { void doActivateBank(const std::string& bankId) {
if (!book()) return;
if (!book()->setActiveBank(bankId)) return; // rejects an unknown id if (!book()->setActiveBank(bankId)) return; // rejects an unknown id
persistBook(); persistBook();
invalidatePanel(); invalidatePanel();
@@ -1073,6 +1079,7 @@ void doActivateBank(const std::string& bankId) {
void transferSamples(const std::vector<std::string>& sampleIds, void transferSamples(const std::vector<std::string>& sampleIds,
const std::string& srcBankId, const std::string& destBankId, const std::string& srcBankId, const std::string& destBankId,
bool copy) { bool copy) {
if (!book()) return;
if (sampleIds.empty() || srcBankId == destBankId) return; if (sampleIds.empty() || srcBankId == destBankId) return;
if (!book()->bank(srcBankId) || !book()->bank(destBankId)) return; if (!book()->bank(srcBankId) || !book()->bank(destBankId)) return;
for (const std::string& sid : sampleIds) { for (const std::string& sid : sampleIds) {
@@ -1108,9 +1115,8 @@ std::vector<std::string> focusedSelectionIds() {
// hands the chosen id straight back, so no hookcommand routing is involved. // hands the chosen id straight back, so no hookcommand routing is involved.
// Appends a string item (id) to `menu` at its end. Portable over Win32/SWELL: both // 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 pos past the // accept InsertMenu(menu, pos, MF_BYPOSITION|MF_STRING, id, text) with a negative
// end appending. -1 as an unsigned position appends on Win32; SWELL clamps a large // position appending. Win32 and SWELL both treat pos < 0 as an append.
// pos to the end.
void menuAppend(HMENU menu, unsigned int id, const char* text, bool grayed = false) { void menuAppend(HMENU menu, unsigned int id, const char* text, bool grayed = false) {
UINT flags = MF_BYPOSITION | MF_STRING; UINT flags = MF_BYPOSITION | MF_STRING;
if (grayed) flags |= MF_GRAYED; if (grayed) flags |= MF_GRAYED;
@@ -1135,6 +1141,7 @@ enum : unsigned int {
// Shows the right-click context menu for a named-bank TAB: activate / rename / delete // Shows the right-click context menu for a named-bank TAB: activate / rename / delete
// / evacuate that bank, plus a create entry. Drives the id-keyed ops. // / evacuate that bank, plus a create entry. Drives the id-keyed ops.
void showTabMenu(int screenX, int screenY, const std::string& bankId) { void showTabMenu(int screenX, int screenY, const std::string& bankId) {
if (!book()) return;
const Bank* bk = book()->bank(bankId); const Bank* bk = book()->bank(bankId);
if (!bk || bk->isPool()) return; if (!bk || bk->isPool()) return;
const bool isActive = book()->activeBankId() == bankId; const bool isActive = book()->activeBankId() == bankId;
@@ -1582,6 +1589,14 @@ WDL_DLGRET dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
SetFocus(hwnd); SetFocus(hwnd);
handleRightClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); handleRightClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0; return 0;
case WM_CAPTURECHANGED:
// Capture lost before a drag began (e.g. pointer left window pre-threshold
// and button released outside) — disarm so the state doesn't stay stale.
if (g_panel.dragArmed && !g_panel.dragging) {
g_panel.dragArmed = false;
invalidatePanel();
}
return 0;
case WM_DESTROY: case WM_DESTROY:
if (GetCapture() == hwnd) ReleaseCapture(); if (GetCapture() == hwnd) ReleaseCapture();
stopAudition(); stopAudition();