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:
@@ -40,6 +40,7 @@
|
||||
#include "daemon/xmrig_manager.h"
|
||||
#include "util/pool_registry.h"
|
||||
#include "ui/notifications.h"
|
||||
#include "ui/schema/skin_manager.h"
|
||||
#include "default_banlist_embedded.h"
|
||||
#include "util/amount_format.h"
|
||||
#include "util/http_download.h"
|
||||
@@ -53,6 +54,7 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
@@ -741,6 +743,108 @@ void App::setCurrentPage(ui::NavPage page)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Debug screenshot sweep ──────────────────────────────────────────────────
|
||||
// Cycle every skin x every build-enabled tab, saving one PNG per (skin,tab). Driven from
|
||||
// App::render() (updateScreenshotSweep pins the page + settles); main.cpp reads the framebuffer
|
||||
// on the settled frame and calls onScreenshotCaptured() to advance.
|
||||
|
||||
// Filesystem-safe one-word page name (tracePageName returns "Overview tab" etc.).
|
||||
static const char* sweepPageName(ui::NavPage page)
|
||||
{
|
||||
switch (page) {
|
||||
case ui::NavPage::Overview: return "overview";
|
||||
case ui::NavPage::Send: return "send";
|
||||
case ui::NavPage::Receive: return "receive";
|
||||
case ui::NavPage::History: return "history";
|
||||
case ui::NavPage::Mining: return "mining";
|
||||
case ui::NavPage::Market: return "market";
|
||||
case ui::NavPage::Console: return "console";
|
||||
case ui::NavPage::Peers: return "network";
|
||||
case ui::NavPage::Explorer: return "explorer";
|
||||
case ui::NavPage::Settings: return "settings";
|
||||
default: return "page";
|
||||
}
|
||||
}
|
||||
|
||||
void App::startScreenshotSweep()
|
||||
{
|
||||
if (screenshot_sweep_active_) return;
|
||||
|
||||
sweep_skins_.clear();
|
||||
for (const auto& s : ui::schema::SkinManager::instance().available())
|
||||
if (s.valid) sweep_skins_.push_back(s.id);
|
||||
sweep_pages_.clear();
|
||||
for (int p = 0; p < static_cast<int>(ui::NavPage::Count_); ++p) {
|
||||
ui::NavPage pg = static_cast<ui::NavPage>(p);
|
||||
if (isPageEnabledForBuild(pg)) sweep_pages_.push_back(pg);
|
||||
}
|
||||
if (sweep_skins_.empty() || sweep_pages_.empty()) return;
|
||||
|
||||
// Timestamped output folder under the config dir.
|
||||
std::time_t now = std::time(nullptr);
|
||||
char stamp[32] = "sweep";
|
||||
if (std::tm* tmv = std::localtime(&now)) std::strftime(stamp, sizeof(stamp), "%Y%m%d_%H%M%S", tmv);
|
||||
namespace fs = std::filesystem;
|
||||
fs::path dir = fs::path(util::Platform::getObsidianDragonDir()) / "screenshots" / (std::string("sweep_") + stamp);
|
||||
std::error_code ec; fs::create_directories(dir, ec);
|
||||
sweep_dir_ = dir.string();
|
||||
|
||||
sweep_saved_skin_ = ui::schema::SkinManager::instance().activeSkinId();
|
||||
sweep_saved_page_ = current_page_;
|
||||
sweep_skin_idx_ = 0; sweep_page_idx_ = 0;
|
||||
screenshot_sweep_active_ = true;
|
||||
sweep_capture_this_frame_ = false;
|
||||
|
||||
ui::schema::SkinManager::instance().setActiveSkin(sweep_skins_[0]);
|
||||
applySweepTarget();
|
||||
ui::Notifications::instance().info("Screenshot sweep running…");
|
||||
DEBUG_LOGF("[Sweep] -> %s (%d skins x %d pages)\n",
|
||||
sweep_dir_.c_str(), (int)sweep_skins_.size(), (int)sweep_pages_.size());
|
||||
}
|
||||
|
||||
void App::applySweepTarget()
|
||||
{
|
||||
current_page_ = sweep_pages_[sweep_page_idx_];
|
||||
page_alpha_ = 1.0f; // skip the page-switch fade so the shot isn't captured mid-animation
|
||||
int idx = sweep_skin_idx_ * static_cast<int>(sweep_pages_.size()) + sweep_page_idx_;
|
||||
char name[160];
|
||||
snprintf(name, sizeof(name), "%03d_%s_%s.png", idx,
|
||||
sweep_skins_[sweep_skin_idx_].c_str(), sweepPageName(current_page_));
|
||||
sweep_current_path_ = (std::filesystem::path(sweep_dir_) / name).string();
|
||||
sweep_settle_frames_ = 4; // let the new skin (TOML reload / acrylic recapture) + page settle
|
||||
sweep_capture_this_frame_ = false;
|
||||
}
|
||||
|
||||
void App::updateScreenshotSweep()
|
||||
{
|
||||
if (!screenshot_sweep_active_) return;
|
||||
current_page_ = sweep_pages_[sweep_page_idx_]; // keep the page pinned each frame
|
||||
page_alpha_ = 1.0f;
|
||||
if (sweep_settle_frames_ > 0) { sweep_settle_frames_--; sweep_capture_this_frame_ = false; }
|
||||
else sweep_capture_this_frame_ = true; // settled — main.cpp captures this frame
|
||||
}
|
||||
|
||||
void App::onScreenshotCaptured()
|
||||
{
|
||||
sweep_capture_this_frame_ = false;
|
||||
if (!screenshot_sweep_active_) return;
|
||||
if (++sweep_page_idx_ >= static_cast<int>(sweep_pages_.size())) {
|
||||
sweep_page_idx_ = 0;
|
||||
if (++sweep_skin_idx_ >= static_cast<int>(sweep_skins_.size())) {
|
||||
// Done — restore the original skin + page.
|
||||
ui::schema::SkinManager::instance().setActiveSkin(sweep_saved_skin_);
|
||||
current_page_ = sweep_saved_page_;
|
||||
page_alpha_ = 1.0f;
|
||||
screenshot_sweep_active_ = false;
|
||||
ui::Notifications::instance().success("Screenshots saved to " + sweep_dir_);
|
||||
DEBUG_LOGF("[Sweep] done -> %s\n", sweep_dir_.c_str());
|
||||
return;
|
||||
}
|
||||
ui::schema::SkinManager::instance().setActiveSkin(sweep_skins_[sweep_skin_idx_]);
|
||||
}
|
||||
applySweepTarget();
|
||||
}
|
||||
|
||||
bool App::shouldRefreshTransactions() const
|
||||
{
|
||||
// NOTE: this is block-height / dirty driven, NOT interval-gated. It returns true only when a new
|
||||
|
||||
Reference in New Issue
Block a user