diff --git a/src/actions.cpp b/src/actions.cpp index 86931be..c3fa34c 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -767,7 +767,7 @@ void doBankRemoveSelected() { (orphanCount == 1 ? " selected sample is" : " selected samples are") + " in no other bank.\n\nRemoving " + (orphanCount == 1 ? "it" : "them") + - " drops the index entry only — the file stays on disk until you prune " + " drops the index entry only -- the file stays on disk until you prune " "(it is never deleted by remove).\n\nRemove anyway?"; const int r = ShowMessageBox(msg.c_str(), "ReaSampler: remove last-reference sample(s)", 4); diff --git a/src/bank_panel.cpp b/src/bank_panel.cpp index 37219d0..69864c3 100644 --- a/src/bank_panel.cpp +++ b/src/bank_panel.cpp @@ -198,7 +198,10 @@ struct CachedThumbnail { enum class Region { Pool, Banks }; // What a drag is dropping onto, resolved live under the pointer during a drag. -enum class DropKind { None, PoolRegion, Tab }; +// BanksRegion fires when the pointer is anywhere in the named-banks grid that is NOT +// on a specific tab (tab takes precedence — more specific wins). The resolved bank is +// always shownBankId. +enum class DropKind { None, PoolRegion, Tab, BanksRegion }; struct PanelState { ReaSamplerSession* session = nullptr; @@ -736,7 +739,7 @@ void drawRegionHeader(LICE_IBitmap* bmp, const RECT& region, const char* title, const bool thisFull = poolBtnIsPool ? (g_panel.fullHeight == BankPanelFullHeight::PoolOnly) : (g_panel.fullHeight == BankPanelFullHeight::BanksOnly); - drawCenteredText(bmp, btn, thisFull ? "\xE2\x87\x85" : "\xE2\x87\x83", // ⇅ / ⇃ + drawCenteredText(bmp, btn, thisFull ? "[v]" : "[^]", // collapse / expand kRgbBtnText, DT_CENTER); } @@ -754,7 +757,7 @@ void drawTabStrip(LICE_IBitmap* bmp, const RECT& region) { const int n = static_cast(tabs.size()); if (n == 0) { RECT r{strip.x + 8, strip.y, strip.x + strip.width, strip.y + strip.height}; - drawCenteredText(bmp, r, "No named banks — click + to create one.", + drawCenteredText(bmp, r, "No named banks -- click + to create one.", RGB(140, 140, 146), DT_LEFT); return; } @@ -772,8 +775,8 @@ void drawTabStrip(LICE_IBitmap* bmp, const RECT& region) { strip.y + strip.height}; RECT rc{strip.x + strip.width - kTabSpec.chevronWidth, strip.y, strip.x + strip.width, strip.y + strip.height}; - drawCenteredText(bmp, lc, "\xE2\x80\xB9", kRgbTabText, DT_CENTER); // ‹ - drawCenteredText(bmp, rc, "\xE2\x80\xBA", kRgbTabText, DT_CENTER); // › + drawCenteredText(bmp, lc, "<", kRgbTabText, DT_CENTER); + drawCenteredText(bmp, rc, ">", kRgbTabText, DT_CENTER); } const std::string activeId = book() ? book()->activeBankId() : std::string(); @@ -869,6 +872,15 @@ void paintPanel(HWND hwnd, HDC hdc) { ? "Select or create a named bank." : "This bank is empty. Move samples here from the pool.", g_panel.focusedRegion == Region::Banks, projectDir); + // Drop-target highlight for the banks region during a drag. BanksRegion fires + // when the pointer is in the grid but not on a specific tab; Tab draws its own + // highlight on the individual tab (drawTabStrip above handles that case). + if (g_panel.dragging && g_panel.dropKind == DropKind::BanksRegion) { + const RECT grid = regionGridRect(region, true); + LICE_DrawRect(&bmp, grid.left + 1, grid.top + 1, + grid.right - grid.left - 2, grid.bottom - grid.top - 2, + kColDropTarget, 1.0f, 0); + } } drawModeSwitch(&bmp, w); @@ -1256,9 +1268,9 @@ void doDeleteBank(const std::string& bankId) { const std::string msg = "\"" + name + "\" holds " + std::to_string(members) + (members == 1 ? " sample" : " samples") + - ".\n\nYes — delete the bank AND drop its samples (files are kept on disk " - "but no bank references them until prune).\nNo — Evacuate them to the " - "pool first, then delete the empty bank (keeps the samples).\nCancel — " + ".\n\nYes -- delete the bank AND drop its samples (files are kept on disk " + "but no bank references them until prune).\nNo -- Evacuate them to the " + "pool first, then delete the empty bank (keeps the samples).\nCancel -- " "do nothing."; // 3 == MB_YESNOCANCEL. 6=Yes, 7=No, 2=Cancel (SDK). const int r = ShowMessageBox(msg.c_str(), @@ -1361,7 +1373,7 @@ void removeSamples(const std::vector& sampleIds, (orphanCount == 1 ? " selected sample is" : " selected samples are") + " in no other bank.\n\nRemoving " + (orphanCount == 1 ? "it" : "them") + - " drops the index entry only — the file stays on disk until you prune " + " drops the index entry only -- the file stays on disk until you prune " "(it is never deleted by remove).\n\nRemove anyway?"; // 4 == MB_YESNO. 6=Yes (SDK); anything else cancels. const int r = ShowMessageBox(msg.c_str(), @@ -1443,11 +1455,11 @@ void showTabMenu(int screenX, int screenY, const std::string& bankId) { isActive ? "Active (capture target)" : "Activate (make capture target)", /*grayed=*/isActive); menuSeparator(menu); - menuAppend(menu, kMenuRename, "Rename\xE2\x80\xA6"); + menuAppend(menu, kMenuRename, "Rename..."); menuAppend(menu, kMenuEvacuate, "Evacuate to pool", /*grayed=*/!nonEmpty); - menuAppend(menu, kMenuDelete, "Delete\xE2\x80\xA6"); + menuAppend(menu, kMenuDelete, "Delete..."); menuSeparator(menu); - menuAppend(menu, kMenuCreate, "New bank\xE2\x80\xA6"); + menuAppend(menu, kMenuCreate, "New bank..."); const int cmd = TrackPopupMenu(menu, TPM_RETURNCMD, screenX, screenY, 0, g_panel.hwnd, nullptr); @@ -1498,7 +1510,7 @@ void showSelectionMenu(int screenX, int screenY) { (" " + dests[i].name).c_str()); menuSeparator(menu); } - menuAppend(menu, kMenuRemove, ("Remove " + label + "\xE2\x80\xA6").c_str()); + menuAppend(menu, kMenuRemove, ("Remove " + label + "...").c_str()); const int cmd = TrackPopupMenu(menu, TPM_RETURNCMD, screenX, screenY, 0, g_panel.hwnd, nullptr); @@ -1803,6 +1815,16 @@ void updateDropTarget(int x, int y) { g_panel.dropBankId = tabs[static_cast(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. + 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; + g_panel.dropBankId = g_panel.shownBankId; + return; + } + } } if (poolShown()) { const RECT pr = poolRegionRect(w, h); @@ -1838,8 +1860,10 @@ void onLBtnUp(int x, int y) { if (g_panel.dragging) { updateDropTarget(x, y); std::string destId; - if (g_panel.dropKind == DropKind::PoolRegion) destId = std::string(kPoolBankId); - else if (g_panel.dropKind == DropKind::Tab) destId = g_panel.dropBankId; + if (g_panel.dropKind == DropKind::PoolRegion) destId = std::string(kPoolBankId); + else if (g_panel.dropKind == DropKind::Tab || + g_panel.dropKind == DropKind::BanksRegion) + destId = g_panel.dropBankId; if (!destId.empty() && destId != g_panel.dragSourceBankId && !g_panel.dragSampleIds.empty()) { diff --git a/src/main.cpp b/src/main.cpp index 609717f..26c18a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -177,11 +177,11 @@ static void DriveRealtimeCapture() // abort from the closed-project DROP (the captured project was closed mid-record, // review §1: nothing restored because the pointers were already freed). if (r.status == reasampler::RealtimeTickStatus::Done) - ShowConsoleMsg("ReaSampler realtime capture: project switched mid-record — " + ShowConsoleMsg("ReaSampler realtime capture: project switched mid-record -- " "captured audio restored into the original project; not " "persisted to avoid crossing projects.\n"); else - ShowConsoleMsg(("ReaSampler realtime capture: project changed mid-record — " + + ShowConsoleMsg(("ReaSampler realtime capture: project changed mid-record -- " + r.result.message + "\n").c_str()); g_rtCapture.reset(); g_rtCaptureProject = nullptr; @@ -646,7 +646,7 @@ static void RunCaptureRealtimeTrack() if (g_rtCapture) { ShowConsoleMsg("ReaSampler realtime capture: a capture is already in " - "progress — let it finish (or stop the transport) first.\n"); + "progress -- let it finish (or stop the transport) first.\n"); return; } @@ -712,7 +712,7 @@ static void RunCancelRealtime() if (r.status == reasampler::RealtimeTickStatus::Done) CommitRealtimeResult(r.result); // Ok: keep what was captured up to the cancel else - ShowConsoleMsg(("ReaSampler realtime capture cancelled — " + + ShowConsoleMsg(("ReaSampler realtime capture cancelled -- " + r.result.message + "\n").c_str()); g_rtCapture.reset(); g_rtCaptureProject = nullptr; diff --git a/src/persist.cpp b/src/persist.cpp index fe303f1..3f49a08 100644 --- a/src/persist.cpp +++ b/src/persist.cpp @@ -142,7 +142,7 @@ std::string getProjExtStateString(ReaProject* proj, const char* ns, // the console so this reads as "too large to load", not silent data loss // (mirrors the malformed-JSON warning in loadFromProject). ShowConsoleMsg(("ReaSampler: stored value for key '" + std::string(key) + - "' exceeds the 16 MB read ceiling — ignoring (bank not " + "' exceeds the 16 MB read ceiling -- ignoring (bank not " "loaded).\n").c_str()); return {}; } @@ -245,7 +245,7 @@ ViewModeModel loadViewModel(ReaProject* proj) { if (viewJson.empty()) return ViewModeModel{}; // no stored view state -> default std::optional loaded = ViewModeModel::deserialize(viewJson); if (!loaded) { - ShowConsoleMsg("ReaSampler: stored view state is malformed — ignoring.\n"); + ShowConsoleMsg("ReaSampler: stored view state is malformed -- ignoring.\n"); return ViewModeModel{}; } return std::move(*loaded); @@ -262,7 +262,7 @@ TailSetting loadTailSetting(ReaProject* proj) { if (tailJson.empty()) return TailSetting{}; // no stored setting -> default std::optional loaded = deserializeTailSetting(tailJson); if (!loaded) { - ShowConsoleMsg("ReaSampler: stored tail setting is malformed — ignoring.\n"); + ShowConsoleMsg("ReaSampler: stored tail setting is malformed -- ignoring.\n"); return TailSetting{}; } return *loaded; @@ -281,7 +281,7 @@ OwnedFileManifest loadOwnedManifest(ReaProject* proj) { if (ownedJson.empty()) return OwnedFileManifest{}; // no stored manifest -> empty std::optional loaded = OwnedFileManifest::deserialize(ownedJson); if (!loaded) { - ShowConsoleMsg("ReaSampler: stored owned-file manifest is malformed — ignoring.\n"); + ShowConsoleMsg("ReaSampler: stored owned-file manifest is malformed -- ignoring.\n"); return OwnedFileManifest{}; } return std::move(*loaded); @@ -334,7 +334,7 @@ void ReaSamplerSession::loadFromProject(void* proj, const std::string& projectDi if (!banksJson.empty()) { std::optional loaded = BankBook::deserialize(banksJson); if (!loaded) { - ShowConsoleMsg("ReaSampler: stored banks are malformed — ignoring.\n"); + ShowConsoleMsg("ReaSampler: stored banks are malformed -- ignoring.\n"); book_ = BankBook{}; } else { book_ = std::move(*loaded);