From 1398ffd24c8e684ac9c464c26bdf86cbb8cc76e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 22 Apr 2016 16:45:06 +0200 Subject: [PATCH] Platform: text input support for Sdl2Application. --- src/Magnum/Platform/Sdl2Application.cpp | 32 +++++ src/Magnum/Platform/Sdl2Application.h | 166 ++++++++++++++++++++++++ 2 files changed, 198 insertions(+) diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index 37012a120..0e8a1dcea 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -33,6 +33,7 @@ #endif #include "Magnum/Version.h" +#include "Magnum/Math/Range.h" #include "Magnum/Platform/Context.h" #include "Magnum/Platform/ScreenedApplication.hpp" @@ -383,6 +384,18 @@ void Sdl2Application::mainLoop() { break; } + #ifndef CORRADE_TARGET_EMSCRIPTEN + case SDL_TEXTINPUT: { + TextInputEvent e{event.text.text}; + textInputEvent(e); + } break; + + case SDL_TEXTEDITING: { + TextEditingEvent e{event.edit.text, event.edit.start, event.edit.length}; + textEditingEvent(e); + } break; + #endif + case SDL_QUIT: #ifndef CORRADE_TARGET_EMSCRIPTEN _flags |= Flag::Exit; @@ -438,6 +451,20 @@ void Sdl2Application::setMouseLocked(bool enabled) { #endif } +#ifndef CORRADE_TARGET_EMSCRIPTEN +void Sdl2Application::startTextInput(const Range2Di& rect) { + SDL_StartTextInput(); + if(!rect.size().isZero()) { + SDL_Rect r{rect.min().x(), rect.min().y(), rect.sizeX(), rect.sizeY()}; + SDL_SetTextInputRect(&r); + } +} + +void Sdl2Application::startTextInput() { + startTextInput({}); +} +#endif + void Sdl2Application::tickEvent() { /* If this got called, the tick event is not implemented by user and thus we don't need to call it ever again */ @@ -451,6 +478,11 @@ void Sdl2Application::mousePressEvent(MouseEvent&) {} void Sdl2Application::mouseReleaseEvent(MouseEvent&) {} void Sdl2Application::mouseMoveEvent(MouseMoveEvent&) {} +#ifndef CORRADE_TARGET_EMSCRIPTEN +void Sdl2Application::textInputEvent(TextInputEvent&) {} +void Sdl2Application::textEditingEvent(TextEditingEvent&) {} +#endif + Sdl2Application::Configuration::Configuration(): #if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_IOS) _title("Magnum SDL2 Application"), diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index d98d488b8..714e607ea 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -330,6 +330,10 @@ class Sdl2Application { class KeyEvent; class MouseEvent; class MouseMoveEvent; + #ifndef CORRADE_TARGET_EMSCRIPTEN + class TextInputEvent; + class TextEditingEvent; + #endif /** * @brief Default constructor @@ -571,6 +575,69 @@ class Sdl2Application { /*@}*/ + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** @{ @name Text input handling */ + public: + /** + * @brief Whether text input is active + * + * If text input is active, text input events go to @ref textInputEvent() + * and @ref textEditingEvent(). + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref startTextInput(), @ref stopTextInput() + */ + bool isTextInputActive() { return SDL_IsTextInputActive(); } + + /** + * @brief Start text input + * + * Starts text input that will go to @ref textInputEvent() and + * @ref textEditingEvent(). The @p rect defines an area where the text + * is being displayed, for example to hint the system where to place + * on-screen keyboard. Ignored if empty. + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref stopTextInput(), @ref isTextInputActive(), + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + void startTextInput(const Range2Di& rect = {}); + #else + /* To avoid including the type in header */ + void startTextInput(const Range2Di& rect); + void startTextInput(); + #endif + + /** + * @brief Stop text input + * + * @note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + * @see @ref startTextInput(), @ref isTextInputActive(), @ref textInputEvent() + * @ref textEditingEvent() + */ + void stopTextInput() { SDL_StopTextInput(); } + + #ifdef DOXYGEN_GENERATING_OUTPUT + protected: + #else + private: + #endif + /** + * @brief Text input event + * + * Called when text input is active and the text is being input. + * @see @ref isTextInputActive() + */ + virtual void textInputEvent(TextInputEvent& event); + + /** + * @brief Text editing event + * + * Called when text input is active and the text is being edited. + */ + virtual void textEditingEvent(TextEditingEvent& event); + + /*@}*/ + #endif + private: enum class Flag: UnsignedByte { Redraw = 1 << 0, @@ -1123,6 +1190,105 @@ class Sdl2Application::MouseMoveEvent: public Sdl2Application::InputEvent { Modifiers _modifiers; }; +#ifndef CORRADE_TARGET_EMSCRIPTEN +/** +@brief Text input event + +@note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". +@see @ref TextEditingEvent, @ref textInputEvent() +*/ +class Sdl2Application::TextInputEvent { + friend Sdl2Application; + + public: + /** @brief Copying is not allowed */ + TextInputEvent(const TextInputEvent&) = delete; + + /** @brief Moving is not allowed */ + TextInputEvent(TextInputEvent&&) = delete; + + /** @brief Copying is not allowed */ + TextInputEvent& operator=(const TextInputEvent&) = delete; + + /** @brief Moving is not allowed */ + TextInputEvent& operator=(TextInputEvent&&) = delete; + + /** @brief Whether the event is accepted */ + constexpr bool isAccepted() const { return _accepted; } + + /** + * @brief Set event as accepted + * + * If the event is ignored (i.e., not set as accepted), it might be + * propagated elsewhere, for example to another screen when using + * @ref BasicScreenedApplication "ScreenedApplication". By default is + * each event ignored and thus propagated. + */ + void setAccepted(bool accepted = true) { _accepted = accepted; } + + /** @brief Input text in UTF-8 */ + constexpr Containers::ArrayView text() const { return _text; } + + private: + constexpr TextInputEvent(Containers::ArrayView text): _text{text} {} + + Containers::ArrayView _text; + bool _accepted; +}; + +/** +@brief Text editing event + +@note Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". +@see @ref textEditingEvent() +*/ +class Sdl2Application::TextEditingEvent { + friend Sdl2Application; + + public: + /** @brief Copying is not allowed */ + TextEditingEvent(const TextEditingEvent&) = delete; + + /** @brief Moving is not allowed */ + TextEditingEvent(TextEditingEvent&&) = delete; + + /** @brief Copying is not allowed */ + TextEditingEvent& operator=(const TextEditingEvent&) = delete; + + /** @brief Moving is not allowed */ + TextEditingEvent& operator=(TextEditingEvent&&) = delete; + + /** @brief Whether the event is accepted */ + constexpr bool isAccepted() const { return _accepted; } + + /** + * @brief Set event as accepted + * + * If the event is ignored (i.e., not set as accepted), it might be + * propagated elsewhere, for example to another screen when using + * @ref BasicScreenedApplication "ScreenedApplication". By default is + * each event ignored and thus propagated. + */ + void setAccepted(bool accepted = true) { _accepted = accepted; } + + /** @brief Input text in UTF-8 */ + constexpr Containers::ArrayView text() const { return _text; } + + /** @brief Location to begin editing from */ + constexpr Int start() const { return _start; } + + /** @brief Number of characters to edit from the start point */ + constexpr Int length() const { return _length; } + + private: + constexpr TextEditingEvent(Containers::ArrayView text, Int start, Int length): _text{text}, _start{start}, _length{length} {} + + Containers::ArrayView _text; + Int _start, _length; + bool _accepted; +}; +#endif + /** @hideinitializer @brief Entry point for SDL2-based applications @param className Class name