|
|
|
|
#ifndef Magnum_Platform_ScreenedApplication_h
|
|
|
|
|
#define Magnum_Platform_ScreenedApplication_h
|
|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @file
|
|
|
|
|
* @brief Class @ref Magnum::Platform::BasicScreenedApplication
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <Corrade/Containers/LinkedList.h>
|
|
|
|
|
|
|
|
|
|
#include "Magnum/Magnum.h"
|
|
|
|
|
#include "Magnum/Tags.h"
|
|
|
|
|
#include "Magnum/Platform/Platform.h"
|
|
|
|
|
|
|
|
|
|
namespace Magnum { namespace Platform {
|
|
|
|
|
|
|
|
|
|
namespace Implementation {
|
|
|
|
|
|
|
|
|
|
CORRADE_HAS_TYPE(HasKeyEvent, typename T::KeyEvent);
|
|
|
|
|
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 key*Event(), otherwise
|
|
|
|
|
provides a dummy virtual so the application can unconditionally override */
|
|
|
|
|
template<class Application, bool> struct ApplicationKeyEventMixin {
|
|
|
|
|
typedef int KeyEvent;
|
|
|
|
|
virtual void keyPressEvent(KeyEvent&) = 0;
|
|
|
|
|
virtual void keyReleaseEvent(KeyEvent&) = 0;
|
|
|
|
|
|
|
|
|
|
void callKeyPressEvent(KeyEvent&, Containers::LinkedList<BasicScreen<Application>>&);
|
|
|
|
|
void callKeyReleaseEvent(KeyEvent&, Containers::LinkedList<BasicScreen<Application>>&);
|
|
|
|
|
};
|
|
|
|
|
template<class Application> struct ApplicationKeyEventMixin<Application, true> {
|
|
|
|
|
void callKeyPressEvent(typename Application::KeyEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens);
|
|
|
|
|
void callKeyReleaseEvent(typename Application::KeyEvent& event, Containers::LinkedList<BasicScreen<Application>>& screens);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
|
|
|
|
|
@m_keywords{ScreenedApplication}
|
|
|
|
|
|
|
|
|
|
Manages list of screens and propagates events to them. If exactly one
|
|
|
|
|
application header is included, this class is also aliased to
|
|
|
|
|
@cpp Platform::ScreenedApplication @ce.
|
|
|
|
|
|
|
|
|
|
When you derive from this class, you're not allowed to implement any
|
|
|
|
|
usual application event handlers --- instead, these are propagated to
|
|
|
|
|
@ref BasicScreen "Screen" instances that get added using @ref addScreen(). Each
|
|
|
|
|
@ref BasicScreen "Screen" specifies which set of events should be propagated to
|
|
|
|
|
it using @ref BasicScreen::setPropagatedEvents(). When the application gets an
|
|
|
|
|
event, they are propagated to the screens:
|
|
|
|
|
|
|
|
|
|
- @ref Sdl2Application::viewportEvent() "viewportEvent()" is propagated to
|
|
|
|
|
all screens.
|
|
|
|
|
- @ref Sdl2Application::drawEvent() "drawEvent()" is propagated in
|
|
|
|
|
back-to-front order to screens which have @ref BasicScreen::PropagatedEvent::Draw
|
|
|
|
|
enabled.
|
|
|
|
|
- Input events (@ref Sdl2Application::keyPressEvent() "keyPressEvent()",
|
|
|
|
|
@ref Sdl2Application::keyReleaseEvent() "keyReleaseEvent()",
|
|
|
|
|
@ref Sdl2Application::mousePressEvent() "mousePressEvent()",
|
|
|
|
|
@ref Sdl2Application::mouseReleaseEvent() "mouseReleaseEvent()",
|
|
|
|
|
@ref Sdl2Application::mouseMoveEvent() "mouseMoveEvent()",
|
|
|
|
|
@ref Sdl2Application::mouseMoveEvent() "mouseScrollEvent()",
|
|
|
|
|
@ref Sdl2Application::textInputEvent() "textInputEvent()" and
|
|
|
|
|
@ref Sdl2Application::textEditingEvent() "textEditingEvent()")
|
|
|
|
|
are propagated in front-to-back order to screens which have
|
|
|
|
|
@ref BasicScreen::PropagatedEvent::Input enabled. If any screen sets the
|
|
|
|
|
event as accepted, it is not propagated further.
|
|
|
|
|
|
|
|
|
|
For the actual application, at the very least you need to implement
|
|
|
|
|
@ref globalDrawEvent(), and in case your application is resizable,
|
|
|
|
|
@ref globalViewportEvent() as well. The global draw event gets called *after*
|
|
|
|
|
all @ref BasicScreen::drawEvent() "Screen::drawEvent()" in order to make it
|
|
|
|
|
possible for you to do a buffer swap, while the global viewport event gets
|
|
|
|
|
called *before* all @ref BasicScreen::viewportEvent() "Screen::viewportEvent()",
|
|
|
|
|
in this case to make it possible to handle viewport changes on the default
|
|
|
|
|
framebuffer:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumPlatform.cpp ScreenedApplication-global-events
|
|
|
|
|
|
|
|
|
|
Uses @ref Corrade::Containers::LinkedList for efficient screen management.
|
|
|
|
|
Traversing front-to-back through the list of screens can be done using
|
|
|
|
|
range-based for:
|
|
|
|
|
|
|
|
|
|
@snippet MagnumPlatform.cpp ScreenedApplication-for-range
|
|
|
|
|
|
|
|
|
|
Or, if you need more flexibility, like in the following code. Traversing
|
|
|
|
|
back-to-front can be done using @ref Corrade::Containers::LinkedList::last()
|
|
|
|
|
and @ref BasicScreen::nextNearerScreen().
|
|
|
|
|
|
|
|
|
|
@snippet MagnumPlatform.cpp ScreenedApplication-for
|
|
|
|
|
|
|
|
|
|
@section Platform-ScreenedApplication-template-specializations Explicit template specializations
|
|
|
|
|
|
|
|
|
|
The following specialization are explicitly compiled into each particular
|
|
|
|
|
`*Application` library. For other specializations you have to use the
|
|
|
|
|
@ref ScreenedApplication.hpp implementation file to avoid linker errors. See
|
|
|
|
|
@ref compilation-speedup-hpp for more information.
|
|
|
|
|
|
|
|
|
|
- @ref AndroidApplication "BasicScreenedApplication<AndroidApplication>"
|
|
|
|
|
- @ref EmscriptenApplication "BasicScreenedApplication<EmscriptenApplication>"
|
|
|
|
|
- @ref GlfwApplication "BasicScreenedApplication<GlfwApplication>"
|
|
|
|
|
- @ref GlxApplication "BasicScreenedApplication<GlxApplication>"
|
|
|
|
|
- @ref Sdl2Application "BasicScreenedApplication<Sdl2Application>"
|
|
|
|
|
- @ref XEglApplication "BasicScreenedApplication<XEglApplication>"
|
|
|
|
|
*/
|
|
|
|
|
template<class Application> class BasicScreenedApplication:
|
|
|
|
|
public Application,
|
|
|
|
|
private Containers::LinkedList<BasicScreen<Application>>,
|
|
|
|
|
private Implementation::ApplicationKeyEventMixin<Application, Implementation::HasKeyEvent<Application>::value>,
|
|
|
|
|
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
|
|
|
|
|
/**
|
|
|
|
|
* @brief Construct with given configuration for OpenGL context
|
|
|
|
|
*
|
|
|
|
|
* Passes the arguments through to a particular application
|
|
|
|
|
* constructor.
|
|
|
|
|
*
|
|
|
|
|
* @note This function is available only if Magnum is compiled with
|
|
|
|
|
* @ref MAGNUM_TARGET_GL enabled (done by default). See
|
|
|
|
|
* @ref building-features for more information.
|
|
|
|
|
*/
|
|
|
|
|
explicit BasicScreenedApplication(const typename Application::Arguments& arguments, const typename Application::Configuration& configuration, const typename Application::GLConfiguration& glConfiguration);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Construct with given configuration
|
|
|
|
|
*
|
|
|
|
|
* Passes the arguments through to a particular application
|
|
|
|
|
* constructor.
|
|
|
|
|
*/
|
|
|
|
|
explicit BasicScreenedApplication(const typename Application::Arguments& arguments, const typename Application::Configuration& configuration = typename Application::Configuration{});
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Constructor
|
|
|
|
|
* @param arguments Application arguments
|
|
|
|
|
*
|
|
|
|
|
* Unlike above, the context is not created and must be created later
|
|
|
|
|
* with @ref Sdl2Application::create() "create()" or
|
|
|
|
|
* @ref Sdl2Application::tryCreate() "tryCreate()".
|
|
|
|
|
*/
|
|
|
|
|
explicit BasicScreenedApplication(const typename Application::Arguments& arguments, NoCreateT);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Add screen to application
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* The new screen is added as backmost. If this is the first screen
|
|
|
|
|
* added, @ref BasicScreen::focusEvent() is called. If not, neither
|
|
|
|
|
* @ref BasicScreen::blurEvent() nor @ref BasicScreen::focusEvent() is
|
|
|
|
|
* called (i.e. the screen default state is used).
|
|
|
|
|
*/
|
|
|
|
|
BasicScreenedApplication<Application>& addScreen(BasicScreen<Application>& screen);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Remove screen from application
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* The screen is blurred before removing. Deleting the object is left
|
|
|
|
|
* up to the user.
|
|
|
|
|
* @see @ref BasicScreen::blurEvent()
|
|
|
|
|
*/
|
|
|
|
|
BasicScreenedApplication<Application>& removeScreen(BasicScreen<Application>& screen);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Focus screen
|
|
|
|
|
* @return Reference to self (for method chaining)
|
|
|
|
|
*
|
|
|
|
|
* Moves the screen to front. Previously focused screen is blurred and
|
|
|
|
|
* this screen is focused.
|
|
|
|
|
* @see @ref BasicScreen::blurEvent(), @ref BasicScreen::focusEvent()
|
|
|
|
|
*/
|
|
|
|
|
BasicScreenedApplication<Application>& focusScreen(BasicScreen<Application>& screen);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Application screens
|
|
|
|
|
*
|
|
|
|
|
* The screens are sorted front-to-back.
|
|
|
|
|
* @see @ref BasicScreen::application(),
|
|
|
|
|
* @ref BasicScreen::nextFartherScreen(),
|
|
|
|
|
* @ref BasicScreen::nextNearerScreen()
|
|
|
|
|
*/
|
|
|
|
|
Containers::LinkedList<BasicScreen<Application>>& screens() {
|
|
|
|
|
return static_cast<Containers::LinkedList<BasicScreen<Application>>&>(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @overload */
|
|
|
|
|
const Containers::LinkedList<BasicScreen<Application>>& screens() const {
|
|
|
|
|
return static_cast<const Containers::LinkedList<BasicScreen<Application>>&>(*this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
/* Nobody will need to have (and delete) ScreenedApplication*, thus
|
|
|
|
|
this is faster than public pure virtual destructor */
|
|
|
|
|
~BasicScreenedApplication();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/**
|
|
|
|
|
* @brief Global viewport event
|
|
|
|
|
*
|
|
|
|
|
* Called when window size changes, *before* all screens'
|
|
|
|
|
* @ref BasicScreen::viewportEvent() "viewportEvent()". Default
|
|
|
|
|
* implementation does nothing. See @ref Sdl2Application::viewportEvent() "*Application::viewportEvent()"
|
|
|
|
|
* for more information.
|
|
|
|
|
*/
|
|
|
|
|
virtual void globalViewportEvent(typename Application::ViewportEvent& size);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Draw event
|
|
|
|
|
*
|
|
|
|
|
* Called *after* all screens' @ref BasicScreen::drawEvent() "drawEvent()".
|
|
|
|
|
* You should call at least @ref Sdl2Application::swapBuffers() "swapBuffers()".
|
|
|
|
|
* If you want to draw immediately again, call also
|
|
|
|
|
* @ref Sdl2Application::redraw() "redraw()".
|
|
|
|
|
*/
|
|
|
|
|
virtual void globalDrawEvent() = 0;
|
|
|
|
|
|
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT /* https://bugzilla.gnome.org/show_bug.cgi?id=776986 */
|
|
|
|
|
friend Containers::LinkedList<BasicScreen<Application>>;
|
|
|
|
|
friend Containers::LinkedListItem<BasicScreen<Application>, BasicScreenedApplication<Application>>;
|
|
|
|
|
friend BasicScreen<Application>;
|
|
|
|
|
#endif
|
|
|
|
|
/* The user is supposed to override only globalViewportEvent() and
|
|
|
|
|
globalDrawEvent(), these implementations are dispatching the events
|
|
|
|
|
to attached screens. */
|
|
|
|
|
void viewportEvent(typename Application::ViewportEvent& event) override final;
|
|
|
|
|
void drawEvent() override final;
|
|
|
|
|
void mousePressEvent(typename Application::MouseEvent& event) override final;
|
|
|
|
|
void mouseReleaseEvent(typename Application::MouseEvent& event) override final;
|
|
|
|
|
void mouseMoveEvent(typename Application::MouseMoveEvent& event) override final;
|
|
|
|
|
|
|
|
|
|
/* These events are not available in all cases, so if the Application
|
|
|
|
|
doesn't have them, they're overriding a mixin dummy */
|
|
|
|
|
void keyPressEvent(typename BasicScreenedApplication<Application>::KeyEvent& event) override final;
|
|
|
|
|
void keyReleaseEvent(typename BasicScreenedApplication<Application>::KeyEvent& 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;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
#endif
|