feat(debug): per-tab screenshot subfolders + overwrite + Open location button

- Organize sweep output into per-tab subfolders: <config>/screenshots/<tab>/<skin>.png
  (was one timestamped folder with idx_skin_tab.png names).
- Fixed folder (no timestamp): subsequent sweeps overwrite the existing PNGs in
  place instead of creating a new directory each run.
- Add an "Open location" TactileButton next to "Run screenshot sweep" that opens
  the screenshots folder via Platform::openFolder(app->screenshotDir()).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-04 17:58:47 -05:00
parent 0d4eaa02e7
commit 4c466d78d1
4 changed files with 19 additions and 14 deletions

View File

@@ -317,6 +317,7 @@ public:
bool wantsScreenshotThisFrame() const { return sweep_capture_this_frame_; }
const std::string& screenshotSweepPath() const { return sweep_current_path_; }
void onScreenshotCaptured();
std::string screenshotDir() const; // <config>/screenshots (fixed; sweeps overwrite in place)
// Dialog triggers (used by settings page to open modal dialogs)
void showImportKeyDialog() { show_import_key_ = true; }

View File

@@ -766,6 +766,11 @@ static const char* sweepPageName(ui::NavPage page)
}
}
std::string App::screenshotDir() const
{
return (std::filesystem::path(util::Platform::getObsidianDragonDir()) / "screenshots").string();
}
void App::startScreenshotSweep()
{
if (screenshot_sweep_active_) return;
@@ -780,14 +785,10 @@ void App::startScreenshotSweep()
}
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();
// Fixed output folder (organized into per-tab subfolders below); subsequent sweeps overwrite the
// existing PNGs in place rather than creating a new folder each time.
sweep_dir_ = screenshotDir();
std::error_code ec; std::filesystem::create_directories(sweep_dir_, ec);
sweep_saved_skin_ = ui::schema::SkinManager::instance().activeSkinId();
sweep_saved_page_ = current_page_;
@@ -806,11 +807,10 @@ 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();
// Organized as <screenshots>/<tab>/<skin>.png — one subfolder per tab, one PNG per theme,
// overwritten in place on the next sweep. (writePng in main.cpp creates the parent subfolder.)
sweep_current_path_ = (std::filesystem::path(sweep_dir_) / sweepPageName(current_page_)
/ (sweep_skins_[sweep_skin_idx_] + ".png")).string();
sweep_settle_frames_ = 4; // let the new skin (TOML reload / acrylic recapture) + page settle
sweep_capture_this_frame_ = false;
}

View File

@@ -2463,6 +2463,9 @@ void RenderSettingsPage(App* app) {
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
if (TactileButton(TR("screenshot_sweep"), ImVec2(0, 0), S.resolveFont("button")))
app->startScreenshotSweep();
ImGui::SameLine();
if (TactileButton(TR("screenshot_open_dir"), ImVec2(0, 0), S.resolveFont("button")))
util::Platform::openFolder(app->screenshotDir());
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
ImGui::Separator();
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));

View File

@@ -254,7 +254,8 @@ void I18n::loadBuiltinEnglish()
strings_["stop_external"] = "Stop external daemon";
strings_["verbose_logging"] = "Verbose logging";
strings_["screenshot_sweep"] = "Run screenshot sweep";
strings_["screenshot_sweep_desc"] = "Cycles every theme across every tab and saves a screenshot of each to a timestamped folder in the config directory. Runs for a few seconds; the path is shown when it finishes.";
strings_["screenshot_open_dir"] = "Open location";
strings_["screenshot_sweep_desc"] = "Cycles every theme across every tab and saves a screenshot of each into per-tab subfolders under the config directory's screenshots folder (overwriting the previous sweep). Runs for a few seconds.";
strings_["mine_when_idle"] = "Mine when idle";
strings_["setup_wizard"] = "Run Setup Wizard...";