Merge fixes: UI mojibake (ASCII strings) + whole banks-grid drop zone

This commit is contained in:
2026-07-26 16:15:53 -04:00
4 changed files with 49 additions and 25 deletions
+1 -1
View File
@@ -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);
+39 -15
View File
@@ -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<int>(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<std::string>& 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<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.
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()) {
+4 -4
View File
@@ -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;
+5 -5
View File
@@ -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<ViewModeModel> 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<TailSetting> 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<OwnedFileManifest> 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<BankBook> 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);