diff --git a/src/Platform/CMakeLists.txt b/src/Platform/CMakeLists.txt index 46b60f929..d4a456870 100644 --- a/src/Platform/CMakeLists.txt +++ b/src/Platform/CMakeLists.txt @@ -22,6 +22,15 @@ # DEALINGS IN THE SOFTWARE. # +# Headers +set(Platform_HEADERS + Platform.h + Screen.h + ScreenedApplication.h + ScreenedApplication.hpp) + +install(FILES ${Platform_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Platform) + # GLUT application if(WITH_GLUTAPPLICATION) find_package(GLUT) diff --git a/src/Platform/GlutApplication.cpp b/src/Platform/GlutApplication.cpp index 07e6d0a49..661e360c2 100644 --- a/src/Platform/GlutApplication.cpp +++ b/src/Platform/GlutApplication.cpp @@ -26,6 +26,8 @@ #include "Context.h" +#include "Platform/ScreenedApplication.hpp" + namespace Magnum { namespace Platform { GlutApplication* GlutApplication::instance = nullptr; @@ -117,4 +119,7 @@ void GlutApplication::mouseMoveEvent(MouseMoveEvent&) {} GlutApplication::Configuration::Configuration(): _title("Magnum GLUT Application"), _size(800, 600), _sampleCount(0) {} GlutApplication::Configuration::~Configuration() = default; +template class BasicScreen; +template class BasicScreenedApplication; + }} diff --git a/src/Platform/GlutApplication.h b/src/Platform/GlutApplication.h index 679073aee..6259be010 100644 --- a/src/Platform/GlutApplication.h +++ b/src/Platform/GlutApplication.h @@ -30,6 +30,7 @@ #include +#include "Platform/Platform.h" #include "Math/Vector2.h" #include "Magnum.h" @@ -543,6 +544,8 @@ When no other application header is included this macro is also aliased to #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_APPLICATION_MAIN typedef GlutApplication Application; +typedef BasicScreen Screen; +typedef BasicScreenedApplication ScreenedApplication; #define MAGNUM_APPLICATION_MAIN(className) MAGNUM_GLUTAPPLICATION_MAIN(className) #else #undef MAGNUM_APPLICATION_MAIN diff --git a/src/Platform/GlxApplication.cpp b/src/Platform/GlxApplication.cpp index 848ba0af0..e100ff5ef 100644 --- a/src/Platform/GlxApplication.cpp +++ b/src/Platform/GlxApplication.cpp @@ -24,6 +24,7 @@ #include "GlxApplication.h" +#include "Platform/ScreenedApplication.hpp" #include "Platform/Implementation/GlxContextHandler.h" namespace Magnum { namespace Platform { @@ -32,4 +33,7 @@ GlxApplication::GlxApplication(const Arguments& arguments, const Configuration& GlxApplication::GlxApplication(const Arguments& arguments, std::nullptr_t): AbstractXApplication(new Implementation::GlxContextHandler, arguments, nullptr) {} +template class BasicScreen; +template class BasicScreenedApplication; + }} diff --git a/src/Platform/GlxApplication.h b/src/Platform/GlxApplication.h index 3d3bb2d9d..e06782701 100644 --- a/src/Platform/GlxApplication.h +++ b/src/Platform/GlxApplication.h @@ -29,6 +29,7 @@ */ #include "Platform/AbstractXApplication.h" +#include "Platform/Platform.h" namespace Magnum { namespace Platform { @@ -102,6 +103,8 @@ When no other application header is included this macro is also aliased to #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_APPLICATION_MAIN typedef GlxApplication Application; +typedef BasicScreen Screen; +typedef BasicScreenedApplication ScreenedApplication; #define MAGNUM_APPLICATION_MAIN(className) MAGNUM_GLXAPPLICATION_MAIN(className) #else #undef MAGNUM_APPLICATION_MAIN diff --git a/src/Platform/NaClApplication.cpp b/src/Platform/NaClApplication.cpp index f1f84ad6e..1094316f8 100644 --- a/src/Platform/NaClApplication.cpp +++ b/src/Platform/NaClApplication.cpp @@ -30,6 +30,7 @@ #include #include "Context.h" +#include "Platform/ScreenedApplication.hpp" namespace Magnum { namespace Platform { @@ -254,4 +255,7 @@ void NaClApplication::mousePressEvent(MouseEvent&) {} void NaClApplication::mouseReleaseEvent(MouseEvent&) {} void NaClApplication::mouseMoveEvent(MouseMoveEvent&) {} +template class BasicScreen; +template class BasicScreenedApplication; + }} diff --git a/src/Platform/NaClApplication.h b/src/Platform/NaClApplication.h index cbe7766f9..5a5bd9dc8 100644 --- a/src/Platform/NaClApplication.h +++ b/src/Platform/NaClApplication.h @@ -37,6 +37,7 @@ #include #include +#include "Platform/Platform.h" #include "Math/Vector2.h" #include "Magnum.h" @@ -657,6 +658,8 @@ When no other application header is included this macro is also aliased to #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_APPLICATION_MAIN typedef NaClApplication Application; +typedef BasicScreen Screen; +typedef BasicScreenedApplication ScreenedApplication; #define MAGNUM_APPLICATION_MAIN(className) MAGNUM_NACLAPPLICATION_MAIN(className) #else #undef MAGNUM_APPLICATION_MAIN diff --git a/src/Platform/Platform.h b/src/Platform/Platform.h new file mode 100644 index 000000000..051685343 --- /dev/null +++ b/src/Platform/Platform.h @@ -0,0 +1,38 @@ +#ifndef Magnum_Platform_Platform_h +#define Magnum_Platform_Platform_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + 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 Forward declarations for @ref Magnum::Platform namespace + */ + +namespace Magnum { namespace Platform { + +template class BasicScreen; +template class BasicScreenedApplication; + +}} + +#endif diff --git a/src/Platform/Screen.h b/src/Platform/Screen.h new file mode 100644 index 000000000..bbdd5fc86 --- /dev/null +++ b/src/Platform/Screen.h @@ -0,0 +1,265 @@ +#ifndef Magnum_Platform_AbstractScreen_h +#define Magnum_Platform_AbstractScreen_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + 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::BasicScreen + */ + +#include + +#include "Platform/ScreenedApplication.h" + +namespace Magnum { namespace Platform { + +namespace Implementation { + enum class PropagatedScreenEvent: UnsignedByte { + Draw = 1 << 0, + Input = 1 << 1 + }; + + typedef Containers::EnumSet PropagatedScreenEvents; + CORRADE_ENUMSET_OPERATORS(PropagatedScreenEvents) +} + +/** +@brief Base for application screens + +See @ref BasicScreenedApplication for more information. + +If exactly one application header is included, this class is also aliased to +`Platform::Screen`. + +@section Screen-explicit-specializations Explicit template specializations + +The following specialization are explicitly compiled into each particular +`*Application` library. For other specializations you have to use +@ref ScreenedApplication.hpp implementation file to avoid linker errors. See +@ref compilation-speedup-hpp for more information. + +- @ref GlutApplication "BasicScreen" +- @ref GlxApplication "BasicScreen" +- @ref NaClApplication "BasicScreen" +- @ref Sdl2Application "BasicScreen" +- @ref XEglApplication "BasicScreen" +*/ +template class BasicScreen: private Containers::LinkedListItem, BasicScreenedApplication> { + friend class Containers::LinkedListItem, BasicScreenedApplication>; + friend class Containers::LinkedList>; + friend class BasicScreenedApplication; + + public: + #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Event propagated to given screen + * + * @see @ref PropagatedEvents, @ref BasicScreen::setPropagatedEvents() + */ + enum class PropagatedEvent: UnsignedByte { + /** + * Draw event. + * + * When enabled, drawEvent() is propagated to this screen. + */ + Draw = 1 << 0, + + /** + * Input events. + * + * When enabled, keyPressEvent(), keyReleaseEvent(), mousePressEvent(), + * mouseReleaseEvent() and mouseMoveEvent() are propagated to this + * screen. + */ + Input = 1 << 1 + }; + + /** + * @brief Events propagated to given screen + * + * @see @ref setPropagatedEvents() + */ + typedef Containers::EnumSet PropagatedEvents; + #else + typedef Implementation::PropagatedScreenEvent PropagatedEvent; + typedef Implementation::PropagatedScreenEvents PropagatedEvents; + #endif + + /** @brief Input event */ + typedef typename BasicScreenedApplication::InputEvent InputEvent; + + /** @brief Key event */ + typedef typename BasicScreenedApplication::KeyEvent KeyEvent; + + /** @brief Mouse event */ + typedef typename BasicScreenedApplication::MouseEvent MouseEvent; + + /** @brief Mouse move event */ + typedef typename BasicScreenedApplication::MouseMoveEvent MouseMoveEvent; + + explicit BasicScreen(); + ~BasicScreen(); + + /** @brief Events propagated to this screen */ + PropagatedEvents propagatedEvents() const { return _propagatedEvents; } + + /** + * @brief Set events propagated to this screen + * + * For non-propagated events related event functions are not called. + * No events are propagated by default, call this function in + * @ref focusEvent() and @ref blurEvent() to reflect focus changes. + */ + void setPropagatedEvents(PropagatedEvents events) { _propagatedEvents = events; } + + /** @brief %Application holding this screen */ + BasicScreenedApplication* application() { + return Containers::LinkedListItem, BasicScreenedApplication>::list(); + } + /** @overload */ + const BasicScreenedApplication* application() const { + return Containers::LinkedListItem, BasicScreenedApplication>::list(); + } + + /** + * @brief Next nearer screen + * + * @see @ref BasicScreenedApplication::frontScreen(), + * @ref BasicScreenedApplication::backScreen() + */ + BasicScreen* nextNearerScreen() { + return Containers::LinkedListItem, BasicScreenedApplication>::previous(); + } + /** @overload */ + const BasicScreen* nextNearerScreen() const { + return Containers::LinkedListItem, BasicScreenedApplication>::previous(); + } + + /** + * @brief Next farther screen + * + * @see @ref BasicScreenedApplication::frontScreen(), + * @ref BasicScreenedApplication::backScreen() + */ + BasicScreen* nextFartherScreen() { + return Containers::LinkedListItem, BasicScreenedApplication>::next(); + } + /** @overload */ + const BasicScreen* nextFartherScreen() const { + return Containers::LinkedListItem, BasicScreenedApplication>::next(); + } + + protected: + /** @brief Request redraw */ + virtual void redraw() { application()->redraw(); } + + /** + * @brief Focus event + * + * Called when screen is focused using @ref BasicScreenedApplication::focusScreen() + * or @ref BasicScreenedApplication::addScreen(). + */ + virtual void focusEvent() = 0; + + /** + * @brief Blur event + * + * Called when another screen is focused using @ref BasicScreenedApplication::focusScreen(), + * @ref BasicScreenedApplication::addScreen() or before the screen is + * removed from application using @ref BasicScreenedApplication::removeScreen(). + */ + virtual void blurEvent() = 0; + + /** + * @brief Viewport event + * + * Called from holder application when viewport size changes. See + * @ref Sdl2Application::viewportEvent() "*Application::viewportEvent()" + * for more information. Setting viewport on default framebuffer should + * be done by the holder application. + */ + virtual void viewportEvent(const Vector2i& size) = 0; + + /** + * @brief Draw event + * + * Called when @ref PropagatedEvent::Draw is enabled and the screen is + * redrawn. See @ref Sdl2Application::viewportEvent() "*Application::viewportEvent()" + * for more information. Buffer swapping and clearing of default + * framebufer should be done by the holder application. + */ + virtual void drawEvent() = 0; + + /** + * @brief Key press event + * + * Called when @ref PropagatedEvent::Input is enabled and an key is + * pressed. See @ref Sdl2Application::keyPressEvent() "*Application::keyPressEvent()" + * for more information. + */ + virtual void keyPressEvent(KeyEvent& event); + + /** + * @brief Key release event + * + * Called when @ref PropagatedEvent::Input is enabled and an key is + * released. See @ref Sdl2Application::keyReleaseEvent() "*Application::keyReleaseEvent()" + * for more information. + */ + virtual void keyReleaseEvent(KeyEvent& event); + + /** + * @brief Mouse press event + * + * Called when @ref PropagatedEvent::Input is enabled and mouse button + * is pressed. See @ref Sdl2Application::mousePressEvent() "*Application::mousePressEvent()" + * for more information. + */ + virtual void mousePressEvent(MouseEvent& event); + + /** + * @brief Mouse release event + * + * Called when @ref PropagatedEvent::Input is enabled and mouse button + * is released. See @ref Sdl2Application::mouseReleaseEvent() "*Application::mouseReleaseEvent()" + * for more information. + */ + virtual void mouseReleaseEvent(MouseEvent& event); + + /** + * @brief Mouse move event + * + * Called when @ref PropagatedEvent::Input is enabled and mouse is + * moved. See @ref Sdl2Application::mouseMoveEvent() "*Application::mouseMoveEvent()" + * for more information. + */ + virtual void mouseMoveEvent(MouseMoveEvent& event); + + private: + PropagatedEvents _propagatedEvents; +}; + +}} + +#endif diff --git a/src/Platform/ScreenedApplication.h b/src/Platform/ScreenedApplication.h new file mode 100644 index 000000000..3bc129f2d --- /dev/null +++ b/src/Platform/ScreenedApplication.h @@ -0,0 +1,199 @@ +#ifndef Magnum_Platform_ScreenedApplication_h +#define Magnum_Platform_ScreenedApplication_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + 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 +#include + +#include "Platform/Platform.h" + +namespace Magnum { namespace Platform { + +/** +@brief Base for applications with screen management + +Manages list of screens and propagates events to them. + +If exactly one application header is included, this class is also aliased to +`Platform::ScreenedApplication`. + +Each @ref BasicScreen "Screen" specifies which set of events should be +propagated to it using @ref BasicScreen::setPropagatedEvents(). When +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()" + and @ref Sdl2Application::mouseMoveEvent() "mouseMoveEvent()") + 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. + +Traversing through the list of screens is done like following: +@code +// front-to-back +for(Screen* s = app.frontScreen(); s; s = s->nextFartherScreen()) { + // ... +} + +// back-to-front +for(Screen* s = app.backScreen(); s; s = s->nextNearerScreen()) { + // ... +} +@endcode + +@section ScreenedApplication-explicit-specializations Explicit template specializations + +The following specialization are explicitly compiled into each particular +`*Application` library. For other specializations you have to use +@ref ScreenedApplication.hpp implementation file to avoid linker errors. See +@ref compilation-speedup-hpp for more information. + +- @ref GlutApplication "BasicScreenedApplication" +- @ref GlxApplication "BasicScreenedApplication" +- @ref NaClApplication "BasicScreenedApplication" +- @ref Sdl2Application "BasicScreenedApplication" +- @ref XEglApplication "BasicScreenedApplication" +*/ +template class BasicScreenedApplication: public Application, private Containers::LinkedList> { + friend class Containers::LinkedList>; + friend class Containers::LinkedListItem, BasicScreenedApplication>; + friend class BasicScreen; + + public: + /** @copydoc Sdl2Application::Sdl2Application(const Arguments, const Configuration&) */ + BasicScreenedApplication(const typename Application::Arguments& arguments, const typename Application::Configuration& configuration = Application::Configuration()): Application(arguments, configuration) {} + + /** @copydoc Sdl2Application::Sdl2Application(const Arguments&, std::nullptr_t) */ + BasicScreenedApplication(const typename Application::Arguments& arguments, std::nullptr_t): Application(arguments, nullptr) {} + + /** + * @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& addScreen(BasicScreen& 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& removeScreen(BasicScreen& 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& focusScreen(BasicScreen& screen); + + /** + * @brief Front screen + * + * @see @ref BasicScreen::nextFartherScreen(), @ref BasicScreen::nextNearerScreen() + */ + BasicScreen* frontScreen() { + return Containers::LinkedList>::first(); + } + /** @overload */ + const BasicScreen* frontScreen() const { + return Containers::LinkedList>::first(); + } + + /** + * @brief Back screen + * + * @see @ref BasicScreen::nextFartherScreen(), @ref BasicScreen::nextNearerScreen() + */ + BasicScreen* backScreen() { + return Containers::LinkedList>::last(); + } + /** @overload */ + const BasicScreen* backScreen() const { + return Containers::LinkedList>::last(); + } + + protected: + /** + * @brief Global viewport event + * + * Called when window size changes, *before* all screens' + * @ref BasicScreen::viewportEvent() "viewportEvent()". You should at + * least pass the new size to @ref DefaultFramebuffer::setViewport(). + * + * Note that this function might not get called at all if the window + * size doesn't change. You are responsible for configuring the initial + * state yourself, viewport of default framebuffer can be retrieved + * from @ref DefaultFramebuffer::viewport(). + */ + virtual void globalViewportEvent(const Vector2i& size) = 0; + + /** + * @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; + + private: + /* The user is supposed to override only globalViewportEvent() and + globalDrawEvent(), these implementations are dispatching the events + to attached screens. */ + void viewportEvent(const Vector2i& size) override final; + void drawEvent() override final; + void keyPressEvent(typename Application::KeyEvent& event) override final; + void keyReleaseEvent(typename Application::KeyEvent& event) 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; +}; + +}} + +#endif diff --git a/src/Platform/ScreenedApplication.hpp b/src/Platform/ScreenedApplication.hpp new file mode 100644 index 000000000..329070da5 --- /dev/null +++ b/src/Platform/ScreenedApplication.hpp @@ -0,0 +1,133 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + 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 @ref compilation-speedup-hpp "Template implementation" for @ref ScreenedApplication.h and @ref Screen.h + */ + +#include "ScreenedApplication.h" + +#include "Platform/Screen.h" + +namespace Magnum { namespace Platform { + +template BasicScreen::BasicScreen() = default; +template BasicScreen::~BasicScreen() = default; + +template void BasicScreen::keyPressEvent(KeyEvent&) {} +template void BasicScreen::keyReleaseEvent(KeyEvent&) {} +template void BasicScreen::mousePressEvent(MouseEvent&) {} +template void BasicScreen::mouseReleaseEvent(MouseEvent&) {} +template void BasicScreen::mouseMoveEvent(MouseMoveEvent&) {} + +template BasicScreenedApplication& BasicScreenedApplication::addScreen(BasicScreen& screen) { + Containers::LinkedList>::insert(&screen); + if(frontScreen() == &screen) screen.focusEvent(); + return *this; +} + +template BasicScreenedApplication& BasicScreenedApplication::removeScreen(BasicScreen& screen) { + screen.blurEvent(); + Containers::LinkedList>::erase(&screen); + return *this; +} + +template BasicScreenedApplication& BasicScreenedApplication::focusScreen(BasicScreen& screen) { + /* Already focused, nothing to do */ + if(frontScreen() == &screen) return *this; + + frontScreen()->blurEvent(); + Containers::LinkedList>::move(&screen, frontScreen()); + screen.focusEvent(); + return *this; +} + +template void BasicScreenedApplication::viewportEvent(const Vector2i& size) { + /* Call viewport event after all other (because of framebuffer resizing) */ + globalViewportEvent(size); + + for(BasicScreen* s = Containers::LinkedList>::first(); s; s = s->next()) + s->viewportEvent(size); +} + +template void BasicScreenedApplication::drawEvent() { + /* Back-to-front rendering */ + for(BasicScreen* s = backScreen(); s; s = s->nextNearerScreen()) + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Draw) s->drawEvent(); + + /* Call global event after all other (because of buffer swapping) */ + globalDrawEvent(); +} + +template void BasicScreenedApplication::keyPressEvent(typename Application::KeyEvent& event) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = frontScreen(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->keyPressEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void BasicScreenedApplication::keyReleaseEvent(typename Application::KeyEvent& event) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = frontScreen(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->keyReleaseEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void BasicScreenedApplication::mousePressEvent(typename Application::MouseEvent& event) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = frontScreen(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->mousePressEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void BasicScreenedApplication::mouseReleaseEvent(typename Application::MouseEvent& event) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = frontScreen(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->mouseReleaseEvent(event); + if(event.isAccepted()) break; + } + } +} + +template void BasicScreenedApplication::mouseMoveEvent(typename Application::MouseMoveEvent& event) { + /* Front-to-back event propagation, stop when the event gets accepted */ + for(BasicScreen* s = frontScreen(); s; s = s->nextFartherScreen()) { + if(s->propagatedEvents() & Implementation::PropagatedScreenEvent::Input) { + s->mouseMoveEvent(event); + if(event.isAccepted()) break; + } + } +} + +}} diff --git a/src/Platform/Sdl2Application.cpp b/src/Platform/Sdl2Application.cpp index ccdfc4301..8c81e6c37 100644 --- a/src/Platform/Sdl2Application.cpp +++ b/src/Platform/Sdl2Application.cpp @@ -29,6 +29,7 @@ #endif #include "Context.h" +#include "Platform/ScreenedApplication.hpp" namespace Magnum { namespace Platform { @@ -262,4 +263,7 @@ Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseMoveEvent::modifier return _modifiers = fixedModifiers(SDL_GetModState()); } +template class BasicScreen; +template class BasicScreenedApplication; + }} diff --git a/src/Platform/Sdl2Application.h b/src/Platform/Sdl2Application.h index 263d9efdb..94d43eed8 100644 --- a/src/Platform/Sdl2Application.h +++ b/src/Platform/Sdl2Application.h @@ -30,6 +30,7 @@ #include +#include "Platform/Platform.h" #include "Math/Vector2.h" #include "Magnum.h" @@ -644,6 +645,8 @@ When no other application header is included this macro is also aliased to #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_APPLICATION_MAIN typedef Sdl2Application Application; +typedef BasicScreen Screen; +typedef BasicScreenedApplication ScreenedApplication; #define MAGNUM_APPLICATION_MAIN(className) MAGNUM_SDL2APPLICATION_MAIN(className) #else #undef MAGNUM_APPLICATION_MAIN diff --git a/src/Platform/XEglApplication.cpp b/src/Platform/XEglApplication.cpp index 4449db1b6..39205ebe6 100644 --- a/src/Platform/XEglApplication.cpp +++ b/src/Platform/XEglApplication.cpp @@ -24,6 +24,7 @@ #include "XEglApplication.h" +#include "Platform/ScreenedApplication.hpp" #include "Platform/Implementation/EglContextHandler.h" namespace Magnum { namespace Platform { @@ -32,4 +33,7 @@ XEglApplication::XEglApplication(const Arguments& arguments, const Configuration XEglApplication::XEglApplication(const Arguments& arguments, std::nullptr_t): AbstractXApplication(new Implementation::EglContextHandler, arguments, nullptr) {} +template class BasicScreen; +template class BasicScreenedApplication; + }} diff --git a/src/Platform/XEglApplication.h b/src/Platform/XEglApplication.h index 3d6ce8d9a..a70331159 100644 --- a/src/Platform/XEglApplication.h +++ b/src/Platform/XEglApplication.h @@ -28,6 +28,7 @@ * @brief Class @ref Magnum::Platform::XEglApplication */ +#include "Platform/Platform.h" #include "Platform/AbstractXApplication.h" namespace Magnum { namespace Platform { @@ -103,6 +104,8 @@ When no other application header is included this macro is also aliased to #ifndef DOXYGEN_GENERATING_OUTPUT #ifndef MAGNUM_APPLICATION_MAIN typedef XEglApplication Application; +typedef BasicScreen Screen; +typedef BasicScreenedApplication ScreenedApplication; #define MAGNUM_APPLICATION_MAIN(className) MAGNUM_XEGLAPPLICATION_MAIN(className) #else #undef MAGNUM_APPLICATION_MAIN