diff --git a/include/imessagebus.h b/include/imessagebus.h index 2751fc2e5e..ebb49c9b3d 100644 --- a/include/imessagebus.h +++ b/include/imessagebus.h @@ -45,6 +45,7 @@ class IMessage GameConfigNeeded, LongRunningOperation, MapFileOperation, + MapOperationFinished, FileSelectionRequest, Notification, TextureChanged, diff --git a/include/iundo.h b/include/iundo.h index cba45179e1..81ac01fb7a 100644 --- a/include/iundo.h +++ b/include/iundo.h @@ -94,7 +94,7 @@ class IUndoSystem /** * Observer implementation which gets notified - * on undo/redo perations. + * on undo/redo operations. */ class Tracker { diff --git a/include/ui/istatusbarmanager.h b/include/ui/istatusbarmanager.h index 42d04f805d..3348a1a3fd 100644 --- a/include/ui/istatusbarmanager.h +++ b/include/ui/istatusbarmanager.h @@ -11,18 +11,19 @@ namespace statusbar { // Use these positions to place the status bar elements in between -// the default ones. A position of 31 would put a widget in between -// StandardPosition::MapStatistics and StandardPosition::ShaderClipboard. +// the default ones. A position of 32 would put a widget in between +// StandardPosition::GridSize and StandardPosition::OrthoViewPosition. struct StandardPosition { enum { Front = 0, - MapStatistics = 10, - GridSize = 20, - OrthoViewPosition = 30, - ShaderClipboard = 40, - MapEditStopwatch = 50, + Commands = 10, + MapStatistics = 20, + GridSize = 30, + OrthoViewPosition = 40, + ShaderClipboard = 50, + MapEditStopwatch = 60, Back = 9000, }; }; diff --git a/libs/messages/MapOperationMessage.h b/libs/messages/MapOperationMessage.h new file mode 100644 index 0000000000..f2c46c5cef --- /dev/null +++ b/libs/messages/MapOperationMessage.h @@ -0,0 +1,41 @@ +#pragma once + +#include "iradiant.h" +#include "imessagebus.h" + +namespace map +{ + +/** + * Message sent when an operation affecting the loaded map is finished. + * This can be an ordinary edit operation, loading, saving, or an undo/redo step. + */ +class OperationMessage : + public radiant::IMessage +{ +private: + std::string _message; + +public: + OperationMessage(const std::string& message) : + _message(message) + {} + + std::size_t getId() const override + { + return IMessage::Type::MapOperationFinished; + } + + const std::string& getMessage() const + { + return _message; + } + + static void Send(const std::string& message) + { + OperationMessage msg(message); + GlobalRadiantCore().getMessageBus().sendMessage(msg); + } +}; + +} diff --git a/radiant/CMakeLists.txt b/radiant/CMakeLists.txt index f72f7e5757..d9fe794bcb 100644 --- a/radiant/CMakeLists.txt +++ b/radiant/CMakeLists.txt @@ -159,6 +159,7 @@ add_executable(darkradiant ui/script/ScriptWindow.cpp ui/selectionset/SelectionSetToolmenu.cpp ui/splash/Splash.cpp + ui/statusbar/CommandStatus.cpp ui/statusbar/EditingStopwatchStatus.cpp ui/statusbar/MapStatistics.cpp ui/statusbar/StatusBarManager.cpp diff --git a/radiant/ui/UserInterfaceModule.cpp b/radiant/ui/UserInterfaceModule.cpp index 64cc5a7186..8acf610175 100644 --- a/radiant/ui/UserInterfaceModule.cpp +++ b/radiant/ui/UserInterfaceModule.cpp @@ -213,6 +213,7 @@ void UserInterfaceModule::initialiseModule(const IApplicationContext& ctx) _mruMenu.reset(new MRUMenu); _shaderClipboardStatus.reset(new statusbar::ShaderClipboardStatus); _editStopwatchStatus.reset(new statusbar::EditingStopwatchStatus); + _commandStatus.reset(new statusbar::CommandStatus); _mapStatisticsStatus.reset(new statusbar::MapStatistics); _manipulatorToggle.reset(new ManipulatorToggle); _textureToolModeToggles.reset(new TexToolModeToggles); @@ -252,6 +253,7 @@ void UserInterfaceModule::shutdownModule() _shaderClipboardStatus.reset(); _mapStatisticsStatus.reset(); _editStopwatchStatus.reset(); + _commandStatus.reset(); _manipulatorToggle.reset(); _selectionModeToggle.reset(); _textureToolModeToggles.reset(); diff --git a/radiant/ui/UserInterfaceModule.h b/radiant/ui/UserInterfaceModule.h index 7b84dd0d34..a3d85e92bc 100644 --- a/radiant/ui/UserInterfaceModule.h +++ b/radiant/ui/UserInterfaceModule.h @@ -17,6 +17,7 @@ #include "SelectionModeToggle.h" #include "statusbar/ShaderClipboardStatus.h" #include "statusbar/EditingStopwatchStatus.h" +#include "statusbar/CommandStatus.h" #include "statusbar/MapStatistics.h" #include "messages/CommandExecutionFailed.h" #include "messages/TextureChanged.h" @@ -49,6 +50,7 @@ class UserInterfaceModule : std::unique_ptr _fileSaveConfirmationHandler; std::unique_ptr _shaderClipboardStatus; std::unique_ptr _editStopwatchStatus; + std::unique_ptr _commandStatus; std::unique_ptr _mapStatisticsStatus; std::unique_ptr _manipulatorToggle; std::unique_ptr _selectionModeToggle; diff --git a/radiant/ui/statusbar/CommandStatus.cpp b/radiant/ui/statusbar/CommandStatus.cpp new file mode 100644 index 0000000000..998376e99d --- /dev/null +++ b/radiant/ui/statusbar/CommandStatus.cpp @@ -0,0 +1,40 @@ +#include "CommandStatus.h" + +#include "ui/istatusbarmanager.h" +#include "iradiant.h" + +namespace ui +{ + +namespace statusbar +{ + +namespace +{ + const char* const STATUS_BAR_ELEMENT = "Commands"; +} + +CommandStatus::CommandStatus() +{ + _mapOperationListener = GlobalRadiantCore().getMessageBus().addListener( + radiant::IMessage::MapOperationFinished, + radiant::TypeListener( + sigc::mem_fun(this, &CommandStatus::onOperationFinished))); + + // Add the status bar element + GlobalStatusBarManager().addTextElement(STATUS_BAR_ELEMENT, "", StandardPosition::Commands, ""); +} + +CommandStatus::~CommandStatus() +{ + GlobalRadiantCore().getMessageBus().removeListener(_mapOperationListener); +} + +void CommandStatus::onOperationFinished(map::OperationMessage& message) +{ + GlobalStatusBarManager().setText(STATUS_BAR_ELEMENT, message.getMessage(), false); +} + +} + +} diff --git a/radiant/ui/statusbar/CommandStatus.h b/radiant/ui/statusbar/CommandStatus.h new file mode 100644 index 0000000000..21797a5e4d --- /dev/null +++ b/radiant/ui/statusbar/CommandStatus.h @@ -0,0 +1,32 @@ +#pragma once + +#include "iundo.h" +#include "imap.h" + +#include "messages/MapOperationMessage.h" + +namespace ui +{ + +namespace statusbar +{ + +/** + * Status bar widget displaying the most recently completed + * operation or any undo / redo activitiy. + */ +class CommandStatus final +{ +private: + std::size_t _mapOperationListener; + +public: + CommandStatus(); + ~CommandStatus(); + + void onOperationFinished(map::OperationMessage& message); +}; + +} + +} diff --git a/radiant/ui/statusbar/StatusBarManager.cpp b/radiant/ui/statusbar/StatusBarManager.cpp index 4c2e0db5ff..8bf10d0deb 100644 --- a/radiant/ui/statusbar/StatusBarManager.cpp +++ b/radiant/ui/statusbar/StatusBarManager.cpp @@ -241,7 +241,8 @@ void StatusBarManager::rebuildStatusBar() // A few default elements don't need to use 1 as proportion auto proportion = i->first == StandardPosition::MapStatistics || i->first == StandardPosition::GridSize || - i->first == StandardPosition::MapEditStopwatch || i->first == StandardPosition::OrthoViewPosition ? 0 : 1; + i->first == StandardPosition::MapEditStopwatch || i->first == StandardPosition::OrthoViewPosition || + i->first == StandardPosition::Commands ? 0 : 1; _statusBar->GetSizer()->Add(i->second->toplevel, proportion, flags, spacing); diff --git a/radiantcore/map/Map.cpp b/radiantcore/map/Map.cpp index dc6a1966f3..444d7397a4 100644 --- a/radiantcore/map/Map.cpp +++ b/radiantcore/map/Map.cpp @@ -44,6 +44,7 @@ #include "messages/ScopedLongRunningOperation.h" #include "messages/FileOverwriteConfirmation.h" #include "messages/FileSaveConfirmation.h" +#include "messages/MapOperationMessage.h" #include "selection/algorithm/Primitives.h" #include "selection/algorithm/Group.h" #include "scene/Group.h" @@ -174,6 +175,8 @@ void Map::loadMapResourceFromLocation(const MapLocation& location) // Map loading finished, emit the signal emitMapEvent(MapLoaded); + OperationMessage::Send(_("Map loaded")); + rMessage() << "--- LoadMapFile ---\n"; rMessage() << _mapName << "\n"; @@ -606,6 +609,7 @@ bool Map::save(const MapFormatPtr& mapFormat) } emitMapEvent(MapSaved); + OperationMessage::Send(_("Map saved")); _saveInProgress = false; @@ -626,6 +630,7 @@ void Map::createNewMap() setModified(false); + OperationMessage::Send(_("Empty Map created")); focusViews(Vector3(0,0,30), Vector3(0,0,0)); } diff --git a/tools/msvc/DarkRadiant.vcxproj b/tools/msvc/DarkRadiant.vcxproj index 16eb64814e..e4b83c0253 100644 --- a/tools/msvc/DarkRadiant.vcxproj +++ b/tools/msvc/DarkRadiant.vcxproj @@ -345,6 +345,7 @@ + @@ -561,6 +562,7 @@ + diff --git a/tools/msvc/DarkRadiant.vcxproj.filters b/tools/msvc/DarkRadiant.vcxproj.filters index 9a923b8115..ebeac2d2fc 100644 --- a/tools/msvc/DarkRadiant.vcxproj.filters +++ b/tools/msvc/DarkRadiant.vcxproj.filters @@ -715,6 +715,9 @@ src\selection + + src\ui\statusbar + @@ -1389,6 +1392,9 @@ src\ui + + src\ui\statusbar + diff --git a/tools/msvc/libs.vcxproj b/tools/msvc/libs.vcxproj index b4efd7bd2c..0e39261d0c 100644 --- a/tools/msvc/libs.vcxproj +++ b/tools/msvc/libs.vcxproj @@ -179,6 +179,7 @@ + diff --git a/tools/msvc/libs.vcxproj.filters b/tools/msvc/libs.vcxproj.filters index 52e927efcf..07d809eebe 100644 --- a/tools/msvc/libs.vcxproj.filters +++ b/tools/msvc/libs.vcxproj.filters @@ -326,6 +326,9 @@ selection + + messages +