Browse Source

Platform: expose mouseScrollEvent() and text*Event() in Screen APIs.

Because not all applications implement these, it's done via a "mixin". I
never did such a thing before, just got an idea that it could work and
I'm equally amazed and horrified that it actually DOES WORK. The Screen
will now expose the MouseScrollEvent, TextInputEvent and
TextEditingEvent typedefs only if the underlying application has them
too and provides the overrideable mouseScrollEvent(), textInputEvent()
and textEditingEvent() also only if the underlying application has them
-- that also means you can't `override` those if the app doesn't provide
such APIs, which acts as a nice check against accidental overgenericity.
pull/364/head
Vladimír Vondruš 7 years ago
parent
commit
2828548d7d
  1. 5
      doc/changelog.dox
  2. 112
      src/Magnum/Platform/Screen.h
  3. 59
      src/Magnum/Platform/ScreenedApplication.h
  4. 57
      src/Magnum/Platform/ScreenedApplication.hpp

5
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

112
src/Magnum/Platform/Screen.h

@ -45,6 +45,43 @@ enum class PropagatedScreenEvent: UnsignedByte {
typedef Containers::EnumSet<PropagatedScreenEvent> 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 Application, bool> class ScreenMouseScrollEventMixin {};
template<class Application> class ScreenMouseScrollEventMixin<Application, true> {
public:
typedef typename BasicScreenedApplication<Application>::MouseScrollEvent MouseScrollEvent;
private:
friend ApplicationMouseScrollEventMixin<Application, true>;
virtual void mouseScrollEvent(MouseScrollEvent& event);
};
template<class Application, bool> class ScreenTextInputEventMixin {};
template<class Application> class ScreenTextInputEventMixin<Application, true> {
public:
typedef typename BasicScreenedApplication<Application>::TextInputEvent TextInputEvent;
private:
friend ApplicationTextInputEventMixin<Application, true>;
virtual void textInputEvent(TextInputEvent& event);
};
template<class Application, bool> class ScreenTextEditingEventMixin {};
template<class Application> class ScreenTextEditingEventMixin<Application, true> {
public:
typedef typename BasicScreenedApplication<Application>::TextEditingEvent TextEditingEvent;
private:
friend ApplicationTextEditingEventMixin<Application, true>;
virtual void textEditingEvent(TextEditingEvent& event);
};
}
/**
@ -69,7 +106,12 @@ The following specialization are explicitly compiled into each particular
- @ref Sdl2Application "BasicScreen<Sdl2Application>"
- @ref XEglApplication "BasicScreen<XEglApplication>"
*/
template<class Application> class BasicScreen: private Containers::LinkedListItem<BasicScreen<Application>, BasicScreenedApplication<Application>> {
template<class Application> class BasicScreen:
private Containers::LinkedListItem<BasicScreen<Application>, BasicScreenedApplication<Application>>,
public Implementation::ScreenMouseScrollEventMixin<Application, Implementation::HasMouseScrollEvent<Application>::value>,
public Implementation::ScreenTextInputEventMixin<Application, Implementation::HasTextInputEvent<Application>::value>,
public Implementation::ScreenTextEditingEventMixin<Application, Implementation::HasTextEditingEvent<Application>::value>
{
public:
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
@ -89,8 +131,10 @@ template<class Application> 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 Application> class BasicScreen: private Containers::LinkedListIte
/** @brief Mouse move event */
typedef typename BasicScreenedApplication<Application>::MouseMoveEvent MouseMoveEvent;
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Mouse scroll event
*
* Defined only if the application has a
* @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent".
*/
typedef typename BasicScreenedApplication<Application>::MouseScrollEvent MouseScrollEvent;
/**
* @brief Text input event
*
* Defined only if the application has a
* @ref Sdl2Application::TextInputEvent "TextInputEvent".
*/
typedef typename BasicScreenedApplication<Application>::TextInputEvent TextInputEvent;
/**
* @brief Text editing event
*
* Defined only if the application has a
* @ref Sdl2Application::TextEditingEvent "TextEditingEvent".
*/
typedef typename BasicScreenedApplication<Application>::TextEditingEvent TextEditingEvent;
#endif
explicit BasicScreen();
~BasicScreen();
@ -284,6 +354,42 @@ template<class Application> 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:

59
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<class Application, bool> struct ApplicationMouseScrollEventMixin {
typedef int MouseScrollEvent;
virtual void mouseScrollEvent(MouseScrollEvent&) = 0;
void callMouseScrollEvent(MouseScrollEvent&, Containers::LinkedList<BasicScreen<Application>>&);
};
template<class Application> struct ApplicationMouseScrollEventMixin<Application, true> {
void callMouseScrollEvent(typename Application::MouseScrollEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens);
};
/* Calls into the screen in case the application has a textInputEvent(),
otherwise provides a dummy virtual so the application can unconditionally
override */
template<class Application, bool> struct ApplicationTextInputEventMixin {
typedef int TextInputEvent;
virtual void textInputEvent(TextInputEvent&) = 0;
void callTextInputEvent(TextInputEvent&, Containers::LinkedList<BasicScreen<Application>>&);
};
template<class Application> struct ApplicationTextInputEventMixin<Application, true> {
void callTextInputEvent(typename Application::TextInputEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens);
};
/* Calls into the screen in case the application has a textEditingEvent(),
otherwise provides a dummy virtual so the application can unconditionally
override */
template<class Application, bool> struct ApplicationTextEditingEventMixin {
typedef int TextEditingEvent;
virtual void textEditingEvent(TextEditingEvent&) = 0;
void callTextEditingEvent(TextEditingEvent&, Containers::LinkedList<BasicScreen<Application>>&);
};
template<class Application> struct ApplicationTextEditingEventMixin<Application, true> {
void callTextEditingEvent(typename Application::TextEditingEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens);
};
}
/**
@brief Base for applications with screen management
@ -98,7 +145,13 @@ The following specialization are explicitly compiled into each particular
- @ref Sdl2Application "BasicScreenedApplication<Sdl2Application>"
- @ref XEglApplication "BasicScreenedApplication<XEglApplication>"
*/
template<class Application> class BasicScreenedApplication: public Application, private Containers::LinkedList<BasicScreen<Application>> {
template<class Application> class BasicScreenedApplication:
public Application,
private Containers::LinkedList<BasicScreen<Application>>,
private Implementation::ApplicationMouseScrollEventMixin<Application, Implementation::HasMouseScrollEvent<Application>::value>,
private Implementation::ApplicationTextInputEventMixin<Application, Implementation::HasTextInputEvent<Application>::value>,
private Implementation::ApplicationTextEditingEventMixin<Application, Implementation::HasTextEditingEvent<Application>::value>
{
public:
#ifdef MAGNUM_TARGET_GL
/**
@ -221,6 +274,10 @@ template<class Application> 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<Application>::MouseScrollEvent& event) override final;
void textInputEvent(typename BasicScreenedApplication<Application>::TextInputEvent& event) override final;
void textEditingEvent(typename BasicScreenedApplication<Application>::TextEditingEvent& event) override final;
};
}}

57
src/Magnum/Platform/ScreenedApplication.hpp

@ -34,6 +34,51 @@
namespace Magnum { namespace Platform {
namespace Implementation {
template<class Application, bool implements> void ApplicationMouseScrollEventMixin<Application, implements>::callMouseScrollEvent(MouseScrollEvent&, Containers::LinkedList<BasicScreen<Application>>&) {}
template<class Application> void ApplicationMouseScrollEventMixin<Application, true>::callMouseScrollEvent(typename Application::MouseScrollEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens) {
/* Front-to-back event propagation, stop when the event gets accepted */
for(BasicScreen<Application>* s = screens.first(); s; s = s->nextFartherScreen()) {
if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
s->mouseScrollEvent(event);
if(event.isAccepted()) break;
}
}
}
template<class Application, bool implements> void ApplicationTextInputEventMixin<Application, implements>::callTextInputEvent(TextInputEvent&, Containers::LinkedList<BasicScreen<Application>>&) {}
template<class Application> void ApplicationTextInputEventMixin<Application, true>::callTextInputEvent(typename Application::TextInputEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens) {
/* Front-to-back event propagation, stop when the event gets accepted */
for(BasicScreen<Application>* s = screens.first(); s; s = s->nextFartherScreen()) {
if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
s->textInputEvent(event);
if(event.isAccepted()) break;
}
}
}
template<class Application, bool implements> void ApplicationTextEditingEventMixin<Application, implements>::callTextEditingEvent(TextEditingEvent&, Containers::LinkedList<BasicScreen<Application>>&) {}
template<class Application> void ApplicationTextEditingEventMixin<Application,
true>::callTextEditingEvent(typename Application::TextEditingEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens) {
/* Front-to-back event propagation, stop when the event gets accepted */
for(BasicScreen<Application>* s = screens.first(); s; s = s->nextFartherScreen()) {
if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) {
s->textEditingEvent(event);
if(event.isAccepted()) break;
}
}
}
template<class Application> void ScreenMouseScrollEventMixin<Application,
true>::mouseScrollEvent(MouseScrollEvent&) {}
template<class Application> void ScreenTextInputEventMixin<Application,
true>::textInputEvent(TextInputEvent&) {}
template<class Application> void ScreenTextEditingEventMixin<Application,
true>::textEditingEvent(TextEditingEvent&) {}
}
template<class Application> BasicScreen<Application>::BasicScreen() = default;
template<class Application> BasicScreen<Application>::~BasicScreen() = default;
@ -160,6 +205,18 @@ template<class Application> void BasicScreenedApplication<Application>::mouseMov
}
}
template<class Application> void BasicScreenedApplication<Application>::mouseScrollEvent(typename BasicScreenedApplication<Application>::MouseScrollEvent& event) {
this->callMouseScrollEvent(event, screens());
}
template<class Application> void BasicScreenedApplication<Application>::textInputEvent(typename BasicScreenedApplication<Application>::TextInputEvent& event) {
this->callTextInputEvent(event, screens());
}
template<class Application> void BasicScreenedApplication<Application>::textEditingEvent(typename BasicScreenedApplication<Application>::TextEditingEvent& event) {
this->callTextEditingEvent(event, screens());
}
}}
#endif

Loading…
Cancel
Save