feat(debug): theme x tab screenshot sweep + Debug options dialog

Add a debug tool that cycles every skin across every build-enabled tab and saves a
PNG of each to a timestamped folder under the config dir (screenshots/sweep_<ts>/)
— for gathering visual context on theme-specific UI work.

- App state machine (app_network.cpp): startScreenshotSweep() builds the
  skin+enabled-page lists, saves the current skin/page, and steps through them;
  updateScreenshotSweep() (top of App::render) pins the page + settles ~4 frames
  after each skin/page change (skin switches reload TOML + reset the acrylic
  capture, so they need to settle); wantsScreenshotThisFrame()/screenshotSweepPath()
  /onScreenshotCaptured() coordinate with main.cpp. Restores the original skin/page
  when done; nothing persisted.
- Framebuffer capture (main.cpp): read the finished frame and encode PNG via the
  bundled miniz (tdefl_write_image_to_png_file_in_memory_ex). GL reads FBO 0 (RGBA,
  bottom-up -> flip); DX11 copies the backbuffer to a staging texture + maps it
  (BGRA, top-down -> channel-swap). Alpha forced opaque.
- Settings UI: move the Verbose logging checkbox off the wallet row into a new
  "Debug options" button that opens a dialog housing the verbose toggle + a "Run
  screenshot sweep" button. New i18n keys.

Both platforms build; no-crash smoke verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-04 17:41:49 -05:00
parent a523611779
commit dddf1b6ec7
6 changed files with 236 additions and 9 deletions

View File

@@ -150,6 +150,7 @@ struct SettingsPageState {
bool confirm_clear_ztx = false;
bool confirm_delete_blockchain = false;
bool confirm_rescan = false;
bool debug_options_open = false;
// Rescan dialog: probe the node's available block range so a bootstrapped/pruned node gets a
// runtime rescan from a snapshot-available height instead of the (failing) -rescan-from-genesis.
bool rescan_height_detecting = false;
@@ -1186,7 +1187,7 @@ void RenderSettingsPage(App* app) {
totalW += cbW(TR("keep_daemon")) + cbSpacing
+ cbW(TR("stop_external")) + cbSpacing;
}
totalW += cbW(TR("verbose_logging"));
// (Verbose logging moved into the Debug options dialog below.)
float scale = (totalW > contentW) ? contentW / totalW : 1.0f;
if (scale < 1.0f) ImGui::SetWindowFontScale(scale);
float sp = cbSpacing * scale;
@@ -1213,19 +1214,18 @@ void RenderSettingsPage(App* app) {
if (ImGui::IsItemHovered())
material::Tooltip("%s", TR("tt_stop_external"));
}
ImGui::SameLine(0, sp);
if (ImGui::Checkbox(TrId("verbose_logging", "verbose").c_str(), &s_settingsState.verbose_logging)) {
dragonx::util::Logger::instance().setVerbose(s_settingsState.verbose_logging);
saveSettingsPageState(app->settings());
}
if (ImGui::IsItemHovered())
material::Tooltip("%s", TR("tt_verbose"));
if (scale < 1.0f) ImGui::SetWindowFontScale(1.0f);
}
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
// Debug options — a button that opens a small dialog (verbose logging + screenshot sweep).
if (TactileButton(TR("debug_options"), ImVec2(0, 0), S.resolveFont("button")))
s_settingsState.debug_options_open = true;
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
// --- Collapsible: Tools & Actions... ---
material::CollapsibleHeader(dl, "##ToolsToggle", TR("tools_actions"),
s_settingsState.tools_expanded, contentW,
@@ -2580,6 +2580,26 @@ void RenderSettingsPage(App* app) {
ImGui::EndChild(); // ##SettingsPageScroll
// Debug options dialog — verbose logging toggle + the theme/tab screenshot sweep.
if (s_settingsState.debug_options_open) {
if (BeginOverlayDialog(TR("debug_options_title"), &s_settingsState.debug_options_open, 460.0f, 0.94f)) {
if (ImGui::Checkbox(TrId("verbose_logging", "dbg_verbose").c_str(), &s_settingsState.verbose_logging)) {
dragonx::util::Logger::instance().setVerbose(s_settingsState.verbose_logging);
saveSettingsPageState(app->settings());
}
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("tt_verbose"));
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
ImGui::TextWrapped("%s", TR("screenshot_sweep_desc"));
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
if (TactileButton(TR("screenshot_sweep"), ImVec2(0, 0), S.resolveFont("button"))) {
app->startScreenshotSweep();
s_settingsState.debug_options_open = false;
}
EndOverlayDialog();
}
}
// Confirmation dialog for clearing z-tx history
if (s_settingsState.confirm_clear_ztx) {
if (BeginOverlayDialog(TR("confirm_clear_ztx_title"), &s_settingsState.confirm_clear_ztx, 480.0f, 0.94f)) {