mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-27 03:40:24 +00:00
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.
This commit is contained in:
parent
f7a6be053d
commit
5103120eef
6 changed files with 71 additions and 12 deletions
|
@ -218,6 +218,14 @@ namespace
|
||||||
if (Settings::Manager::getInt("async num threads", "Physics") == 0)
|
if (Settings::Manager::getInt("async num threads", "Physics") == 0)
|
||||||
profiler.removeUserStatsLine(" -Async");
|
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()
|
void OMW::Engine::executeLocalScripts()
|
||||||
|
@ -676,7 +684,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mWorkQueue,
|
mWorkQueue,
|
||||||
new SceneUtil::WriteScreenshotToFileOperation(
|
new SceneUtil::WriteScreenshotToFileOperation(
|
||||||
mCfgMgr.getScreenshotPath().string(),
|
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 exitCurrentGuiMode() = 0;
|
||||||
|
|
||||||
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 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 staticMessageBox(const std::string& message) = 0;
|
||||||
virtual void removeStaticMessageBox() = 0;
|
virtual void removeStaticMessageBox() = 0;
|
||||||
virtual void interactiveMessageBox (const std::string& message,
|
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)
|
void WindowManager::staticMessageBox(const std::string& message)
|
||||||
{
|
{
|
||||||
mMessageBoxManager->createMessageBox(message, true);
|
mMessageBoxManager->createMessageBox(message, true);
|
||||||
|
@ -803,6 +808,8 @@ namespace MWGui
|
||||||
|
|
||||||
void WindowManager::update (float frameDuration)
|
void WindowManager::update (float frameDuration)
|
||||||
{
|
{
|
||||||
|
handleScheduledMessageBoxes();
|
||||||
|
|
||||||
bool gameRunning = MWBase::Environment::get().getStateManager()->getState()!=
|
bool gameRunning = MWBase::Environment::get().getStateManager()->getState()!=
|
||||||
MWBase::StateManager::State_NoGame;
|
MWBase::StateManager::State_NoGame;
|
||||||
|
|
||||||
|
@ -2204,4 +2211,12 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
return mVersionDescription;
|
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 <stack>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
#include <components/sdlutil/events.hpp>
|
#include <components/sdlutil/events.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
#include <components/misc/guarded.hpp>
|
||||||
|
|
||||||
#include "mapwindow.hpp"
|
#include "mapwindow.hpp"
|
||||||
#include "statswatcher.hpp"
|
#include "statswatcher.hpp"
|
||||||
|
@ -264,6 +266,7 @@ namespace MWGui
|
||||||
void exitCurrentGuiMode() override;
|
void exitCurrentGuiMode() override;
|
||||||
|
|
||||||
void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) 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 staticMessageBox(const std::string& message) override;
|
||||||
void removeStaticMessageBox() override;
|
void removeStaticMessageBox() override;
|
||||||
void interactiveMessageBox (const std::string& message,
|
void interactiveMessageBox (const std::string& message,
|
||||||
|
@ -524,6 +527,17 @@ namespace MWGui
|
||||||
|
|
||||||
float mScalingFactor;
|
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.
|
* 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:
|
* Supported syntax:
|
||||||
|
@ -555,6 +569,8 @@ namespace MWGui
|
||||||
void updatePinnedWindows();
|
void updatePinnedWindows();
|
||||||
|
|
||||||
void enableScene(bool enable);
|
void enableScene(bool enable);
|
||||||
|
|
||||||
|
void handleScheduledMessageBoxes();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,59 +51,74 @@ namespace
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
void writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
|
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
|
||||||
const osg::Image& image)
|
const osg::Image& image)
|
||||||
{
|
{
|
||||||
// Count screenshots.
|
// Count screenshots.
|
||||||
int shotCount = 0;
|
int shotCount = 0;
|
||||||
|
|
||||||
// Find the first unused filename with a do-while
|
// Find the first unused filename with a do-while
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
std::string lastFileName;
|
||||||
|
std::string lastFilePath;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Reset the stream
|
// Reset the stream
|
||||||
stream.str("");
|
stream.str("");
|
||||||
stream.clear();
|
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;
|
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);
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(screenshotFormat);
|
||||||
if (!readerwriter)
|
if (!readerwriter)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Error: Can't write screenshot, no '" << screenshotFormat << "' readerwriter found";
|
Log(Debug::Error) << "Error: Can't write screenshot, no '" << screenshotFormat << "' readerwriter found";
|
||||||
return;
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
|
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
|
||||||
if (!result.success())
|
if (!result.success())
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
|
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return lastFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteScreenshotToFileOperation::WriteScreenshotToFileOperation(const std::string& screenshotPath,
|
WriteScreenshotToFileOperation::WriteScreenshotToFileOperation(const std::string& screenshotPath,
|
||||||
const std::string& screenshotFormat)
|
const std::string& screenshotFormat,
|
||||||
|
std::function<void (std::string)> callback)
|
||||||
: mScreenshotPath(screenshotPath)
|
: mScreenshotPath(screenshotPath)
|
||||||
, mScreenshotFormat(screenshotFormat)
|
, mScreenshotFormat(screenshotFormat)
|
||||||
|
, mCallback(callback)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteScreenshotToFileOperation::operator()(const osg::Image& image, const unsigned int /*context_id*/)
|
void WriteScreenshotToFileOperation::operator()(const osg::Image& image, const unsigned int /*context_id*/)
|
||||||
{
|
{
|
||||||
|
std::string fileName;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
writeScreenshotToFile(mScreenshotPath, mScreenshotFormat, image);
|
fileName = writeScreenshotToFile(mScreenshotPath, mScreenshotFormat, image);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "Failed to write screenshot to file with path=\"" << mScreenshotPath
|
Log(Debug::Error) << "Failed to write screenshot to file with path=\"" << mScreenshotPath
|
||||||
<< "\", format=\"" << mScreenshotFormat << "\": " << e.what();
|
<< "\", 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,
|
AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr<WorkQueue> queue,
|
||||||
|
|
|
@ -15,19 +15,21 @@ namespace SceneUtil
|
||||||
{
|
{
|
||||||
class WorkQueue;
|
class WorkQueue;
|
||||||
|
|
||||||
void writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
|
std::string writeScreenshotToFile(const std::string& screenshotPath, const std::string& screenshotFormat,
|
||||||
const osg::Image& image);
|
const osg::Image& image);
|
||||||
|
|
||||||
class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
class WriteScreenshotToFileOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
||||||
{
|
{
|
||||||
public:
|
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;
|
void operator()(const osg::Image& image, const unsigned int context_id) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string mScreenshotPath;
|
const std::string mScreenshotPath;
|
||||||
const std::string mScreenshotFormat;
|
const std::string mScreenshotFormat;
|
||||||
|
const std::function<void (std::string)> mCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncScreenCaptureOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
class AsyncScreenCaptureOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation
|
||||||
|
|
Loading…
Reference in a new issue