diff --git a/doc/changelog.dox b/doc/changelog.dox index 5141ab8d0..3a12bc665 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -352,6 +352,11 @@ See also: @ref Platform::GlfwApplication::exit() now have an optional parameter to specify the actual application return code (see [mosra/magnum#332](https://github.com/mosra/magnum/pull/332)) +- Extended @ref Platform::BasicScreen with + @ref Platform::BasicScreen::mouseScrollEvent() "mouseScrollEvent()", + @ref Platform::BasicScreen::textInputEvent() "textInputEvent()" and + @ref Platform::BasicScreen::textEditingEvent() "textEditingEvent()" on + application implementations that provide such events @subsubsection changelog-latest-changes-text Text library diff --git a/src/Magnum/Platform/Screen.h b/src/Magnum/Platform/Screen.h index 075199715..d5b90ce39 100644 --- a/src/Magnum/Platform/Screen.h +++ b/src/Magnum/Platform/Screen.h @@ -45,6 +45,43 @@ enum class PropagatedScreenEvent: UnsignedByte { typedef Containers::EnumSet PropagatedScreenEvents; CORRADE_ENUMSET_OPERATORS(PropagatedScreenEvents) +/* These provide overrideable event handlers on the Screen side for events that + are not implemented by all apps. The virtual *Event() function is defined + only if the base Application has it. Calling into those is done through + a corresponding Application*EventMixin defined in ScreenedApplication.h. */ +template class ScreenMouseScrollEventMixin {}; +template class ScreenMouseScrollEventMixin { + public: + typedef typename BasicScreenedApplication::MouseScrollEvent MouseScrollEvent; + + private: + friend ApplicationMouseScrollEventMixin; + + virtual void mouseScrollEvent(MouseScrollEvent& event); +}; + +template class ScreenTextInputEventMixin {}; +template class ScreenTextInputEventMixin { + public: + typedef typename BasicScreenedApplication::TextInputEvent TextInputEvent; + + private: + friend ApplicationTextInputEventMixin; + + virtual void textInputEvent(TextInputEvent& event); +}; + +template class ScreenTextEditingEventMixin {}; +template class ScreenTextEditingEventMixin { + public: + typedef typename BasicScreenedApplication::TextEditingEvent TextEditingEvent; + + private: + friend ApplicationTextEditingEventMixin; + + virtual void textEditingEvent(TextEditingEvent& event); +}; + } /** @@ -69,7 +106,12 @@ The following specialization are explicitly compiled into each particular - @ref Sdl2Application "BasicScreen" - @ref XEglApplication "BasicScreen" */ -template class BasicScreen: private Containers::LinkedListItem, BasicScreenedApplication> { +template class BasicScreen: + private Containers::LinkedListItem, BasicScreenedApplication>, + public Implementation::ScreenMouseScrollEventMixin::value>, + public Implementation::ScreenTextInputEventMixin::value>, + public Implementation::ScreenTextEditingEventMixin::value> +{ public: #ifdef DOXYGEN_GENERATING_OUTPUT /** @@ -89,8 +131,10 @@ template class BasicScreen: private Containers::LinkedListIte * Input events. * * When enabled, @ref keyPressEvent(), @ref keyReleaseEvent(), - * @ref mousePressEvent(), @ref mouseReleaseEvent() and - * @ref mouseMoveEvent() are propagated to this screen. + * @ref mousePressEvent(), @ref mouseReleaseEvent(), + * @ref mouseMoveEvent(), @ref mouseScrollEvent(), + * @ref textInputEvent() and @ref textEditingEvent() are propagated + * to this screen. */ Input = 1 << 1 }; @@ -121,6 +165,32 @@ template class BasicScreen: private Containers::LinkedListIte /** @brief Mouse move event */ typedef typename BasicScreenedApplication::MouseMoveEvent MouseMoveEvent; + #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Mouse scroll event + * + * Defined only if the application has a + * @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent". + */ + typedef typename BasicScreenedApplication::MouseScrollEvent MouseScrollEvent; + + /** + * @brief Text input event + * + * Defined only if the application has a + * @ref Sdl2Application::TextInputEvent "TextInputEvent". + */ + typedef typename BasicScreenedApplication::TextInputEvent TextInputEvent; + + /** + * @brief Text editing event + * + * Defined only if the application has a + * @ref Sdl2Application::TextEditingEvent "TextEditingEvent". + */ + typedef typename BasicScreenedApplication::TextEditingEvent TextEditingEvent; + #endif + explicit BasicScreen(); ~BasicScreen(); @@ -284,6 +354,42 @@ template class BasicScreen: private Containers::LinkedListIte */ virtual void mouseMoveEvent(MouseMoveEvent& event); + #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Mouse scroll event + * + * Called when @ref PropagatedEvent::Input is enabled and mouse wheel + * is rotated. See @ref Sdl2Application::mouseScrollEvent() "*Application::mouseScrollEvent()" + * for more information. Defined only if the application has a + * @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent". + */ + virtual void mouseScrollEvent(MouseScrollEvent& event); + #endif + + /*@}*/ + + /** @{ @name Text input handling */ + + #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Text input event + * + * Called when @ref PropagatedEvent::Input is enabled and text is being + * input. Defined only if the application has a + * @ref Sdl2Application::TextInputEvent "TextInputEvent". + */ + virtual void textInputEvent(TextInputEvent& event); + + /** + * @brief Text editing event + * + * Called when @ref PropagatedEvent::Input and the text is being + * edited. Defined only if the application has a + * @ref Sdl2Application::TextEditingEvent "TextEditingEvent". + */ + virtual void textEditingEvent(TextEditingEvent& event); + #endif + /*@}*/ private: diff --git a/src/Magnum/Platform/ScreenedApplication.h b/src/Magnum/Platform/ScreenedApplication.h index 887e5e447..122001204 100644 --- a/src/Magnum/Platform/ScreenedApplication.h +++ b/src/Magnum/Platform/ScreenedApplication.h @@ -37,6 +37,53 @@ namespace Magnum { namespace Platform { +namespace Implementation { + +CORRADE_HAS_TYPE(HasMouseScrollEvent, typename T::MouseScrollEvent); +CORRADE_HAS_TYPE(HasTextInputEvent, typename T::TextInputEvent); +CORRADE_HAS_TYPE(HasTextEditingEvent, typename T::TextEditingEvent); + +/* Calls into the screen in case the application has a mouseScrollEvent(), + otherwise provides a dummy virtual so the application can unconditionally + override */ +template struct ApplicationMouseScrollEventMixin { + typedef int MouseScrollEvent; + virtual void mouseScrollEvent(MouseScrollEvent&) = 0; + + void callMouseScrollEvent(MouseScrollEvent&, Containers::LinkedList>&); +}; +template struct ApplicationMouseScrollEventMixin { + void callMouseScrollEvent(typename Application::MouseScrollEvent& event, Containers::LinkedList>& screens); +}; + +/* Calls into the screen in case the application has a textInputEvent(), + otherwise provides a dummy virtual so the application can unconditionally + override */ +template struct ApplicationTextInputEventMixin { + typedef int TextInputEvent; + virtual void textInputEvent(TextInputEvent&) = 0; + + void callTextInputEvent(TextInputEvent&, Containers::LinkedList>&); +}; +template struct ApplicationTextInputEventMixin { + void callTextInputEvent(typename Application::TextInputEvent& event, Containers::LinkedList>& screens); +}; + +/* Calls into the screen in case the application has a textEditingEvent(), + otherwise provides a dummy virtual so the application can unconditionally + override */ +template struct ApplicationTextEditingEventMixin { + typedef int TextEditingEvent; + virtual void textEditingEvent(TextEditingEvent&) = 0; + + void callTextEditingEvent(TextEditingEvent&, Containers::LinkedList>&); +}; +template struct ApplicationTextEditingEventMixin { + void callTextEditingEvent(typename Application::TextEditingEvent& event, Containers::LinkedList>& screens); +}; + +} + /** @brief Base for applications with screen management @@ -98,7 +145,13 @@ The following specialization are explicitly compiled into each particular - @ref Sdl2Application "BasicScreenedApplication" - @ref XEglApplication "BasicScreenedApplication" */ -template class BasicScreenedApplication: public Application, private Containers::LinkedList> { +template class BasicScreenedApplication: + public Application, + private Containers::LinkedList>, + private Implementation::ApplicationMouseScrollEventMixin::value>, + private Implementation::ApplicationTextInputEventMixin::value>, + private Implementation::ApplicationTextEditingEventMixin::value> +{ public: #ifdef MAGNUM_TARGET_GL /** @@ -221,6 +274,10 @@ template class BasicScreenedApplication: public Application, void mousePressEvent(typename Application::MouseEvent& event) override final; void mouseReleaseEvent(typename Application::MouseEvent& event) override final; void mouseMoveEvent(typename Application::MouseMoveEvent& event) override final; + + void mouseScrollEvent(typename BasicScreenedApplication::MouseScrollEvent& event) override final; + void textInputEvent(typename BasicScreenedApplication::TextInputEvent& event) override final; + void textEditingEvent(typename BasicScreenedApplication::TextEditingEvent& event) override final; }; }} diff --git a/src/Magnum/Platform/ScreenedApplication.hpp b/src/Magnum/Platform/ScreenedApplication.hpp index ac5a581c6..06ff14144 100644 --- a/src/Magnum/Platform/ScreenedApplication.hpp +++ b/src/Magnum/Platform/ScreenedApplication.hpp @@ -34,6 +34,51 @@ namespace Magnum { namespace Platform { +namespace Implementation { + +template void ApplicationMouseScrollEventMixin::callMouseScrollEvent(MouseScrollEvent&, Containers::LinkedList>&) {} +template void ApplicationMouseScrollEventMixin::callMouseScrollEvent(typename Application::MouseScrollEvent& event, Containers::LinkedList>& screens) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = screens.first(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->mouseScrollEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void ApplicationTextInputEventMixin::callTextInputEvent(TextInputEvent&, Containers::LinkedList>&) {} +template void ApplicationTextInputEventMixin::callTextInputEvent(typename Application::TextInputEvent& event, Containers::LinkedList>& screens) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = screens.first(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->textInputEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void ApplicationTextEditingEventMixin::callTextEditingEvent(TextEditingEvent&, Containers::LinkedList>&) {} +template void ApplicationTextEditingEventMixin::callTextEditingEvent(typename Application::TextEditingEvent& event, Containers::LinkedList>& screens) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = screens.first(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->textEditingEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void ScreenMouseScrollEventMixin::mouseScrollEvent(MouseScrollEvent&) {} +template void ScreenTextInputEventMixin::textInputEvent(TextInputEvent&) {} +template void ScreenTextEditingEventMixin::textEditingEvent(TextEditingEvent&) {} + +} + template BasicScreen::BasicScreen() = default; template BasicScreen::~BasicScreen() = default; @@ -160,6 +205,18 @@ template void BasicScreenedApplication::mouseMov } } +template void BasicScreenedApplication::mouseScrollEvent(typename BasicScreenedApplication::MouseScrollEvent& event) { + this->callMouseScrollEvent(event, screens()); +} + +template void BasicScreenedApplication::textInputEvent(typename BasicScreenedApplication::TextInputEvent& event) { + this->callTextInputEvent(event, screens()); +} + +template void BasicScreenedApplication::textEditingEvent(typename BasicScreenedApplication::TextEditingEvent& event) { + this->callTextEditingEvent(event, screens()); +} + }} #endif