diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 9651aaafbd..278c97f029 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -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 {} ) ); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 6e3c615de3..f256cc387e 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -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, diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1694206504..eebcf4b094 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -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(); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index ef411a39df..8c7e365ec7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -8,6 +8,7 @@ **/ #include +#include #include @@ -16,6 +17,7 @@ #include #include #include +#include #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> 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(); }; } diff --git a/components/sceneutil/screencapture.cpp b/components/sceneutil/screencapture.cpp index c010b390aa..47119f3644 100644 --- a/components/sceneutil/screencapture.cpp +++ b/components/sceneutil/screencapture.cpp @@ -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 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 queue, diff --git a/components/sceneutil/screencapture.hpp b/components/sceneutil/screencapture.hpp index 8087095e4e..6395d989d8 100644 --- a/components/sceneutil/screencapture.hpp +++ b/components/sceneutil/screencapture.hpp @@ -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 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 mCallback; }; class AsyncScreenCaptureOperation : public osgViewer::ScreenCaptureHandler::CaptureOperation