diff --git a/radiant/eventmanager/ModifierHintPopup.h b/radiant/eventmanager/ModifierHintPopup.h new file mode 100644 index 0000000000..ac5eb590a6 --- /dev/null +++ b/radiant/eventmanager/ModifierHintPopup.h @@ -0,0 +1,105 @@ +#pragma once + +#include + +namespace ui +{ + +class ModifierHintPopup : + public wxPopupWindow +{ +private: + wxStaticText* _text; + +public: + ModifierHintPopup(wxWindow* parent) : + wxPopupWindow(parent, wxBORDER_SIMPLE) + { + SetSizer(new wxBoxSizer(wxHORIZONTAL)); + + _text = new wxStaticText(this, wxID_ANY, _("Test")); + GetSizer()->Add(_text, 1, wxALL, 3); + + Layout(); + Fit(); + + Reposition(); + +#if 0 + // Subscribe to the parent window's visibility and iconise events to avoid + // the popup from lingering around long after the tree is gone (#5095) + auto* parentWindow = wxGetTopLevelParent(parent); + + if (parentWindow != nullptr) + { + parentWindow->Bind(wxEVT_SHOW, &SearchPopupWindow::_onParentVisibilityChanged, this); + parentWindow->Bind(wxEVT_ICONIZE, &SearchPopupWindow::_onParentMinimized, this); + + // Detect when the parent window is losing focus (e.g. by alt-tabbing) + parentWindow->Bind(wxEVT_ACTIVATE, &SearchPopupWindow::_onParentActivate, this); + + // Detect parent window movements to reposition ourselves + parentWindow->Bind(wxEVT_MOVE, &SearchPopupWindow::_onParentMoved, this); + } +#endif + } + + virtual ~ModifierHintPopup() + { + } + + void SetText(const wxString& text) + { + _text->SetLabelText(text); + + Layout(); + Fit(); + + Reposition(); + } + +private: + void Reposition() + { + // Position this control in the bottom left corner + wxPoint popupPos = GetParent()->GetScreenPosition() + wxSize(0, GetParent()->GetSize().y - GetSize().y); + Position(popupPos, wxSize(0, 0)); + } +#if 0 + void _onIdleClose(wxIdleEvent& ev) + { + _owner.Close(); + ev.Skip(); + } + + void _onParentActivate(wxActivateEvent& ev) + { + if (!ev.GetActive()) + { + _owner.Close(); + } + } + + void _onParentMoved(wxMoveEvent&) + { + Reposition(); + } + + void _onParentMinimized(wxIconizeEvent&) + { + // Close any searches when the parent window is minimized + _owner.Close(); + } + + void _onParentVisibilityChanged(wxShowEvent& ev) + { + if (!ev.IsShown()) + { + // Close any searches when the parent window is hidden + _owner.Close(); + } + } +#endif +}; + +} diff --git a/radiant/eventmanager/MouseToolManager.cpp b/radiant/eventmanager/MouseToolManager.cpp index 63e31f1706..13ee2d54a1 100644 --- a/radiant/eventmanager/MouseToolManager.cpp +++ b/radiant/eventmanager/MouseToolManager.cpp @@ -21,8 +21,11 @@ namespace } MouseToolManager::MouseToolManager() : - _activeModifierState(0) -{} + _activeModifierState(0), + _hintCloseTimer(this) +{ + Bind(wxEVT_TIMER, &MouseToolManager::onCloseTimerIntervalReached, this); +} // RegisterableModule implementation const std::string& MouseToolManager::getName() const @@ -222,8 +225,50 @@ void MouseToolManager::updateStatusbar(unsigned int newState) }); } + if (statusText.empty()) + { + _hintCloseTimer.Stop(); + + if (_hintPopup) + { + _hintPopup->Close(); + _hintPopup.reset(); + } + + return; + } + + _hintCloseTimer.StartOnce(1000); + + if (!_hintPopup) + { + _hintPopup.reset(new ModifierHintPopup(GlobalMainFrame().getWxTopLevelWindow())); + _hintPopup->Show(); + } + + _hintPopup->SetText(statusText); + // Pass the call - GlobalStatusBarManager().setText(STATUS_BAR_ELEMENT, statusText); + //GlobalStatusBarManager().setText(STATUS_BAR_ELEMENT, statusText); +} + +void MouseToolManager::onCloseTimerIntervalReached(wxTimerEvent& ev) +{ + // If no modifiers are held anymore, close the popup + bool modifierHeld = wxGetKeyState(WXK_SHIFT) || wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT); + + if (modifierHeld) + { + ev.GetTimer().StartOnce(1000); + return; + } + + if (_hintPopup) + { + _hintPopup->Close(); + _hintPopup.reset(); + return; + } } module::StaticModule mouseToolManagerModule; diff --git a/radiant/eventmanager/MouseToolManager.h b/radiant/eventmanager/MouseToolManager.h index 4c9cabc2c3..30f1eddb52 100644 --- a/radiant/eventmanager/MouseToolManager.h +++ b/radiant/eventmanager/MouseToolManager.h @@ -5,6 +5,9 @@ #include "imousetoolmanager.h" #include "xmlutil/Node.h" #include "MouseToolGroup.h" +#include "ModifierHintPopup.h" +#include +#include namespace ui { @@ -14,6 +17,7 @@ namespace ui * This is used by the GlobalXYWnd and GlobalCamera instances. */ class MouseToolManager : + public wxEvtHandler, public IMouseToolManager { protected: @@ -22,6 +26,9 @@ class MouseToolManager : unsigned int _activeModifierState; + wxTimer _hintCloseTimer; + std::unique_ptr _hintPopup; + public: MouseToolManager(); @@ -51,6 +58,8 @@ class MouseToolManager : void loadGroupMapping(MouseToolGroup::Type type, const xml::NodeList& userMappings, const xml::NodeList& defaultMappings); void saveToolMappings(); + + void onCloseTimerIntervalReached(wxTimerEvent& ev); }; } // namespace diff --git a/tools/msvc/DarkRadiant.vcxproj b/tools/msvc/DarkRadiant.vcxproj index a942ca3c37..64ae53d860 100644 --- a/tools/msvc/DarkRadiant.vcxproj +++ b/tools/msvc/DarkRadiant.vcxproj @@ -399,6 +399,7 @@ + diff --git a/tools/msvc/DarkRadiant.vcxproj.filters b/tools/msvc/DarkRadiant.vcxproj.filters index 1375ccc79c..74fa8262ea 100644 --- a/tools/msvc/DarkRadiant.vcxproj.filters +++ b/tools/msvc/DarkRadiant.vcxproj.filters @@ -1407,6 +1407,9 @@ src\map + + src\eventmanager +