From 40bfa7ae9105bdeb60b85e8cccc26f75efa20541 Mon Sep 17 00:00:00 2001 From: Marco Melorio Date: Thu, 17 Oct 2019 18:24:24 +0200 Subject: [PATCH] Plaftorm: Add cursor management support --- src/Magnum/Platform/GlfwApplication.cpp | 37 +++++++++++++++ src/Magnum/Platform/GlfwApplication.h | 30 ++++++++++++ src/Magnum/Platform/Sdl2Application.cpp | 63 +++++++++++++++++++++++++ src/Magnum/Platform/Sdl2Application.h | 46 ++++++++++++++++++ 4 files changed, 176 insertions(+) diff --git a/src/Magnum/Platform/GlfwApplication.cpp b/src/Magnum/Platform/GlfwApplication.cpp index 008d09a77..91f2a7c54 100644 --- a/src/Magnum/Platform/GlfwApplication.cpp +++ b/src/Magnum/Platform/GlfwApplication.cpp @@ -549,6 +549,8 @@ void GlfwApplication::setupCallbacks() { GlfwApplication::~GlfwApplication() { glfwDestroyWindow(_window); + for(auto& cursor: _cursors) + glfwDestroyCursor(cursor); glfwTerminate(); } @@ -603,6 +605,41 @@ int GlfwApplication::exec() { return _exitCode; } +void GlfwApplication::setCursor(Cursor cursor) { + CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(_cursors)); + + _cursor = cursor; + + if(cursor == Cursor::Hidden) { + glfwSetInputMode(_window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + return; + } else if(cursor == Cursor::HiddenLocked) { + glfwSetInputMode(_window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + return; + } else { + glfwSetInputMode(_window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + + if(!_cursors[UnsignedInt(cursor)]) { + constexpr Int CursorMap[] { + GLFW_ARROW_CURSOR, + GLFW_IBEAM_CURSOR, + GLFW_CROSSHAIR_CURSOR, + GLFW_HRESIZE_CURSOR, + GLFW_VRESIZE_CURSOR, + GLFW_HAND_CURSOR + }; + + _cursors[UnsignedInt(cursor)] = glfwCreateStandardCursor(CursorMap[UnsignedInt(cursor)]); + } + + glfwSetCursor(_window, _cursors[UnsignedInt(cursor)]); +} + +GlfwApplication::Cursor GlfwApplication::cursor() { + return _cursor; +} + auto GlfwApplication::MouseMoveEvent::buttons() -> Buttons { if(!_buttons) { _buttons = Buttons{}; diff --git a/src/Magnum/Platform/GlfwApplication.h b/src/Magnum/Platform/GlfwApplication.h index f32f71c39..e0bad2345 100644 --- a/src/Magnum/Platform/GlfwApplication.h +++ b/src/Magnum/Platform/GlfwApplication.h @@ -487,6 +487,33 @@ class GlfwApplication { /** @{ @name Mouse handling */ public: + /** + * @brief Cursor type + * + * @see @ref setCursor() + */ + enum class Cursor : UnsignedInt { + Arrow, /**< Arrow */ + TextInput, /**< Text input */ + Crosshair, /**< Crosshair */ + ResizeWE, /**< Double arrow pointing west and east */ + ResizeNS, /**< Double arrow pointing north and south */ + Hand, /**< Hand */ + Hidden, /**< Hidden */ + HiddenLocked /**< Hidden and locked */ + }; + + public: + /** + * @brief Set the cursor to the @p type + */ + void setCursor(Cursor cursor); + + /** + * @brief Get the current cursor type + */ + Cursor cursor(); + /** @brief Warp mouse cursor to given coordinates */ void warpCursor(const Vector2i& position) { glfwSetCursorPos(_window, Double(position.x()), Double(position.y())); @@ -577,6 +604,9 @@ class GlfwApplication { void setupCallbacks(); + GLFWcursor* _cursors[8]{}; + Cursor _cursor = Cursor::Arrow; + /* These are saved from command-line arguments */ bool _verboseLog{}; Implementation::GlfwDpiScalingPolicy _commandLineDpiScalingPolicy{}; diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index ae90c1cb6..98fb44b73 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -684,6 +684,11 @@ Sdl2Application::~Sdl2Application() { #endif #endif + #ifndef CORRADE_TARGET_EMSCRIPTEN + for(auto& cursor: _cursors) + SDL_FreeCursor(cursor); + #endif + #ifndef CORRADE_TARGET_EMSCRIPTEN SDL_DestroyWindow(_window); #endif @@ -880,6 +885,64 @@ bool Sdl2Application::mainLoopIteration() { return !(_flags & Flag::Exit); } +#ifndef CORRADE_TARGET_EMSCRIPTEN +void Sdl2Application::setCursor(Cursor cursor) { + CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(_cursors)); + + if(cursor == Cursor::Hidden) { + SDL_ShowCursor(SDL_DISABLE); + SDL_SetWindowGrab(_window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + return; + } else if(cursor == Cursor::HiddenLocked) { + SDL_SetWindowGrab(_window, SDL_TRUE); + SDL_SetRelativeMouseMode(SDL_TRUE); + return; + } else { + SDL_ShowCursor(SDL_ENABLE); + SDL_SetWindowGrab(_window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + } + + if(!_cursors[UnsignedInt(cursor)]) { + constexpr SDL_SystemCursor CursorMap[] { + SDL_SYSTEM_CURSOR_ARROW, + SDL_SYSTEM_CURSOR_IBEAM, + SDL_SYSTEM_CURSOR_WAIT, + SDL_SYSTEM_CURSOR_CROSSHAIR, + SDL_SYSTEM_CURSOR_WAITARROW, + SDL_SYSTEM_CURSOR_SIZENWSE, + SDL_SYSTEM_CURSOR_SIZENESW, + SDL_SYSTEM_CURSOR_SIZEWE, + SDL_SYSTEM_CURSOR_SIZENS, + SDL_SYSTEM_CURSOR_SIZEALL, + SDL_SYSTEM_CURSOR_NO, + SDL_SYSTEM_CURSOR_HAND + }; + + _cursors[UnsignedInt(cursor)] = SDL_CreateSystemCursor(CursorMap[UnsignedInt(cursor)]); + } + + SDL_SetCursor(_cursors[UnsignedInt(cursor)]); +} + +Sdl2Application::Cursor Sdl2Application::cursor() { + if(SDL_GetRelativeMouseMode()) + return Cursor::HiddenLocked; + else if(!SDL_ShowCursor(SDL_QUERY)) + return Cursor::Hidden; + + SDL_Cursor* cursor = SDL_GetCursor(); + + if(cursor) + for(UnsignedInt i = 0; i < sizeof(_cursors); i++) + if(_cursors[i] == cursor) + return Cursor(i); + + return Cursor::Arrow; +} +#endif + void Sdl2Application::setMouseLocked(bool enabled) { /** @todo Implement this in Emscripten */ #ifndef CORRADE_TARGET_EMSCRIPTEN diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index 5a82eac5e..188158b09 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -832,6 +832,48 @@ class Sdl2Application { /** @{ @name Mouse handling */ public: + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Cursor type + * + * @see @ref setCursor() + */ + enum class Cursor : UnsignedInt { + Arrow, /**< Arrow */ + TextInput, /**< Text input */ + Wait, /**< Wait */ + Crosshair, /**< Crosshair */ + WaitArrow, /**< Small wait cursor */ + ResizeNWSE, /**< Double arrow pointing northwest and southeast */ + ResizeNESW, /**< Double arrow pointing northeast and southwest */ + ResizeWE, /**< Double arrow pointing west and east */ + ResizeNS, /**< Double arrow pointing north and south */ + ResizeAll, /**< Four pointed arrow pointing north, south, east, and west */ + No, /**< Slashed circle or crossbones */ + Hand, /**< Hand */ + Hidden, /**< Hidden */ + HiddenLocked /**< Hidden and locked */ + }; + #endif + + public: + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Set the cursor to the @p type + */ + void setCursor(Cursor cursor); + + /** + * @brief Get the current cursor type + */ + Cursor cursor(); + #endif + + /** @brief Warp mouse cursor to given coordinates */ + void warpCursor(const Vector2i& position) { + SDL_WarpMouseInWindow(_window, position.x(), position.y()); + } + /** @brief Whether mouse is locked */ bool isMouseLocked() const { return SDL_GetRelativeMouseMode(); } @@ -1015,6 +1057,10 @@ class Sdl2Application { typedef Containers::EnumSet Flags; CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) + #ifndef CORRADE_TARGET_EMSCRIPTEN + SDL_Cursor* _cursors[14]{}; + #endif + /* These are saved from command-line arguments */ bool _verboseLog{}; Implementation::Sdl2DpiScalingPolicy _commandLineDpiScalingPolicy{};