Files
XCEngine/new_editor/app/Platform/Win32/EditorWindowScreenshotController.cpp

210 lines
6.5 KiB
C++
Raw Normal View History

#include "Platform/Win32/EditorWindowScreenshotController.h"
#include "Support/ExecutablePath.h"
#include <chrono>
#include <cstdio>
#include <sstream>
#include <system_error>
namespace XCEngine::UI::Editor::App {
namespace {
2026-04-10 00:41:28 +08:00
std::filesystem::path ResolveBuildCaptureRoot(const std::filesystem::path& requestedCaptureRoot) {
std::filesystem::path captureRoot = App::GetExecutableDirectory() / "captures";
2026-04-10 00:41:28 +08:00
const std::filesystem::path scenarioPath = requestedCaptureRoot.parent_path().filename();
if (!scenarioPath.empty() && scenarioPath != "captures") {
captureRoot /= scenarioPath;
}
return captureRoot.lexically_normal();
}
} // namespace
void EditorWindowScreenshotController::Initialize(const std::filesystem::path& captureRoot) {
2026-04-10 00:41:28 +08:00
m_captureRoot = ResolveBuildCaptureRoot(captureRoot);
m_historyRoot = (m_captureRoot / "history").lexically_normal();
m_latestCapturePath = (m_captureRoot / "latest.png").lexically_normal();
2026-04-22 02:14:26 +08:00
m_activeHistoryCapturePath.clear();
m_captureCount = 0;
m_capturePending = false;
m_pendingReason.clear();
2026-04-10 00:41:28 +08:00
m_lastCaptureSummary = "Output: " + m_captureRoot.string();
m_lastCaptureError.clear();
}
void EditorWindowScreenshotController::Shutdown() {
2026-04-22 02:14:26 +08:00
m_activeHistoryCapturePath.clear();
m_capturePending = false;
m_pendingReason.clear();
}
void EditorWindowScreenshotController::RequestCapture(std::string reason) {
m_pendingReason = reason.empty() ? "capture" : std::move(reason);
m_capturePending = true;
}
bool EditorWindowScreenshotController::TryBeginCapture(std::filesystem::path& outHistoryPath) {
2026-04-22 02:14:26 +08:00
outHistoryPath.clear();
if (!m_capturePending) {
2026-04-22 02:14:26 +08:00
return false;
}
std::error_code errorCode = {};
std::filesystem::create_directories(m_captureRoot, errorCode);
if (errorCode) {
m_lastCaptureError = "Failed to create screenshot directory: " + m_captureRoot.string();
m_lastCaptureSummary = "AutoShot failed";
2026-04-22 02:14:26 +08:00
ResetPendingRequest();
return false;
}
std::filesystem::create_directories(m_historyRoot, errorCode);
if (errorCode) {
m_lastCaptureError = "Failed to create screenshot directory: " + m_historyRoot.string();
m_lastCaptureSummary = "AutoShot failed";
2026-04-22 02:14:26 +08:00
ResetPendingRequest();
return false;
}
m_activeHistoryCapturePath = BuildHistoryCapturePath(m_pendingReason);
outHistoryPath = m_activeHistoryCapturePath;
return true;
}
void EditorWindowScreenshotController::CompleteCaptureSuccess(
const std::filesystem::path& historyPath) {
2026-04-22 02:14:26 +08:00
const std::filesystem::path resolvedHistoryPath =
historyPath.empty() ? m_activeHistoryCapturePath : historyPath;
if (resolvedHistoryPath.empty()) {
CompleteCaptureFailure("Capture completed without a valid history path.");
return;
}
2026-04-22 02:14:26 +08:00
std::error_code errorCode = {};
const std::uintmax_t historyFileSize =
std::filesystem::file_size(resolvedHistoryPath, errorCode);
if (errorCode || historyFileSize == 0u) {
CompleteCaptureFailure("Capture completed without a valid PNG payload.");
return;
}
errorCode.clear();
std::filesystem::copy_file(
2026-04-22 02:14:26 +08:00
resolvedHistoryPath,
m_latestCapturePath,
std::filesystem::copy_options::overwrite_existing,
errorCode);
if (errorCode) {
m_lastCaptureError = "Failed to update latest screenshot: " + m_latestCapturePath.string();
m_lastCaptureSummary = "AutoShot failed";
2026-04-22 02:14:26 +08:00
ResetPendingRequest();
return;
}
++m_captureCount;
m_lastCaptureError.clear();
m_lastCaptureSummary =
2026-04-22 02:14:26 +08:00
"Shot: latest.png | " + resolvedHistoryPath.filename().string();
ResetPendingRequest();
}
void EditorWindowScreenshotController::CompleteCaptureFailure(std::string error) {
2026-04-22 02:14:26 +08:00
if (!m_activeHistoryCapturePath.empty()) {
std::error_code deleteError = {};
std::filesystem::remove(m_activeHistoryCapturePath, deleteError);
}
m_lastCaptureError = error.empty()
? "Screenshot capture failed."
: std::move(error);
m_lastCaptureSummary = "AutoShot failed";
ResetPendingRequest();
}
bool EditorWindowScreenshotController::HasPendingCapture() const {
return m_capturePending;
}
const std::filesystem::path& EditorWindowScreenshotController::GetLatestCapturePath() const {
return m_latestCapturePath;
}
const std::string& EditorWindowScreenshotController::GetLastCaptureSummary() const {
return m_lastCaptureSummary;
}
const std::string& EditorWindowScreenshotController::GetLastCaptureError() const {
return m_lastCaptureError;
}
void EditorWindowScreenshotController::ResetPendingRequest() {
2026-04-22 02:14:26 +08:00
m_capturePending = false;
m_pendingReason.clear();
m_activeHistoryCapturePath.clear();
}
std::filesystem::path EditorWindowScreenshotController::BuildHistoryCapturePath(
std::string_view reason) const {
std::ostringstream filename;
filename << BuildTimestampString()
<< '_'
<< (m_captureCount + 1u)
<< '_'
<< SanitizeReason(reason)
<< ".png";
return (m_historyRoot / filename.str()).lexically_normal();
}
std::string EditorWindowScreenshotController::BuildTimestampString() {
const auto now = std::chrono::system_clock::now();
const std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::tm localTime = {};
localtime_s(&localTime, &currentTime);
char buffer[32] = {};
std::snprintf(
buffer,
sizeof(buffer),
"%04d%02d%02d_%02d%02d%02d",
localTime.tm_year + 1900,
localTime.tm_mon + 1,
localTime.tm_mday,
localTime.tm_hour,
localTime.tm_min,
localTime.tm_sec);
return buffer;
}
std::string EditorWindowScreenshotController::SanitizeReason(std::string_view reason) {
std::string sanitized = {};
sanitized.reserve(reason.size());
bool lastWasSeparator = false;
for (const unsigned char value : reason) {
if (std::isalnum(value)) {
sanitized.push_back(static_cast<char>(std::tolower(value)));
lastWasSeparator = false;
continue;
}
if (!lastWasSeparator) {
sanitized.push_back('_');
lastWasSeparator = true;
}
}
while (!sanitized.empty() && sanitized.front() == '_') {
sanitized.erase(sanitized.begin());
}
while (!sanitized.empty() && sanitized.back() == '_') {
sanitized.pop_back();
}
return sanitized.empty() ? "capture" : sanitized;
}
} // namespace XCEngine::UI::Editor::App