Notify about saved screenshot

Show message about saved screenshot via schedule message box. Since screenshot
saving happens not in the main thread calling messageBox directly is unsafe.
WindowManager::scheduleMessageBox delays message box showing until next update
in the main thread.
dont-compose-content
elsid 4 years ago
parent f7a6be053d
commit 5103120eef
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -218,6 +218,14 @@ namespace
if (Settings::Manager::getInt("async num threads", "Physics") == 0)
profiler.removeUserStatsLine(" -Async");
}
struct ScheduleNonDialogMessageBox
{
void operator()(std::string message) const
{
MWBase::Environment::get().getWindowManager()->scheduleMessageBox(std::move(message), MWGui::ShowInDialogueMode_Never);
}
};
}
void OMW::Engine::executeLocalScripts()
@ -676,7 +684,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mWorkQueue,
new SceneUtil::WriteScreenshotToFileOperation(
mCfgMgr.getScreenshotPath().string(),
Settings::Manager::getString("screenshot format", "General")
Settings::Manager::getString("screenshot format", "General"),
ScheduleNonDialogMessageBox {}
)
);

@ -228,6 +228,8 @@ namespace MWBase
virtual void exitCurrentGuiMode() = 0;
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
/// Puts message into a queue to show on the next update. Thread safe alternative for messageBox.
virtual void scheduleMessageBox(std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;
virtual void staticMessageBox(const std::string& message) = 0;
virtual void removeStaticMessageBox() = 0;
virtual void interactiveMessageBox (const std::string& message,

@ -749,6 +749,11 @@ namespace MWGui
}
}
void WindowManager::scheduleMessageBox(std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode)
{
mScheduledMessageBoxes.lock()->emplace_back(std::move(message), showInDialogueMode);
}
void WindowManager::staticMessageBox(const std::string& message)
{
mMessageBoxManager->createMessageBox(message, true);
@ -803,6 +808,8 @@ namespace MWGui
void WindowManager::update (float frameDuration)
{
handleScheduledMessageBoxes();
bool gameRunning = MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame;
@ -2204,4 +2211,12 @@ namespace MWGui
{
return mVersionDescription;
}
void WindowManager::handleScheduledMessageBoxes()
{
const auto scheduledMessageBoxes = mScheduledMessageBoxes.lock();
for (const ScheduledMessageBox& v : *scheduledMessageBoxes)
messageBox(v.mMessage, v.mShowInDialogueMode);
scheduledMessageBoxes->clear();
}
}

@ -8,6 +8,7 @@
**/
#include <stack>
#include <vector>
#include <osg/ref_ptr>
@ -16,6 +17,7 @@
#include <components/sdlutil/events.hpp>
#include <components/settings/settings.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include <components/misc/guarded.hpp>
#include "mapwindow.hpp"
#include "statswatcher.hpp"
@ -264,6 +266,7 @@ namespace MWGui
void exitCurrentGuiMode() override;
void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) override;
void scheduleMessageBox (std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) override;
void staticMessageBox(const std::string& message) override;
void removeStaticMessageBox() override;
void interactiveMessageBox (const std::string& message,
@ -524,6 +527,17 @@ namespace MWGui
float mScalingFactor;
struct ScheduledMessageBox
{
std::string mMessage;
MWGui::ShowInDialogueMode mShowInDialogueMode;
ScheduledMessageBox(std::string&& message, MWGui::ShowInDialogueMode showInDialogueMode)
: mMessage(std::move(message)), mShowInDialogueMode(showInDialogueMode) {}
};
Misc::ScopeGuarded<std::vector<ScheduledMessageBox>> mScheduledMessageBoxes;
/**
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
* Supported syntax:
@ -555,6 +569,8 @@ namespace MWGui
void updatePinnedWindows();
void enableScene(bool enable);
void handleScheduledMessageBoxes();
};
}

@ -51,59 +51,74 @@ namespace
namespace SceneUtil
{
void writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
const osg::Image& image)
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
const osg::Image& image)
{
// Count screenshots.
int shotCount = 0;
// Find the first unused filename with a do-while
std::ostringstream stream;
std::string lastFileName;
std::string lastFilePath;
do
{
// Reset the stream
stream.str("");
stream.clear();
stream << screenshotPath << "/screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << screenshotFormat;
stream << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << screenshotFormat;
} while (boost::filesystem::exists(stream.str()));
lastFileName = stream.str();
lastFilePath = screenshotPath + "/" + lastFileName;
} while (boost::filesystem::exists(lastFilePath));
boost::filesystem::ofstream outStream;
outStream.open(boost::filesystem::path(stream.str()), std::ios::binary);
outStream.open(boost::filesystem::path(std::move(lastFilePath)), std::ios::binary);
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(screenshotFormat);
if (!readerwriter)
{
Log(Debug::Error) << "Error: Can't write screenshot, no '" << screenshotFormat << "' readerwriter found";
return;
return std::string();
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
if (!result.success())
{
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
return std::string();
}
return lastFileName;
}
WriteScreenshotToFileOperation::WriteScreenshotToFileOperation(const std::string& screenshotPath,
const std::string& screenshotFormat)
const std::string& screenshotFormat,
std::function<void (std::string)> callback)
: mScreenshotPath(screenshotPath)
, mScreenshotFormat(screenshotFormat)
, mCallback(callback)
{
}
void WriteScreenshotToFileOperation::operator()(const osg::Image& image, const unsigned int /*context_id*/)
{
std::string fileName;
try
{
writeScreenshotToFile(mScreenshotPath, mScreenshotFormat, image);
fileName = writeScreenshotToFile(mScreenshotPath, mScreenshotFormat, image);
}
catch (const std::exception& e)
{
Log(Debug::Error) << "Failed to write screenshot to file with path=\"" << mScreenshotPath
<< "\", format=\"" << mScreenshotFormat << "\": " << e.what();
}
if (fileName.empty())
mCallback("Failed to save screenshot");
else
mCallback(fileName + " has been saved");
}
AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr<WorkQueue> queue,

@ -15,19 +15,21 @@ namespace SceneUtil
{
class WorkQueue;
void writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
const osg::Image& image);
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
const osg::Image& image);
class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
{
public:
WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat);
WriteScreenshotToFileOperation(const std::string& screenshotPath, const std::string& screenshotFormat,
std::function<void (std::string)> callback);
void operator()(const osg::Image& image, const unsigned int context_id) override;
private:
const std::string mScreenshotPath;
const std::string mScreenshotFormat;
const std::function<void (std::string)> mCallback;
};
class AsyncScreenCaptureOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation

Loading…
Cancel
Save