From 8489103f6a13a573c14ea3bd5dcf4a966b20aa36 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sun, 30 Jul 2017 12:03:57 -0700 Subject: [PATCH 01/24] Added Private/Utility.hh with Or for template metaprogramming --- CMakeLists.txt | 1 + Doxyfile.in | 3 +- SDL2pp/Private/Utility.hh | 70 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 SDL2pp/Private/Utility.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 51eb91e..b31df9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ SET(LIBRARY_HEADERS SDL2pp/Texture.hh SDL2pp/Wav.hh SDL2pp/Window.hh + SDL2pp/Private/Utility.hh ) SET(LIBRARY_EXTERNAL_HEADERS diff --git a/Doxyfile.in b/Doxyfile.in index 54617af..02d3b47 100644 --- a/Doxyfile.in +++ b/Doxyfile.in @@ -21,7 +21,8 @@ INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/SDL2pp" \ RECURSIVE = YES # Exclude foreign files -EXCLUDE = "@CMAKE_CURRENT_SOURCE_DIR@/SDL2pp/external" +EXCLUDE = "@CMAKE_CURRENT_SOURCE_DIR@/SDL2pp/external" \ + "@CMAKE_CURRENT_SOURCE_DIR@/SDL2pp/Private" # Examples (doesn't work atm) EXAMPLE_PATH = "@CMAKE_CURRENT_SOURCE_DIR@/examples" diff --git a/SDL2pp/Private/Utility.hh b/SDL2pp/Private/Utility.hh new file mode 100644 index 0000000..e0fb6df --- /dev/null +++ b/SDL2pp/Private/Utility.hh @@ -0,0 +1,70 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_PRIVATE_UTILITY_HH +#define SDL2PP_PRIVATE_UTILITY_HH + +#if __cplusplus > 201703L +// No need to include utility, until C++17 there +// is no definition for std::disjuntion before +#include +#endif + +#include + + +namespace SDL2pp { +/* + * This is code not to be used directly by users of SDL2pp. + */ +namespace Private { +/* + * Templated class to perform an "OR" operation on any amount of types. + * + * Usage is as follows: + * template , HasFeatureTwo> + * void UseFeatureOneOrFeatureTwo(T t) { + * // The code will be only compiled if either + * // HasFeatureOne or HasFeatureTwo are type_true + * } + */ +#if __cplusplus >= 201703L + // Use the standard definitions if they are available + template + using Or = typename std::disjunction::type; +#else + template + struct OrOperation : std::false_type { }; + + template + struct OrOperation : T { }; + + template + struct OrOperation : std::conditional> { }; + + template + using Or = typename OrOperation::type; +#endif +} +} + +#endif From 315d032b3b7437370310b01118eb522122c94f65 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sun, 30 Jul 2017 12:43:49 -0700 Subject: [PATCH 02/24] Added And operation for template metaprogramming --- SDL2pp/Private/Utility.hh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/SDL2pp/Private/Utility.hh b/SDL2pp/Private/Utility.hh index e0fb6df..7ba47f0 100644 --- a/SDL2pp/Private/Utility.hh +++ b/SDL2pp/Private/Utility.hh @@ -64,6 +64,35 @@ namespace Private { template using Or = typename OrOperation::type; #endif + +/* + * Templated class to perform an "AND" operation on any amount of types. + * + * Usage is as follows: + * template , HasFeatureTwo> + * void UseFeatureOneAndFeatureTwo(T t) { + * // The code will be only compiled if both + * // HasFeatureOne and HasFeatureTwo are type_true + * } + */ +#if __cplusplus >= 201703L + // Use the standard definitions if they are available + template + using And = typename std::conjunction::type; +#else + template + struct AndOperation : std::true_type { }; + + template + struct AndOperation : T { }; + + template + struct AndOperation : std::conditional, T> { }; + + template + using And = typename AndOperation::type; +#endif } } From 3c3d45d94c66cb922f8c622b28590f9c115f58f1 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sun, 30 Jul 2017 23:44:28 -0700 Subject: [PATCH 03/24] Added TupleHasType class for template metaprogramming --- SDL2pp/Private/Utility.hh | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/SDL2pp/Private/Utility.hh b/SDL2pp/Private/Utility.hh index 7ba47f0..67e6403 100644 --- a/SDL2pp/Private/Utility.hh +++ b/SDL2pp/Private/Utility.hh @@ -28,9 +28,9 @@ #include #endif +#include #include - namespace SDL2pp { /* * This is code not to be used directly by users of SDL2pp. @@ -93,6 +93,25 @@ namespace Private { template using And = typename AndOperation::type; #endif + +/* + * Templated class to an specific type in a tuple, returns std::true_type if the + * tuple contains T, std::false_type otherwise. + */ +template +struct TupleHasTypeOperation; + +template +struct TupleHasTypeOperation> : std::false_type { }; + +template +struct TupleHasTypeOperation> : TupleHasTypeOperation> { }; + +template +struct TupleHasTypeOperation> : std::true_type { }; + +template +using TupleHasType = typename TupleHasTypeOperation::type; } } From 6375e5f79a5f73ffa42edf53e76ef498f3b43ca2 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Mon, 31 Jul 2017 00:16:42 -0700 Subject: [PATCH 04/24] Added class to identify EventHandlerFunctors with template metaprogramming --- CMakeLists.txt | 1 + SDL2pp/Private/EventHandlerFunctor.hh | 60 +++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 SDL2pp/Private/EventHandlerFunctor.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index b31df9a..90d6c72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ SET(LIBRARY_HEADERS SDL2pp/Texture.hh SDL2pp/Wav.hh SDL2pp/Window.hh + SDL2pp/Private/EventHandlerFunctor.hh SDL2pp/Private/Utility.hh ) diff --git a/SDL2pp/Private/EventHandlerFunctor.hh b/SDL2pp/Private/EventHandlerFunctor.hh new file mode 100644 index 0000000..17ca78b --- /dev/null +++ b/SDL2pp/Private/EventHandlerFunctor.hh @@ -0,0 +1,60 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_PRIVATE_EVENTHANDLERFUNCTOR_HH +#define SDL2PP_PRIVATE_EVENTHANDLERFUNCTOR_HH + +#include +#include + +namespace SDL2pp { +/* + * This is code not to be used directly by users of SDL2pp. + */ +namespace Private { + /* + * Helper alias to help identify a functor object with the correct signature + * to be used as an event handler. + */ + template + using EventHandlerFunctorSignature = std::function; + + /* + * Templated class to identify a class that is not an event handler functor. + */ + template + struct IsEventHandlerFunctor : std::false_type { }; + + /* + * Templated class to identify a class that is an event handler functor, the + * way this is done is by verifying if the functor is assignable to the + * expected signature. + */ + template + struct IsEventHandlerFunctor< + EventHandlerType, + EventType, + std::is_convertible> + > : std::true_type { }; +} +} + +#endif From 04e10e978837e53be929cd2b55dd90d72cbb7af8 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Mon, 31 Jul 2017 00:37:19 -0700 Subject: [PATCH 05/24] Added class to identify EventHandlerObjects with template metaprogramming --- CMakeLists.txt | 1 + SDL2pp/Private/EventHandlerObject.hh | 56 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 SDL2pp/Private/EventHandlerObject.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 90d6c72..c9118e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ SET(LIBRARY_HEADERS SDL2pp/Wav.hh SDL2pp/Window.hh SDL2pp/Private/EventHandlerFunctor.hh + SDL2pp/Private/EventHandlerObject.hh SDL2pp/Private/Utility.hh ) diff --git a/SDL2pp/Private/EventHandlerObject.hh b/SDL2pp/Private/EventHandlerObject.hh new file mode 100644 index 0000000..45a486c --- /dev/null +++ b/SDL2pp/Private/EventHandlerObject.hh @@ -0,0 +1,56 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_PRIVATE_EVENTHANDLEROBJECT_HH +#define SDL2PP_PRIVATE_EVENTHANDLEROBJECT_HH + +#include + +namespace SDL2pp { +/* + * This is code not to be used directly by users of SDL2pp. + */ +namespace Private { + /* + * Templated class to identify a class that is not an event handler object. + */ + template + struct IsEventHandlerObject : std::false_type { }; + + /* + * Templated class to identify a class that is an event handler object, the + * way this is done is by verifying that an instance of EventHandlerType has + * the "HandleEvent" member function which received a "const EventType &" + * and returns void. + */ + template + struct IsEventHandlerObject< + EventHandlerType, + EventType, + std::is_same< + decltype(std::declval().HandleEvent(std::declval())), + void + > + > : std::true_type { }; +} +} + +#endif From 56931b52615bad891b7a95079f202794f45cdbc5 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Mon, 31 Jul 2017 00:51:57 -0700 Subject: [PATCH 06/24] Added class IsEventHandler to help identify valid event handlers with template metaprogramming --- CMakeLists.txt | 1 + SDL2pp/Private/EventHandler.hh | 105 +++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 SDL2pp/Private/EventHandler.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index c9118e9..68a526b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,7 @@ SET(LIBRARY_HEADERS SDL2pp/Texture.hh SDL2pp/Wav.hh SDL2pp/Window.hh + SDL2pp/Private/EventHandler.hh SDL2pp/Private/EventHandlerFunctor.hh SDL2pp/Private/EventHandlerObject.hh SDL2pp/Private/Utility.hh diff --git a/SDL2pp/Private/EventHandler.hh b/SDL2pp/Private/EventHandler.hh new file mode 100644 index 0000000..e8a825e --- /dev/null +++ b/SDL2pp/Private/EventHandler.hh @@ -0,0 +1,105 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_PRIVATE_EVENTHANDLER_HH +#define SDL2PP_PRIVATE_EVENTHANDLER_HH + +#include +#include +#include + +#include +#include + +#include + +namespace SDL2pp { +/* + * This is code not to be used directly by users of SDL2pp. + */ +namespace Private { + /* + * Tuple containing all the valid events that can be handled. + */ + using ValidEventTypes = std::tuple< + SDL_Event, + SDL_AudioDeviceEvent, + SDL_ControllerAxisEvent, + SDL_ControllerButtonEvent, + SDL_ControllerDeviceEvent, + SDL_DollarGestureEvent, + SDL_DropEvent, + SDL_JoyAxisEvent, + SDL_JoyBallEvent, + SDL_JoyButtonEvent, + SDL_JoyDeviceEvent, + SDL_JoyHatEvent, + SDL_KeyboardEvent, + SDL_MouseButtonEvent, + SDL_MouseMotionEvent, + SDL_MouseWheelEvent, + SDL_MultiGestureEvent, + SDL_QuitEvent, + SDL_SysWMEvent, + SDL_TextEditingEvent, + SDL_TextInputEvent, + SDL_TouchFingerEvent, + SDL_UserEvent, + SDL_WindowEvent + >; + + /* + * Templated class to identify a class that is not an event handler. + */ + template + struct IsEventHandler : std::false_type { }; + + /* + * Templated class to identify a type that is an event handler, the type + * EventHandlerType is considered to be an event handler if is either an + * event handler object or an event handler functor for the given event + * type. Also the event type must be a valid SDL event type. + * + * In other words, any of the following code can be executed: + * { + * EventType event; + * EventHandlerType eventHandler; + * eventHandler(event); + * // or + * eventHandler.HandleEvent(event); + * } + */ + template + struct IsEventHandler< + EventHandlerType, + EventType, + And< + Or< + IsEventHandlerObject, + IsEventHandlerFunctor + >, + TupleHasType + > + > : std::true_type { }; +} +} + +#endif From 0b636118b9759234d502d44b6ea8e67e67915c04 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Mon, 31 Jul 2017 01:55:31 -0700 Subject: [PATCH 07/24] Added EventPolling (needs to implement DispatchEvent) --- CMakeLists.txt | 1 + SDL2pp/EventPolling.hh | 52 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 SDL2pp/EventPolling.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 68a526b..5007857 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,6 +145,7 @@ SET(LIBRARY_HEADERS SDL2pp/AudioSpec.hh SDL2pp/Color.hh SDL2pp/ContainerRWops.hh + SDL2pp/EventPolling.hh SDL2pp/Exception.hh SDL2pp/Optional.hh SDL2pp/Point.hh diff --git a/SDL2pp/EventPolling.hh b/SDL2pp/EventPolling.hh new file mode 100644 index 0000000..24199be --- /dev/null +++ b/SDL2pp/EventPolling.hh @@ -0,0 +1,52 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_EVENTPOLLING_HH +#define SDL2PP_EVENTPOLLING_HH + +#include + +namespace SDL2pp { +namespace Event { + template + bool PollEvent(EventHandlers&&...) { + SDL_Event event; + if (!SDL_PollEvent(&event)) { + return false; + } + + // TODO: Private::DispatchEvent(event, eventHandlers...); + + return true; + } + + template + int PollAllEvents(EventHandlers&&... eventHandlers) { + int result; + + for (result = 0; PollEvent(eventHandlers...); result++); + + return result; + } +} +} + +#endif From e5d873a7ed6b7cc18708ee998f81b7a5ca370aeb Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sat, 5 Aug 2017 13:57:30 -0700 Subject: [PATCH 08/24] Added event dispatching --- CMakeLists.txt | 1 + SDL2pp/EventPolling.hh | 5 ++- SDL2pp/Private/EventDispatching.hh | 70 ++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 SDL2pp/Private/EventDispatching.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 5007857..c38a26e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ SET(LIBRARY_HEADERS SDL2pp/Texture.hh SDL2pp/Wav.hh SDL2pp/Window.hh + SDL2pp/Private/EventDispatching.hh SDL2pp/Private/EventHandler.hh SDL2pp/Private/EventHandlerFunctor.hh SDL2pp/Private/EventHandlerObject.hh diff --git a/SDL2pp/EventPolling.hh b/SDL2pp/EventPolling.hh index 24199be..1dd2570 100644 --- a/SDL2pp/EventPolling.hh +++ b/SDL2pp/EventPolling.hh @@ -22,18 +22,19 @@ #ifndef SDL2PP_EVENTPOLLING_HH #define SDL2PP_EVENTPOLLING_HH -#include +#include namespace SDL2pp { namespace Event { template - bool PollEvent(EventHandlers&&...) { + bool PollEvent(EventHandlers&&... eventHandlers) { SDL_Event event; if (!SDL_PollEvent(&event)) { return false; } // TODO: Private::DispatchEvent(event, eventHandlers...); + Private::DispatchEvent(event, eventHandlers...); return true; } diff --git a/SDL2pp/Private/EventDispatching.hh b/SDL2pp/Private/EventDispatching.hh new file mode 100644 index 0000000..6b671a6 --- /dev/null +++ b/SDL2pp/Private/EventDispatching.hh @@ -0,0 +1,70 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_PRIVATE_EVENTDISPATCHING_HH +#define SDL2PP_PRIVATE_EVENTDISPATCHING_HH + +#include + +#include + +#include + +namespace SDL2pp { +namespace Private +{ + template + auto DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler) -> std::enable_if::value> + { + eventHandler(event); + } + + template + auto DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler) -> std::enable_if::value> + { + eventHandler.HandleEvent(event); + } + + template + auto DispatchEvent(const SDL_Event&, EventHandler&&) -> std::enable_if::value> + { + static_assert(!IsEventHandler::value, "One of the given values is not a valid event handler"); + } + + template + void DispatchEvent(const SDL_Event & event, EventHandlers&&... eventHandlers) { + DispatchEvent(event, eventHandlers...); + } + + template + void DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler, EventHandlers&&... eventHandlers) { + DispatchEvent(event, eventHandler); + DispatchEvent(event, eventHandlers...); + } + + template <> + void DispatchEvent(const SDL_Event &) { + // no-op + } +} +} + +#endif From 8c873d644dec2fbc87c6a00fb99fb8e1a68080da Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sat, 5 Aug 2017 14:58:21 -0700 Subject: [PATCH 09/24] Added tests for Private/Utility.hh --- tests/CMakeLists.txt | 1 + tests/test_utility.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/test_utility.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1c14256..1eb1e61 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,7 @@ SET(CLI_TESTS test_pointrect test_pointrect_constexpr test_rwops + test_utility test_wav ) diff --git a/tests/test_utility.cc b/tests/test_utility.cc new file mode 100644 index 0000000..ca420c3 --- /dev/null +++ b/tests/test_utility.cc @@ -0,0 +1,28 @@ +#include + +#include + +using namespace SDL2pp::Private; +using namespace std; + +int main(int, char*[]) { + static_assert(Or::value, "OR(true, true) should be true"); + static_assert(Or::value, "OR(true, false) should be true"); + static_assert(Or::value, "OR(false, true) should be true"); + static_assert(!Or::value, "OR(false, false) should be false"); + + static_assert(And::value, "AND(true, true) should be true"); + static_assert(!And::value, "AND(true, false) should be false"); + static_assert(!And::value, "AND(false, true) should be false"); + static_assert(!And::value, "AND(false, false) should be false"); + + struct A { }; + struct B { }; + struct C { }; + + static_assert(TupleHasType>::value, ""); + static_assert(TupleHasType>::value, ""); + static_assert(!TupleHasType>::value, ""); + + return 0; +} From a52074324e67832b9cdc575af594c0c934581b41 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sat, 5 Aug 2017 16:38:01 -0700 Subject: [PATCH 10/24] Added EventHandler tests --- tests/CMakeLists.txt | 1 + tests/test_eventhandler.cc | 69 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/test_eventhandler.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1eb1e61..a66c299 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,6 +3,7 @@ SET(CLI_TESTS test_color test_color_constexpr test_error + test_eventhandler test_optional test_pointrect test_pointrect_constexpr diff --git a/tests/test_eventhandler.cc b/tests/test_eventhandler.cc new file mode 100644 index 0000000..b76893f --- /dev/null +++ b/tests/test_eventhandler.cc @@ -0,0 +1,69 @@ +#include + +#include + +using namespace SDL2pp::Private; + +void EventHandlerFunction(const SDL_Event &); + +struct EventHandlerOperator { + void operator()(SDL_Event); +}; + +struct EventHandler { + void HandleEvent(const SDL_Event &); +}; + +struct InvalidEventHandler { + void HandleEvent(SDL_Event); +}; + +int main(int, char*[]) { + auto lambda = [](const SDL_Event &) { }; + + // Test IsEventHandlerFunctor + static_assert( + IsEventHandlerFunctor::value, + "IsEventHandlerFunctor<> should accept functions like void(const SDL_Event &)" + ); + static_assert( + IsEventHandlerFunctor::value, + "IsEventHandlerFunctor<> should accept functions like void(const SDL_Event &)" + ); + static_assert( + !IsEventHandlerFunctor::value, + "IsEventHandlerFunctor<> shouldn't accept a class with operator(const SDL_Event &)" + ); + + // Test IsEventHandlerObject + static_assert( + IsEventHandlerObject::value, + "IsEventHandlerObject<> should accept a class with HandleEvent(const SDL_Event &)" + ); + static_assert( + !IsEventHandlerObject::value, + "IsEventHandlerObject<> shouldn't accept a class with a different HandleEvent() signature" + ); + + // Test IsEventHandler + static_assert( + IsEventHandler::value, + "IsEventHandler<> should accept functions like void(const SDL_Event &)" + ); + static_assert( + IsEventHandler::value, + "IsEventHandler<> should accept functions like void(const SDL_Event &)" + ); + static_assert( + IsEventHandler::value, + "IsEventHandler<> should accept a class with HandleEvent(const SDL_Event &)" + ); + static_assert( + !IsEventHandler::value, + "IsEventHandler<> shouldn't accept a class with operator(const SDL_Event &)" + ); + static_assert( + !IsEventHandler::value, + "IsEventHandler<> shouldn't accept a class with a different HandleEvent() signature" + ); +} From ab48a57a406f0db467986a1f0752e0e4f9d4971a Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sat, 5 Aug 2017 16:39:02 -0700 Subject: [PATCH 11/24] Added enable_if for the EventHandler templates --- SDL2pp/Private/EventHandler.hh | 16 +++++++++------- SDL2pp/Private/EventHandlerFunctor.hh | 4 +++- SDL2pp/Private/EventHandlerObject.hh | 16 ++++++++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/SDL2pp/Private/EventHandler.hh b/SDL2pp/Private/EventHandler.hh index e8a825e..9ca240d 100644 --- a/SDL2pp/Private/EventHandler.hh +++ b/SDL2pp/Private/EventHandler.hh @@ -91,13 +91,15 @@ namespace Private { struct IsEventHandler< EventHandlerType, EventType, - And< - Or< - IsEventHandlerObject, - IsEventHandlerFunctor - >, - TupleHasType - > + typename std::enable_if< + And< + Or< + IsEventHandlerObject, + IsEventHandlerFunctor + >, + TupleHasType + >::value + >::type > : std::true_type { }; } } diff --git a/SDL2pp/Private/EventHandlerFunctor.hh b/SDL2pp/Private/EventHandlerFunctor.hh index 17ca78b..1b2f41e 100644 --- a/SDL2pp/Private/EventHandlerFunctor.hh +++ b/SDL2pp/Private/EventHandlerFunctor.hh @@ -52,7 +52,9 @@ namespace Private { struct IsEventHandlerFunctor< EventHandlerType, EventType, - std::is_convertible> + typename std::enable_if< + std::is_convertible>::value + >::type > : std::true_type { }; } } diff --git a/SDL2pp/Private/EventHandlerObject.hh b/SDL2pp/Private/EventHandlerObject.hh index 45a486c..df3d9ee 100644 --- a/SDL2pp/Private/EventHandlerObject.hh +++ b/SDL2pp/Private/EventHandlerObject.hh @@ -29,6 +29,15 @@ namespace SDL2pp { * This is code not to be used directly by users of SDL2pp. */ namespace Private { + /* + * Templated class to detect if a given type can handle a given event. + */ + template + struct HasEventHandlerMethod : std::is_same< + decltype(std::declval().HandleEvent(std::declval())), + void + > { }; + /* * Templated class to identify a class that is not an event handler object. */ @@ -45,10 +54,9 @@ namespace Private { struct IsEventHandlerObject< EventHandlerType, EventType, - std::is_same< - decltype(std::declval().HandleEvent(std::declval())), - void - > + typename std::enable_if< + HasEventHandlerMethod::value + >::type > : std::true_type { }; } } From 04f7c2a3658c377436524b6e29ea95af9e935299 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sat, 5 Aug 2017 22:16:14 -0700 Subject: [PATCH 12/24] More fixes for event handlers meta programming logic --- SDL2pp/Private/EventHandlerFunctor.hh | 9 +----- SDL2pp/Private/EventHandlerObject.hh | 18 ++++-------- tests/test_eventhandler.cc | 42 +++++++++++++-------------- 3 files changed, 28 insertions(+), 41 deletions(-) diff --git a/SDL2pp/Private/EventHandlerFunctor.hh b/SDL2pp/Private/EventHandlerFunctor.hh index 1b2f41e..e8daed9 100644 --- a/SDL2pp/Private/EventHandlerFunctor.hh +++ b/SDL2pp/Private/EventHandlerFunctor.hh @@ -30,13 +30,6 @@ namespace SDL2pp { * This is code not to be used directly by users of SDL2pp. */ namespace Private { - /* - * Helper alias to help identify a functor object with the correct signature - * to be used as an event handler. - */ - template - using EventHandlerFunctorSignature = std::function; - /* * Templated class to identify a class that is not an event handler functor. */ @@ -53,7 +46,7 @@ namespace Private { EventHandlerType, EventType, typename std::enable_if< - std::is_convertible>::value + std::is_convertible>::value >::type > : std::true_type { }; } diff --git a/SDL2pp/Private/EventHandlerObject.hh b/SDL2pp/Private/EventHandlerObject.hh index df3d9ee..2e55000 100644 --- a/SDL2pp/Private/EventHandlerObject.hh +++ b/SDL2pp/Private/EventHandlerObject.hh @@ -29,15 +29,6 @@ namespace SDL2pp { * This is code not to be used directly by users of SDL2pp. */ namespace Private { - /* - * Templated class to detect if a given type can handle a given event. - */ - template - struct HasEventHandlerMethod : std::is_same< - decltype(std::declval().HandleEvent(std::declval())), - void - > { }; - /* * Templated class to identify a class that is not an event handler object. */ @@ -47,15 +38,18 @@ namespace Private { /* * Templated class to identify a class that is an event handler object, the * way this is done is by verifying that an instance of EventHandlerType has - * the "HandleEvent" member function which received a "const EventType &" - * and returns void. + * the "HandleEvent" member function which received a "EventType" and + * returns void. */ template struct IsEventHandlerObject< EventHandlerType, EventType, typename std::enable_if< - HasEventHandlerMethod::value + std::is_same< + decltype(std::declval().HandleEvent(std::declval())), + void + >::value >::type > : std::true_type { }; } diff --git a/tests/test_eventhandler.cc b/tests/test_eventhandler.cc index b76893f..aafb345 100644 --- a/tests/test_eventhandler.cc +++ b/tests/test_eventhandler.cc @@ -4,66 +4,66 @@ using namespace SDL2pp::Private; -void EventHandlerFunction(const SDL_Event &); +void EventHandlerFunction(SDL_Event); -struct EventHandlerOperator { +struct EventHandlerFunctor { void operator()(SDL_Event); }; struct EventHandler { - void HandleEvent(const SDL_Event &); -}; - -struct InvalidEventHandler { void HandleEvent(SDL_Event); }; +struct InvalidEventHandler { + void handleEvent(SDL_Event); +}; + int main(int, char*[]) { - auto lambda = [](const SDL_Event &) { }; + auto lambda = [](SDL_Event) { }; // Test IsEventHandlerFunctor static_assert( IsEventHandlerFunctor::value, - "IsEventHandlerFunctor<> should accept functions like void(const SDL_Event &)" + "IsEventHandlerFunctor<> should accept functions like void(SDL_Event)" ); static_assert( IsEventHandlerFunctor::value, - "IsEventHandlerFunctor<> should accept functions like void(const SDL_Event &)" + "IsEventHandlerFunctor<> should accept functions like void(SDL_Event)" ); static_assert( - !IsEventHandlerFunctor::value, - "IsEventHandlerFunctor<> shouldn't accept a class with operator(const SDL_Event &)" + IsEventHandlerFunctor::value, + "IsEventHandlerFunctor<> shouldn accept a class with operator(SDL_Event)" ); // Test IsEventHandlerObject static_assert( IsEventHandlerObject::value, - "IsEventHandlerObject<> should accept a class with HandleEvent(const SDL_Event &)" + "IsEventHandlerObject<> should accept a class with HandleEvent(SDL_Event)" ); static_assert( !IsEventHandlerObject::value, - "IsEventHandlerObject<> shouldn't accept a class with a different HandleEvent() signature" + "IsEventHandlerObject<> shouldn't accept a class without a valid signature" ); // Test IsEventHandler static_assert( IsEventHandler::value, - "IsEventHandler<> should accept functions like void(const SDL_Event &)" + "IsEventHandler<> should accept functions like void(SDL_Event)" ); static_assert( IsEventHandler::value, - "IsEventHandler<> should accept functions like void(const SDL_Event &)" + "IsEventHandler<> should accept functions like void(SDL_Event)" + ); + static_assert( + IsEventHandler::value, + "IsEventHandler<> should accept a class with operator(SDL_Event)" ); static_assert( IsEventHandler::value, - "IsEventHandler<> should accept a class with HandleEvent(const SDL_Event &)" - ); - static_assert( - !IsEventHandler::value, - "IsEventHandler<> shouldn't accept a class with operator(const SDL_Event &)" + "IsEventHandler<> should accept a class with HandleEvent(SDL_Event)" ); static_assert( !IsEventHandler::value, - "IsEventHandler<> shouldn't accept a class with a different HandleEvent() signature" + "IsEventHandler<> shouldn't accept a class without a valid signature" ); } From 06f1d48de47d1742eba5a759c2ae7465982a3309 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sat, 5 Aug 2017 23:08:12 -0700 Subject: [PATCH 13/24] Added basic event dispatching (needs event types specialization) --- SDL2pp/Private/EventDispatching.hh | 27 +++++++------- tests/CMakeLists.txt | 1 + tests/test_eventdispatching.cc | 57 ++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 13 deletions(-) create mode 100644 tests/test_eventdispatching.cc diff --git a/SDL2pp/Private/EventDispatching.hh b/SDL2pp/Private/EventDispatching.hh index 6b671a6..7299bca 100644 --- a/SDL2pp/Private/EventDispatching.hh +++ b/SDL2pp/Private/EventDispatching.hh @@ -28,35 +28,36 @@ #include +#include +using namespace std; + namespace SDL2pp { namespace Private { template - auto DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler) -> std::enable_if::value> - { - eventHandler(event); - } - - template - auto DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler) -> std::enable_if::value> + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type { eventHandler.HandleEvent(event); } template - auto DispatchEvent(const SDL_Event&, EventHandler&&) -> std::enable_if::value> + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type { - static_assert(!IsEventHandler::value, "One of the given values is not a valid event handler"); + eventHandler(event); + } + + template + auto DispatchSpecificEvent(const SDL_Event &, EventHandler&&) -> typename std::enable_if::value>::type + { + static_assert(IsEventHandler::value, "Event handler is not a valid functor or object"); } template - void DispatchEvent(const SDL_Event & event, EventHandlers&&... eventHandlers) { - DispatchEvent(event, eventHandlers...); - } + void DispatchEvent(const SDL_Event &, EventHandlers&&...); template void DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler, EventHandlers&&... eventHandlers) { - DispatchEvent(event, eventHandler); + DispatchSpecificEvent(event, eventHandler); DispatchEvent(event, eventHandlers...); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a66c299..e8a9cfc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,6 +3,7 @@ SET(CLI_TESTS test_color test_color_constexpr test_error + test_eventdispatching test_eventhandler test_optional test_pointrect diff --git a/tests/test_eventdispatching.cc b/tests/test_eventdispatching.cc new file mode 100644 index 0000000..e7fca38 --- /dev/null +++ b/tests/test_eventdispatching.cc @@ -0,0 +1,57 @@ +#include + +#include + +#include "testing.h" + +using namespace SDL2pp::Private; + +static auto globalResult = Sint32{0}; + +inline void handler(SDL_Event event) +{ + globalResult = event.user.code; +} + +BEGIN_TEST(int, char*[]) + +SDL_Event event; +event.type = SDL_USEREVENT; +event.user.code = 31; + +DispatchEvent(event); + +auto result = Sint32{0}; +DispatchEvent(event, [&result](SDL_Event event) { + result = event.user.code; +}); +EXPECT_EQUAL(event.user.code, result); + +DispatchEvent(event, handler); +EXPECT_EQUAL(event.user.code, globalResult); + +struct EventHandlerFunctor { + Sint32 result; + + void operator()(SDL_Event event) { + result = event.user.code; + } +}; + +auto eventHandlerFunctor = EventHandlerFunctor{}; +DispatchEvent(event, eventHandlerFunctor); +EXPECT_EQUAL(event.user.code, eventHandlerFunctor.result); + +struct EventHandlerObject { + Sint32 result; + + void HandleEvent(SDL_Event event) { + result = event.user.code; + } +}; + +auto eventHandlerObject = EventHandlerObject{}; +DispatchEvent(event, eventHandlerObject); +EXPECT_EQUAL(event.user.code, eventHandlerObject.result); + +END_TEST() From c53f01931b5f57fd4a90ef06c77eb263101e4e60 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Sun, 6 Aug 2017 16:28:51 -0700 Subject: [PATCH 14/24] Added dispatching for all events --- SDL2pp/Private/EventDispatching.hh | 353 ++++++++++++++++++++++++++++- tests/test_eventdispatching.cc | 12 + 2 files changed, 359 insertions(+), 6 deletions(-) diff --git a/SDL2pp/Private/EventDispatching.hh b/SDL2pp/Private/EventDispatching.hh index 7299bca..63b01b6 100644 --- a/SDL2pp/Private/EventDispatching.hh +++ b/SDL2pp/Private/EventDispatching.hh @@ -27,30 +27,371 @@ #include #include - -#include -using namespace std; +#include namespace SDL2pp { namespace Private { + template + void DispatchEventToObject(const EventType &event, EventHandler&& eventHandler) { + eventHandler.HandleEvent(event); + } + + template + void DispatchEventToFunctor(const EventType &event, EventHandler&& eventHandler) { + eventHandler(event); + } + template auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type { - eventHandler.HandleEvent(event); + DispatchEventToObject(event, eventHandler); } template auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type { - eventHandler(event); + DispatchEventToFunctor(event, eventHandler); + } + +#if SDL_VERSION_ATLEAST(2, 0, 5) + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_AUDIODEVICEADDED || event.type == SDL_AUDIODEVICEREMOVED) + DispatchEventToObject(event.type, eventHandler); } template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_AUDIODEVICEADDED || event.type == SDL_AUDIODEVICEREMOVED) + DispatchEventToFunctor(event.type, eventHandler); + } +#endif + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_CONTROLLERAXISMOTION) + DispatchEventToObject(event.caxis, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_CONTROLLERAXISMOTION) + DispatchEventToFunctor(event.caxis, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONDOWN) + DispatchEventToObject(event.cbutton, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONDOWN) + DispatchEventToFunctor(event.cbutton, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_CONTROLLERDEVICEADDED || event.type == SDL_CONTROLLERDEVICEREMOVED || event.type == SDL_CONTROLLERDEVICEREMAPPED) + DispatchEventToObject(event.cdevice, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_CONTROLLERDEVICEADDED || event.type == SDL_CONTROLLERDEVICEREMOVED || event.type == SDL_CONTROLLERDEVICEREMAPPED) + DispatchEventToFunctor(event.cdevice, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_DOLLARGESTURE || event.type == SDL_DOLLARRECORD) + DispatchEventToObject(event.dgesture, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_DOLLARGESTURE || event.type == SDL_DOLLARRECORD) + DispatchEventToFunctor(event.dgesture, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT +#if SDL_VERSION_ATLEAST(2, 0, 5) + || event.type == SDL_DROPBEGIN || event.type == SDL_DROPCOMPLETE +#endif + ) + DispatchEventToObject(event.drop, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT +#if SDL_VERSION_ATLEAST(2, 0, 5) + || event.type == SDL_DROPBEGIN || event.type == SDL_DROPCOMPLETE +#endif + ) + DispatchEventToObject(event.drop, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYAXISMOTION) + DispatchEventToObject(event.jaxis, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYAXISMOTION) + DispatchEventToFunctor(event.jaxis, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYBALLMOTION) + DispatchEventToObject(event.jball, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYBALLMOTION) + DispatchEventToFunctor(event.jball, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP) + DispatchEventToObject(event.jbutton, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP) + DispatchEventToFunctor(event.jbutton, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED) + DispatchEventToObject(event.jdevice, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED) + DispatchEventToFunctor(event.jdevice, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYHATMOTION) + DispatchEventToObject(event.jhat, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_JOYHATMOTION) + DispatchEventToFunctor(event.jhat, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) + DispatchEventToObject(event.key, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) + DispatchEventToFunctor(event.key, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) + DispatchEventToObject(event.button, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) + DispatchEventToFunctor(event.button, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MOUSEMOTION) + DispatchEventToObject(event.motion, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MOUSEMOTION) + DispatchEventToFunctor(event.motion, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MOUSEWHEEL) + DispatchEventToObject(event.wheel, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MOUSEWHEEL) + DispatchEventToFunctor(event.wheel, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MULTIGESTURE) + DispatchEventToObject(event.mgesture, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_MULTIGESTURE) + DispatchEventToFunctor(event.mgesture, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_QUIT) + DispatchEventToObject(event.quit, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_QUIT) + DispatchEventToFunctor(event.quit, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_SYSWMEVENT) + DispatchEventToObject(event.syswm, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_SYSWMEVENT) + DispatchEventToFunctor(event.syswm, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_TEXTEDITING) + DispatchEventToObject(event.edit, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_TEXTEDITING) + DispatchEventToFunctor(event.edit, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_TEXTINPUT) + DispatchEventToObject(event.text, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_TEXTINPUT) + DispatchEventToFunctor(event.text, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP) + DispatchEventToObject(event.tfinger, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP) + DispatchEventToFunctor(event.tfinger, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_USEREVENT) + DispatchEventToObject(event.user, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_USEREVENT) + DispatchEventToFunctor(event.user, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_WINDOWEVENT) + DispatchEventToObject(event.window, eventHandler); + } + + template + auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { + if (event.type == SDL_WINDOWEVENT) + DispatchEventToFunctor(event.window, eventHandler); + } + + // TODO: Find an easy way to make IsEventHandler + /*template auto DispatchSpecificEvent(const SDL_Event &, EventHandler&&) -> typename std::enable_if::value>::type { static_assert(IsEventHandler::value, "Event handler is not a valid functor or object"); - } + }*/ template void DispatchEvent(const SDL_Event &, EventHandlers&&...); diff --git a/tests/test_eventdispatching.cc b/tests/test_eventdispatching.cc index e7fca38..183505f 100644 --- a/tests/test_eventdispatching.cc +++ b/tests/test_eventdispatching.cc @@ -54,4 +54,16 @@ auto eventHandlerObject = EventHandlerObject{}; DispatchEvent(event, eventHandlerObject); EXPECT_EQUAL(event.user.code, eventHandlerObject.result); +struct SpecificEventHandler { + Sint32 result; + + void HandleEvent(SDL_UserEvent event) { + result = event.code; + } +}; + +auto specificEventHandler = SpecificEventHandler{}; +DispatchEvent(event, specificEventHandler); +EXPECT_EQUAL(event.user.code, specificEventHandler.result); + END_TEST() From 09268ce431b6627e36a00704f173a4da150a90d1 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 01:50:26 -0700 Subject: [PATCH 15/24] Added event types filters --- CMakeLists.txt | 1 + SDL2pp/Private/EventHandler.hh | 2 +- SDL2pp/Private/EventTypeFilters.hh | 107 +++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 SDL2pp/Private/EventTypeFilters.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index c38a26e..c09e687 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ SET(LIBRARY_HEADERS SDL2pp/Private/EventHandler.hh SDL2pp/Private/EventHandlerFunctor.hh SDL2pp/Private/EventHandlerObject.hh + SDL2pp/Private/EventTypeFilters.hh SDL2pp/Private/Utility.hh ) diff --git a/SDL2pp/Private/EventHandler.hh b/SDL2pp/Private/EventHandler.hh index 9ca240d..a869e7e 100644 --- a/SDL2pp/Private/EventHandler.hh +++ b/SDL2pp/Private/EventHandler.hh @@ -62,7 +62,7 @@ namespace Private { SDL_TextEditingEvent, SDL_TextInputEvent, SDL_TouchFingerEvent, - SDL_UserEvent, + //SDL_UserEvent, <- User events are a special case SDL_WindowEvent >; diff --git a/SDL2pp/Private/EventTypeFilters.hh b/SDL2pp/Private/EventTypeFilters.hh new file mode 100644 index 0000000..c0dcaac --- /dev/null +++ b/SDL2pp/Private/EventTypeFilters.hh @@ -0,0 +1,107 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2017 Vraiment + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_PRIVATE_EVENTHANDLERBYTYPE_HH +#define SDL2PP_PRIVATE_EVENTHANDLERBYTYPE_HH + +#include + +#include + +namespace SDL2pp { +/* + * This is code not to be used directly by users of SDL2pp. + */ +namespace Private { + /* + * Templated struct that is used to: + * - Verify an event is of the given type + * - Get the specific event for that given type + */ + template + struct EventTypeFilter { + // Should return true if the given event is of the type EventType + static bool ShouldHandleEvent(const SDL_Event &); + + // Should return the member of SDL_Event that is of the given EventType + static const EventType &GetEventByType(const SDL_Event &event); + }; + + // SDL_Event is defined without a macro because the arguments are not used + // this shutdowns "unnused variables" warnings on some compilers + template <> + struct EventTypeFilter { + static bool ShouldHandleEvent(const SDL_Event &) { + return true; + } + + static const SDL_Event &GetEventByType(const SDL_Event &event) { + return event; + } + }; + +// I use a macro here to make things less verbose +#define SDL2PP_DEFINE_EVENT_MAPPING(eventType, condition, eventObject) template<>\ + struct EventTypeFilter {\ + static bool ShouldHandleEvent(const SDL_Event &event) {\ + return condition;\ + }\ + \ + static const eventType &GetEventByType(const SDL_Event &event) {\ + return eventObject;\ + }\ + } + +#if SDL_VERSION_ATLEAST(2, 0, 4) + SDL2PP_DEFINE_EVENT_MAPPING(SDL_AudioDeviceEvent, event.type == SDL_AUDIODEVICEADDED || event.type == SDL_AUDIODEVICEREMOVED, event.adevice); +#endif + SDL2PP_DEFINE_EVENT_MAPPING(SDL_ControllerAxisEvent, event.type == SDL_CONTROLLERAXISMOTION, event.caxis); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_ControllerButtonEvent, event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONUP, event.cbutton); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_ControllerDeviceEvent, event.type == SDL_CONTROLLERDEVICEADDED || event.type == SDL_CONTROLLERDEVICEREMOVED || event.type == SDL_CONTROLLERDEVICEREMAPPED, event.cdevice); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_DollarGestureEvent, event.type == SDL_DOLLARGESTURE || event.type == SDL_DOLLARRECORD, event.dgesture); +#if SDL_VERSION_ATLEAST(2, 0, 5) + SDL2PP_DEFINE_EVENT_MAPPING(SDL_DropEvent, event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT || event.type == SDL_DROPBEGIN || event.type == SDL_DROPCOMPLETE, event.drop); +#else + SDL2PP_DEFINE_EVENT_MAPPING(SDL_DropEvent, event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT, event.drop); +#endif + SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyAxisEvent, event.type == SDL_JOYAXISMOTION, event.jaxis); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyBallEvent, event.type == SDL_JOYBALLMOTION, event.jball); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyButtonEvent, event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP, event.jbutton); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyDeviceEvent, event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED, event.jdevice); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyHatEvent, event.type == SDL_JOYHATMOTION, event.jhat); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_KeyboardEvent, event.type == SDL_KEYDOWN || event.type == SDL_KEYUP, event.key); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_MouseButtonEvent, event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP, event.button); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_MouseMotionEvent, event.type == SDL_MOUSEMOTION, event.motion); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_MouseWheelEvent, event.type == SDL_MOUSEWHEEL, event.wheel); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_MultiGestureEvent, event.type == SDL_MULTIGESTURE, event.mgesture); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_QuitEvent, event.type == SDL_QUIT, event.quit); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_SysWMEvent, event.type == SDL_SYSWMEVENT, event.syswm); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_TextEditingEvent, event.type == SDL_TEXTEDITING, event.edit); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_TextInputEvent, event.type == SDL_TEXTINPUT, event.text); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_TouchFingerEvent, event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP, event.tfinger); + //SDL2PP_DEFINE_EVENT_MAPPING(SDL_UserEvent, event.type == SDL_USEREVENT, event.user); <- This won't work + SDL2PP_DEFINE_EVENT_MAPPING(SDL_WindowEvent, event.type == SDL_WINDOWEVENT, event.window); + +#undef SDL2PP_DEFINE_EVENT_MAPPING +} +} + +#endif From b470eae400a0152df34636ab98c835dc8de3ed31 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 02:00:22 -0700 Subject: [PATCH 16/24] Changed event dispatching to use EventTypeFilter and all the EventTypes --- SDL2pp/Private/EventDispatching.hh | 469 +++++++---------------------- tests/test_eventdispatching.cc | 155 +++++++--- 2 files changed, 220 insertions(+), 404 deletions(-) diff --git a/SDL2pp/Private/EventDispatching.hh b/SDL2pp/Private/EventDispatching.hh index 63b01b6..d91a40b 100644 --- a/SDL2pp/Private/EventDispatching.hh +++ b/SDL2pp/Private/EventDispatching.hh @@ -22,386 +22,139 @@ #ifndef SDL2PP_PRIVATE_EVENTDISPATCHING_HH #define SDL2PP_PRIVATE_EVENTDISPATCHING_HH -#include - -#include - -#include -#include +#include namespace SDL2pp { -namespace Private -{ +/* + * This is code not to be used directly by users of SDL2pp. + */ +namespace Private { + /* + * Templated function to dynamically dispatch an event of type EventType to an event handler functor of type EventHandler. + * + * This will be only called if 'eventHandler(event)' + */ template - void DispatchEventToObject(const EventType &event, EventHandler&& eventHandler) { - eventHandler.HandleEvent(event); - } - - template - void DispatchEventToFunctor(const EventType &event, EventHandler&& eventHandler) { + auto DispatchEventHandlerFunctor(const EventType &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + { eventHandler(event); } - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + /* + * Templated function to do nothing when trying to dispatch an event of type EventType to an invalid event handler functor of type EventHandler. + */ + template + auto DispatchEventHandlerFunctor(const EventType &, EventHandler&&) -> typename std::enable_if::value>::type { - DispatchEventToObject(event, eventHandler); + // no-op } - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + /* + * Templated function to do nothing when trying to dispatch an event of type EventType to an invalid event handler object of type EventHandler. + */ + template + auto DispatchEventHandlerObject(const EventType &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type { - DispatchEventToFunctor(event, eventHandler); + eventHandler.HandleEvent(event); } -#if SDL_VERSION_ATLEAST(2, 0, 5) - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + /* + * Templated function to dynamically dispatch an event of type EventType to an event handler object of type EventHandler. + * + * This will be only called if 'eventHandler.HandleEvent(event)' + */ + template + auto DispatchEventHandlerObject(const EventType &, EventHandler&&) -> typename std::enable_if::value>::type { - if (event.type == SDL_AUDIODEVICEADDED || event.type == SDL_AUDIODEVICEREMOVED) - DispatchEventToObject(event.type, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_AUDIODEVICEADDED || event.type == SDL_AUDIODEVICEREMOVED) - DispatchEventToFunctor(event.type, eventHandler); - } -#endif - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_CONTROLLERAXISMOTION) - DispatchEventToObject(event.caxis, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_CONTROLLERAXISMOTION) - DispatchEventToFunctor(event.caxis, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONDOWN) - DispatchEventToObject(event.cbutton, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONDOWN) - DispatchEventToFunctor(event.cbutton, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_CONTROLLERDEVICEADDED || event.type == SDL_CONTROLLERDEVICEREMOVED || event.type == SDL_CONTROLLERDEVICEREMAPPED) - DispatchEventToObject(event.cdevice, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_CONTROLLERDEVICEADDED || event.type == SDL_CONTROLLERDEVICEREMOVED || event.type == SDL_CONTROLLERDEVICEREMAPPED) - DispatchEventToFunctor(event.cdevice, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_DOLLARGESTURE || event.type == SDL_DOLLARRECORD) - DispatchEventToObject(event.dgesture, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_DOLLARGESTURE || event.type == SDL_DOLLARRECORD) - DispatchEventToFunctor(event.dgesture, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT -#if SDL_VERSION_ATLEAST(2, 0, 5) - || event.type == SDL_DROPBEGIN || event.type == SDL_DROPCOMPLETE -#endif - ) - DispatchEventToObject(event.drop, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT -#if SDL_VERSION_ATLEAST(2, 0, 5) - || event.type == SDL_DROPBEGIN || event.type == SDL_DROPCOMPLETE -#endif - ) - DispatchEventToObject(event.drop, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYAXISMOTION) - DispatchEventToObject(event.jaxis, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYAXISMOTION) - DispatchEventToFunctor(event.jaxis, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYBALLMOTION) - DispatchEventToObject(event.jball, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYBALLMOTION) - DispatchEventToFunctor(event.jball, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP) - DispatchEventToObject(event.jbutton, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP) - DispatchEventToFunctor(event.jbutton, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED) - DispatchEventToObject(event.jdevice, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYDEVICEADDED || event.type == SDL_JOYDEVICEREMOVED) - DispatchEventToFunctor(event.jdevice, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYHATMOTION) - DispatchEventToObject(event.jhat, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_JOYHATMOTION) - DispatchEventToFunctor(event.jhat, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) - DispatchEventToObject(event.key, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) - DispatchEventToFunctor(event.key, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) - DispatchEventToObject(event.button, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) - DispatchEventToFunctor(event.button, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MOUSEMOTION) - DispatchEventToObject(event.motion, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MOUSEMOTION) - DispatchEventToFunctor(event.motion, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MOUSEWHEEL) - DispatchEventToObject(event.wheel, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MOUSEWHEEL) - DispatchEventToFunctor(event.wheel, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MULTIGESTURE) - DispatchEventToObject(event.mgesture, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_MULTIGESTURE) - DispatchEventToFunctor(event.mgesture, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_QUIT) - DispatchEventToObject(event.quit, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_QUIT) - DispatchEventToFunctor(event.quit, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_SYSWMEVENT) - DispatchEventToObject(event.syswm, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_SYSWMEVENT) - DispatchEventToFunctor(event.syswm, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_TEXTEDITING) - DispatchEventToObject(event.edit, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_TEXTEDITING) - DispatchEventToFunctor(event.edit, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_TEXTINPUT) - DispatchEventToObject(event.text, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_TEXTINPUT) - DispatchEventToFunctor(event.text, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP) - DispatchEventToObject(event.tfinger, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP) - DispatchEventToFunctor(event.tfinger, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_USEREVENT) - DispatchEventToObject(event.user, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_USEREVENT) - DispatchEventToFunctor(event.user, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_WINDOWEVENT) - DispatchEventToObject(event.window, eventHandler); - } - - template - auto DispatchSpecificEvent(const SDL_Event &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type - { - if (event.type == SDL_WINDOWEVENT) - DispatchEventToFunctor(event.window, eventHandler); + // no-op } - // TODO: Find an easy way to make IsEventHandler - /*template - auto DispatchSpecificEvent(const SDL_Event &, EventHandler&&) -> typename std::enable_if::value>::type - { - static_assert(IsEventHandler::value, "Event handler is not a valid functor or object"); - }*/ + /* + * Templated class to dispatch an event to a given event handler: + * + * EventHandler is the type of the event handler + * ValidEventHandler is a boolean to detect if the event was actially valid for any of the event types + * EvenTypes is a tuple containing a list of valid event types + * + * Basically, this class would be roughly the equivalent of the following pseudocode: + * + * DispatchEvent(SDL_Event event, EventHandler eventHandler, EventTypes eventTypes) { + * auto validEventHandler = false; + * + * for (auto eventType : eventTypes) { + * validEventHandler |= IsValidEventHandler(EventHandler, eventType); + * if (ShouldHandleEvent(event)) { + * DispatchEventToFunctor(event, eventHandler); + * DispatchEventToObject(event, eventHandler); + * } + * } + * + * if (!validEventHandler) throw; + * } + */ + template + struct EventDispatcher; + + /* + * Instatiation of the class to dispatch an event to a given event handler, expansion to a given type: + * + * The head of the tuple is "peeled" and used to dispatch the event to the event handler. + * The tail then is passed to another expansion of EventDispatcher along with the calculated value of IsEventHandler + * + */ + template + struct EventDispatcher> { + static constexpr bool IsValidEventHandler = ValidEventHandler || IsEventHandler::value; + + using Filter = EventTypeFilter; + + static void DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler) { + if (Filter::ShouldHandleEvent(event)) { + DispatchEventHandlerFunctor(Filter::GetEventByType(event), std::forward(eventHandler)); + DispatchEventHandlerObject(Filter::GetEventByType(event), std::forward(eventHandler)); + + } + + EventDispatcher>::DispatchEvent(event, std::forward(eventHandler)); + } + }; + + /* + * Instantiation of the class to dispatch an event to a given event handler, final expansion: + * + * The tuple of valid event types is empty and the value of the ValidEventHandler boolean + * is placed in the IsValidEventHandler variable, finally when an event gets dispatched + * an static_assert happens to verify if the event handler actually handled any events. + */ + template + struct EventDispatcher> { + static constexpr auto IsValidEventHandler = ValidEventHandler; + + static void DispatchEvent(const SDL_Event &, EventHandler&&) { + static_assert(IsValidEventHandler, "One of the given event handlers is not a valid one"); + } + }; + /* + * Templated class expand a list of event handlers so they can be dispatched. + */ template void DispatchEvent(const SDL_Event &, EventHandlers&&...); - + + /* + * Instantiation of the class to expand a list of event handlers so they can be dispatched. + * + * This "peels" the first event handler from the arguments, dispatchs it and then expands the tail of the list. + */ template void DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler, EventHandlers&&... eventHandlers) { - DispatchSpecificEvent(event, eventHandler); + EventDispatcher::DispatchEvent(event, std::forward(eventHandler)); DispatchEvent(event, eventHandlers...); } - + + /* + * Instantiation of the class to expand a list of event handlers, when the list is empty. + */ template <> void DispatchEvent(const SDL_Event &) { // no-op diff --git a/tests/test_eventdispatching.cc b/tests/test_eventdispatching.cc index 183505f..903d526 100644 --- a/tests/test_eventdispatching.cc +++ b/tests/test_eventdispatching.cc @@ -6,64 +6,127 @@ using namespace SDL2pp::Private; -static auto globalResult = Sint32{0}; +namespace TestFreeFunctions { + static auto globalResult = Sint32{0}; -inline void handler(SDL_Event event) -{ - globalResult = event.user.code; + inline void handler(SDL_Event event) { + globalResult = event.user.code; + } } BEGIN_TEST(int, char*[]) + // These test require a major rework, commenting everything in the mean time + SDL_Event event; + event.type = SDL_QUIT; + event.user.code = 31; -SDL_Event event; -event.type = SDL_USEREVENT; -event.user.code = 31; + // Test dispatching with no event handler + DispatchEvent(event); -DispatchEvent(event); - -auto result = Sint32{0}; -DispatchEvent(event, [&result](SDL_Event event) { - result = event.user.code; -}); -EXPECT_EQUAL(event.user.code, result); - -DispatchEvent(event, handler); -EXPECT_EQUAL(event.user.code, globalResult); - -struct EventHandlerFunctor { - Sint32 result; - - void operator()(SDL_Event event) { - result = event.user.code; + // Test dispatching with lambda as event handler + { + auto result = Sint32{0}; + DispatchEvent(event, [&result](SDL_Event event) { + result = event.user.code; + }); + EXPECT_EQUAL(event.user.code, result); } -}; -auto eventHandlerFunctor = EventHandlerFunctor{}; -DispatchEvent(event, eventHandlerFunctor); -EXPECT_EQUAL(event.user.code, eventHandlerFunctor.result); - -struct EventHandlerObject { - Sint32 result; - - void HandleEvent(SDL_Event event) { - result = event.user.code; + // Test dispatching with function as event handler + { + DispatchEvent(event, TestFreeFunctions::handler); + EXPECT_EQUAL(event.user.code, TestFreeFunctions::globalResult); } -}; -auto eventHandlerObject = EventHandlerObject{}; -DispatchEvent(event, eventHandlerObject); -EXPECT_EQUAL(event.user.code, eventHandlerObject.result); + // Test dispatching with a functor as event handler + { + struct EventHandlerFunctor { + Sint32 result; -struct SpecificEventHandler { - Sint32 result; + void operator()(SDL_Event event) { + result = event.user.code; + } + }; + + auto eventHandlerFunctor = EventHandlerFunctor{}; + DispatchEvent(event, eventHandlerFunctor); + EXPECT_EQUAL(event.user.code, eventHandlerFunctor.result); + } + + // Test dispatching with an object as event handler + { + struct EventHandlerObject { + Sint32 result; + + void HandleEvent(SDL_Event event) { + result = event.user.code; + } + }; + + auto eventHandlerObject = EventHandlerObject{}; + DispatchEvent(event, eventHandlerObject); + EXPECT_EQUAL(event.user.code, eventHandlerObject.result); + } + + // Test several event handlers + { + struct EventHandlerFunctor { + bool executed = false; + + void operator()(SDL_QuitEvent) { + executed = true; + } + }; + auto eventHandlerFunctor1 = EventHandlerFunctor{}; + auto eventHandlerFunctor2 = EventHandlerFunctor{}; + + struct EventHandlerObject { + bool executed = false; + + void HandleEvent(SDL_QuitEvent) { + executed = true; + } + }; + auto eventHandlerObject = EventHandlerObject{}; - void HandleEvent(SDL_UserEvent event) { - result = event.code; + auto lambdaExecuted = false; + auto lambda = [&lambdaExecuted](SDL_QuitEvent) { lambdaExecuted = true; }; + + DispatchEvent(event, eventHandlerFunctor1, eventHandlerFunctor2, eventHandlerObject, lambda); + EXPECT_TRUE(eventHandlerFunctor1.executed); + EXPECT_TRUE(eventHandlerFunctor2.executed); + EXPECT_TRUE(eventHandlerObject.executed); + EXPECT_TRUE(lambdaExecuted); } -}; - -auto specificEventHandler = SpecificEventHandler{}; -DispatchEvent(event, specificEventHandler); -EXPECT_EQUAL(event.user.code, specificEventHandler.result); + // Test event handler with several event types + { + struct EventHandler { + bool quitEventExecuted = false; + bool keyboardEventExecuted = false; + + void HandleEvent(SDL_QuitEvent) { + quitEventExecuted = true; + } + + void HandleEvent(SDL_KeyboardEvent) { + keyboardEventExecuted = true; + } + }; + + auto eventHandler = EventHandler{}; + DispatchEvent(event, eventHandler); + + EXPECT_TRUE(eventHandler.quitEventExecuted); + EXPECT_TRUE(!eventHandler.keyboardEventExecuted); + + eventHandler.quitEventExecuted = false; + + event.type = SDL_KEYUP; + + DispatchEvent(event, eventHandler); + + EXPECT_TRUE(!eventHandler.quitEventExecuted); + EXPECT_TRUE(eventHandler.keyboardEventExecuted); + } END_TEST() From 40a5297f0e6bb14dc840be38fa96caab9a6b9e5f Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 20:23:10 -0700 Subject: [PATCH 17/24] Added comments and EventPolling header to master header --- SDL2pp/EventPolling.hh | 53 ++++++++++++++++++++++++++++++++++++++++-- SDL2pp/SDL2pp.hh | 8 +++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/SDL2pp/EventPolling.hh b/SDL2pp/EventPolling.hh index 1dd2570..6e4e96a 100644 --- a/SDL2pp/EventPolling.hh +++ b/SDL2pp/EventPolling.hh @@ -26,6 +26,32 @@ namespace SDL2pp { namespace Event { + //////////////////////////////////////////////////////////// + /// \brief Polls and handles a single event + /// + /// This function tries to poll a single event from the event + /// queue using SDL_PollEvent(). If an event was polled the + /// event handler is called using the retrieved SDL_Event as an + /// argument then this function returns true. If no event was + /// retrieved the event handler is not called and this function + /// returns false. + /// + /// This function accepts the following as event handlers: + /// - Functors (lambdas, free functions, callable objects) + /// - Objects (Objects that have a HandleEvent(EventType) function) + /// + /// \ingroup events + /// + /// \headerfile SDL2pp/EventPolling.hh + /// + /// \param[in] eventHandlers A list of event handlers that will handle the event + /// + /// \returns True if an event was polled, false otherwise + /// + /// \see https://wiki.libsdl.org/SDL_PollEvent + /// \see https://wiki.libsdl.org/CategoryEvents#Structures + /// + //////////////////////////////////////////////////////////// template bool PollEvent(EventHandlers&&... eventHandlers) { SDL_Event event; @@ -33,12 +59,35 @@ namespace Event { return false; } - // TODO: Private::DispatchEvent(event, eventHandlers...); Private::DispatchEvent(event, eventHandlers...); return true; } - + + //////////////////////////////////////////////////////////// + /// \brief Polls and handles all the events from the event queue + /// + /// This function calls SDL_PollEvent() until the event queue is empty. + /// Then for each event that was polled the event handler is called + /// using the polled event as an argument. This function returns the + /// amount of events that were polled. + /// + /// This function accepts the following as event handlers: + /// - Functors (lambdas, free functions, callable objects) + /// - Objects (Objects that have a HandleEvent(EventType) function) + /// + /// \ingroup events + /// + /// \headerfile SDL2pp/EventPolling.hh + /// + /// \param[in] eventHandlers A list of event handlers that will handle the polled event + /// + /// \returns The amount of polled events (can be zero) + /// + /// \see https://wiki.libsdl.org/SDL_PollEvent + /// \see https://wiki.libsdl.org/CategoryEvents#Structures + /// + //////////////////////////////////////////////////////////// template int PollAllEvents(EventHandlers&&... eventHandlers) { int result; diff --git a/SDL2pp/SDL2pp.hh b/SDL2pp/SDL2pp.hh index 22110b4..61e0153 100644 --- a/SDL2pp/SDL2pp.hh +++ b/SDL2pp/SDL2pp.hh @@ -97,6 +97,14 @@ #include #include +/////////////////////////////////////////////////////////// +/// \defgroup events Event handling +/// +/// \brief Functions and classes to easily manage SDL events +/// +//////////////////////////////////////////////////////////// +#include + #ifdef SDL2PP_WITH_TTF //////////////////////////////////////////////////////////// /// \defgroup ttf SDL_ttf From f6695239d5cc549254a0d599134916f68a5eb553 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 20:26:52 -0700 Subject: [PATCH 18/24] Added SDL_UserEvent support --- SDL2pp/Private/EventHandler.hh | 2 +- SDL2pp/Private/EventTypeFilters.hh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SDL2pp/Private/EventHandler.hh b/SDL2pp/Private/EventHandler.hh index a869e7e..9ca240d 100644 --- a/SDL2pp/Private/EventHandler.hh +++ b/SDL2pp/Private/EventHandler.hh @@ -62,7 +62,7 @@ namespace Private { SDL_TextEditingEvent, SDL_TextInputEvent, SDL_TouchFingerEvent, - //SDL_UserEvent, <- User events are a special case + SDL_UserEvent, SDL_WindowEvent >; diff --git a/SDL2pp/Private/EventTypeFilters.hh b/SDL2pp/Private/EventTypeFilters.hh index c0dcaac..3ff4404 100644 --- a/SDL2pp/Private/EventTypeFilters.hh +++ b/SDL2pp/Private/EventTypeFilters.hh @@ -97,7 +97,7 @@ namespace Private { SDL2PP_DEFINE_EVENT_MAPPING(SDL_TextEditingEvent, event.type == SDL_TEXTEDITING, event.edit); SDL2PP_DEFINE_EVENT_MAPPING(SDL_TextInputEvent, event.type == SDL_TEXTINPUT, event.text); SDL2PP_DEFINE_EVENT_MAPPING(SDL_TouchFingerEvent, event.type == SDL_FINGERMOTION || event.type == SDL_FINGERDOWN || event.type == SDL_FINGERUP, event.tfinger); - //SDL2PP_DEFINE_EVENT_MAPPING(SDL_UserEvent, event.type == SDL_USEREVENT, event.user); <- This won't work + SDL2PP_DEFINE_EVENT_MAPPING(SDL_UserEvent, SDL_USEREVENT <= event.type && event.type <= SDL_LASTEVENT, event.user); SDL2PP_DEFINE_EVENT_MAPPING(SDL_WindowEvent, event.type == SDL_WINDOWEVENT, event.window); #undef SDL2PP_DEFINE_EVENT_MAPPING From 90b0138390ad9c7a5c29168351d11b7bb47fed53 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 20:32:23 -0700 Subject: [PATCH 19/24] Merged headers that define what an event handler is --- CMakeLists.txt | 2 - SDL2pp/Private/EventHandler.hh | 47 +++++++++++++++++++++- SDL2pp/Private/EventHandlerFunctor.hh | 55 ------------------------- SDL2pp/Private/EventHandlerObject.hh | 58 --------------------------- 4 files changed, 45 insertions(+), 117 deletions(-) delete mode 100644 SDL2pp/Private/EventHandlerFunctor.hh delete mode 100644 SDL2pp/Private/EventHandlerObject.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index c09e687..723c373 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,8 +161,6 @@ SET(LIBRARY_HEADERS SDL2pp/Window.hh SDL2pp/Private/EventDispatching.hh SDL2pp/Private/EventHandler.hh - SDL2pp/Private/EventHandlerFunctor.hh - SDL2pp/Private/EventHandlerObject.hh SDL2pp/Private/EventTypeFilters.hh SDL2pp/Private/Utility.hh ) diff --git a/SDL2pp/Private/EventHandler.hh b/SDL2pp/Private/EventHandler.hh index 9ca240d..fc673c7 100644 --- a/SDL2pp/Private/EventHandler.hh +++ b/SDL2pp/Private/EventHandler.hh @@ -22,10 +22,9 @@ #ifndef SDL2PP_PRIVATE_EVENTHANDLER_HH #define SDL2PP_PRIVATE_EVENTHANDLER_HH -#include -#include #include +#include #include #include @@ -66,6 +65,50 @@ namespace Private { SDL_WindowEvent >; + /* + * Templated class to identify a class that is not an event handler functor. + */ + template + struct IsEventHandlerFunctor : std::false_type { }; + + /* + * Templated class to identify a class that is an event handler functor, the + * way this is done is by verifying if the functor is assignable to the + * expected signature. + */ + template + struct IsEventHandlerFunctor< + EventHandlerType, + EventType, + typename std::enable_if< + std::is_convertible>::value + >::type + > : std::true_type { }; + + /* + * Templated class to identify a class that is not an event handler object. + */ + template + struct IsEventHandlerObject : std::false_type { }; + + /* + * Templated class to identify a class that is an event handler object, the + * way this is done is by verifying that an instance of EventHandlerType has + * the "HandleEvent" member function which received a "EventType" and + * returns void. + */ + template + struct IsEventHandlerObject< + EventHandlerType, + EventType, + typename std::enable_if< + std::is_same< + decltype(std::declval().HandleEvent(std::declval())), + void + >::value + >::type + > : std::true_type { }; + /* * Templated class to identify a class that is not an event handler. */ diff --git a/SDL2pp/Private/EventHandlerFunctor.hh b/SDL2pp/Private/EventHandlerFunctor.hh deleted file mode 100644 index e8daed9..0000000 --- a/SDL2pp/Private/EventHandlerFunctor.hh +++ /dev/null @@ -1,55 +0,0 @@ -/* - libSDL2pp - C++11 bindings/wrapper for SDL2 - Copyright (C) 2017 Vraiment - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#ifndef SDL2PP_PRIVATE_EVENTHANDLERFUNCTOR_HH -#define SDL2PP_PRIVATE_EVENTHANDLERFUNCTOR_HH - -#include -#include - -namespace SDL2pp { -/* - * This is code not to be used directly by users of SDL2pp. - */ -namespace Private { - /* - * Templated class to identify a class that is not an event handler functor. - */ - template - struct IsEventHandlerFunctor : std::false_type { }; - - /* - * Templated class to identify a class that is an event handler functor, the - * way this is done is by verifying if the functor is assignable to the - * expected signature. - */ - template - struct IsEventHandlerFunctor< - EventHandlerType, - EventType, - typename std::enable_if< - std::is_convertible>::value - >::type - > : std::true_type { }; -} -} - -#endif diff --git a/SDL2pp/Private/EventHandlerObject.hh b/SDL2pp/Private/EventHandlerObject.hh deleted file mode 100644 index 2e55000..0000000 --- a/SDL2pp/Private/EventHandlerObject.hh +++ /dev/null @@ -1,58 +0,0 @@ -/* - libSDL2pp - C++11 bindings/wrapper for SDL2 - Copyright (C) 2017 Vraiment - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#ifndef SDL2PP_PRIVATE_EVENTHANDLEROBJECT_HH -#define SDL2PP_PRIVATE_EVENTHANDLEROBJECT_HH - -#include - -namespace SDL2pp { -/* - * This is code not to be used directly by users of SDL2pp. - */ -namespace Private { - /* - * Templated class to identify a class that is not an event handler object. - */ - template - struct IsEventHandlerObject : std::false_type { }; - - /* - * Templated class to identify a class that is an event handler object, the - * way this is done is by verifying that an instance of EventHandlerType has - * the "HandleEvent" member function which received a "EventType" and - * returns void. - */ - template - struct IsEventHandlerObject< - EventHandlerType, - EventType, - typename std::enable_if< - std::is_same< - decltype(std::declval().HandleEvent(std::declval())), - void - >::value - >::type - > : std::true_type { }; -} -} - -#endif From d64bdb3449dccf2841b12bbe79dbadf6c4499b7a Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 20:44:38 -0700 Subject: [PATCH 20/24] Added more event dispatching events --- tests/test_eventdispatching.cc | 50 ++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/tests/test_eventdispatching.cc b/tests/test_eventdispatching.cc index 903d526..81a2702 100644 --- a/tests/test_eventdispatching.cc +++ b/tests/test_eventdispatching.cc @@ -17,6 +17,7 @@ namespace TestFreeFunctions { BEGIN_TEST(int, char*[]) // These test require a major rework, commenting everything in the mean time SDL_Event event; + event.common.timestamp = 98; event.type = SDL_QUIT; event.user.code = 31; @@ -122,11 +123,56 @@ BEGIN_TEST(int, char*[]) eventHandler.quitEventExecuted = false; - event.type = SDL_KEYUP; + SDL_Event keyboardEvent; + keyboardEvent.type = SDL_KEYUP; - DispatchEvent(event, eventHandler); + DispatchEvent(keyboardEvent, eventHandler); EXPECT_TRUE(!eventHandler.quitEventExecuted); EXPECT_TRUE(eventHandler.keyboardEventExecuted); } + + // Test call event handler that's both a functor and object + { + struct EventHandler { + bool quitEventFunctorExecuted = false; + bool quitEventObjectExecuted = false; + + void operator()(SDL_QuitEvent) { + quitEventFunctorExecuted = true; + } + + void HandleEvent(SDL_QuitEvent) { + quitEventObjectExecuted = true; + } + }; + + auto eventHandler = EventHandler{}; + DispatchEvent(event, eventHandler); + + EXPECT_TRUE(eventHandler.quitEventFunctorExecuted); + EXPECT_TRUE(eventHandler.quitEventObjectExecuted); + } + + // Test don't call event handler with annotated types + { + struct EventHandler { + bool quitEventFunctorExecuted = false; + bool quitEventObjectExecuted = false; + + void operator()(SDL_QuitEvent) { + quitEventFunctorExecuted = true; + } + + void HandleEvent(SDL_QuitEvent &) { + quitEventObjectExecuted = true; + } + }; + + auto eventHandler = EventHandler{}; + DispatchEvent(event, eventHandler); + + EXPECT_TRUE(eventHandler.quitEventFunctorExecuted); + EXPECT_TRUE(!eventHandler.quitEventObjectExecuted); + } END_TEST() From a8edb0fe668487711b855fc7124ff4f1ba267051 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 21:15:11 -0700 Subject: [PATCH 21/24] Added tests for event polling --- tests/CMakeLists.txt | 1 + tests/test_eventpolling.cc | 76 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/test_eventpolling.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e8a9cfc..b1f63e3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ SET(CLI_TESTS test_error test_eventdispatching test_eventhandler + test_eventpolling test_optional test_pointrect test_pointrect_constexpr diff --git a/tests/test_eventpolling.cc b/tests/test_eventpolling.cc new file mode 100644 index 0000000..fbe24d9 --- /dev/null +++ b/tests/test_eventpolling.cc @@ -0,0 +1,76 @@ +#include + +#include +#include + +#include "testing.h" + +using namespace SDL2pp; +using namespace SDL2pp::Event; + +BEGIN_TEST(int, char*[]) + SDL sdl{SDL_INIT_EVENTS}; + + // Empty event poll + SDL_Event event; + while (SDL_PollEvent(&event)); + + // Poll a single event + { + event.type = SDL_KEYUP; + SDL_PushEvent(&event); + + EXPECT_TRUE(PollEvent()); + EXPECT_TRUE(!PollEvent()); // Verify no additional events + } + + // Poll multiple events single event + { + event.type = SDL_KEYUP; + constexpr auto amountOfEvents = 5; + for (auto n = 0; n < amountOfEvents; n++) + SDL_PushEvent(&event); + + EXPECT_EQUAL(PollAllEvents(), amountOfEvents); + EXPECT_TRUE(!PollEvent()); // Verify no additional events + } + + // Poll with an event handler + { + struct EventHandler { + int eventsHandled = 0; + int keyboardEventsHandled = 0; + bool quitEventHandled = false; + + void HandleEvent(SDL_Event) { + eventsHandled++; + } + + void HandleEvent(SDL_KeyboardEvent) { + keyboardEventsHandled++; + } + + void HandleEvent(SDL_QuitEvent) { + quitEventHandled = true; + } + }; + + event.type = SDL_KEYUP; + SDL_PushEvent(&event); + + event.type = SDL_KEYDOWN; + SDL_PushEvent(&event); + + event.type = SDL_QUIT; + SDL_PushEvent(&event); + + auto eventHandler = EventHandler{}; + + EXPECT_EQUAL(PollAllEvents(eventHandler), 3); + EXPECT_TRUE(!PollEvent()); // Verify no additional events + + EXPECT_EQUAL(eventHandler.eventsHandled, 3); + EXPECT_EQUAL(eventHandler.keyboardEventsHandled, 2); + EXPECT_EQUAL(eventHandler.quitEventHandled, true); + } +END_TEST() From 3c903e101fb6bb383abb19f479805c21f910c622 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Tue, 8 Aug 2017 23:01:08 -0700 Subject: [PATCH 22/24] Minor updates to comments, template parameters names in EventDispatching.hh --- SDL2pp/Private/EventDispatching.hh | 67 +++++++++++++++--------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/SDL2pp/Private/EventDispatching.hh b/SDL2pp/Private/EventDispatching.hh index d91a40b..9108e2c 100644 --- a/SDL2pp/Private/EventDispatching.hh +++ b/SDL2pp/Private/EventDispatching.hh @@ -30,41 +30,42 @@ namespace SDL2pp { */ namespace Private { /* - * Templated function to dynamically dispatch an event of type EventType to an event handler functor of type EventHandler. + * Templated function to dynamically dispatch an event of type EventType to an event handler functor of type EventHandlerType. * - * This will be only called if 'eventHandler(event)' + * This will be only called if 'eventHandler(event)' can be called */ - template - auto DispatchEventHandlerFunctor(const EventType &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + template + auto DispatchEventHandlerFunctor(const EventType &event, EventHandlerType&& eventHandler) -> typename std::enable_if::value>::type { eventHandler(event); } /* - * Templated function to do nothing when trying to dispatch an event of type EventType to an invalid event handler functor of type EventHandler. + * Templated function to do nothing when trying to dispatch an event of type EventType to an invalid event handler functor of type EventHandlerType. */ - template - auto DispatchEventHandlerFunctor(const EventType &, EventHandler&&) -> typename std::enable_if::value>::type + template + auto DispatchEventHandlerFunctor(const EventType &, EventHandlerType&&) -> typename std::enable_if::value>::type { // no-op } /* - * Templated function to do nothing when trying to dispatch an event of type EventType to an invalid event handler object of type EventHandler. + * Templated function to dynamically dispatch an event of type EventType to an event handler object of type EventHandlerType. + * + * This will be only called if 'eventHandler.HandleEvent(event)' can be called */ - template - auto DispatchEventHandlerObject(const EventType &event, EventHandler&& eventHandler) -> typename std::enable_if::value>::type + template + auto DispatchEventHandlerObject(const EventType &event, EventHandlerType&& eventHandler) -> typename std::enable_if::value>::type { eventHandler.HandleEvent(event); } + /* - * Templated function to dynamically dispatch an event of type EventType to an event handler object of type EventHandler. - * - * This will be only called if 'eventHandler.HandleEvent(event)' + * Templated function to do nothing when trying to dispatch an event of type EventType to an invalid event handler object of type EventHandlerType. */ - template - auto DispatchEventHandlerObject(const EventType &, EventHandler&&) -> typename std::enable_if::value>::type + template + auto DispatchEventHandlerObject(const EventType &, EventHandlerType&&) -> typename std::enable_if::value>::type { // no-op } @@ -72,13 +73,13 @@ namespace Private { /* * Templated class to dispatch an event to a given event handler: * - * EventHandler is the type of the event handler * ValidEventHandler is a boolean to detect if the event was actially valid for any of the event types + * EventHandlerType is the type of the event handler * EvenTypes is a tuple containing a list of valid event types * * Basically, this class would be roughly the equivalent of the following pseudocode: * - * DispatchEvent(SDL_Event event, EventHandler eventHandler, EventTypes eventTypes) { + * DispatchEvent(SDL_Event event, EventHandlerType eventHandler, EventTypes eventTypes) { * auto validEventHandler = false; * * for (auto eventType : eventTypes) { @@ -92,7 +93,7 @@ namespace Private { * if (!validEventHandler) throw; * } */ - template + template struct EventDispatcher; /* @@ -102,20 +103,20 @@ namespace Private { * The tail then is passed to another expansion of EventDispatcher along with the calculated value of IsEventHandler * */ - template - struct EventDispatcher> { - static constexpr bool IsValidEventHandler = ValidEventHandler || IsEventHandler::value; + template + struct EventDispatcher> { + static constexpr bool IsValidEventHandler = ValidEventHandler || IsEventHandler::value; using Filter = EventTypeFilter; - static void DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler) { + static void DispatchEvent(const SDL_Event &event, EventHandlerType&& eventHandler) { if (Filter::ShouldHandleEvent(event)) { - DispatchEventHandlerFunctor(Filter::GetEventByType(event), std::forward(eventHandler)); - DispatchEventHandlerObject(Filter::GetEventByType(event), std::forward(eventHandler)); + DispatchEventHandlerFunctor(Filter::GetEventByType(event), std::forward(eventHandler)); + DispatchEventHandlerObject(Filter::GetEventByType(event), std::forward(eventHandler)); } - EventDispatcher>::DispatchEvent(event, std::forward(eventHandler)); + EventDispatcher>::DispatchEvent(event, std::forward(eventHandler)); } }; @@ -126,11 +127,11 @@ namespace Private { * is placed in the IsValidEventHandler variable, finally when an event gets dispatched * an static_assert happens to verify if the event handler actually handled any events. */ - template - struct EventDispatcher> { + template + struct EventDispatcher> { static constexpr auto IsValidEventHandler = ValidEventHandler; - static void DispatchEvent(const SDL_Event &, EventHandler&&) { + static void DispatchEvent(const SDL_Event &, EventHandlerType&&) { static_assert(IsValidEventHandler, "One of the given event handlers is not a valid one"); } }; @@ -138,17 +139,17 @@ namespace Private { /* * Templated class expand a list of event handlers so they can be dispatched. */ - template - void DispatchEvent(const SDL_Event &, EventHandlers&&...); + template + void DispatchEvent(const SDL_Event &, EventHandlerTypes&&...); /* * Instantiation of the class to expand a list of event handlers so they can be dispatched. * * This "peels" the first event handler from the arguments, dispatchs it and then expands the tail of the list. */ - template - void DispatchEvent(const SDL_Event &event, EventHandler&& eventHandler, EventHandlers&&... eventHandlers) { - EventDispatcher::DispatchEvent(event, std::forward(eventHandler)); + template + void DispatchEvent(const SDL_Event &event, EventHandlerType&& eventHandler, EventHandlerTypes&&... eventHandlers) { + EventDispatcher::DispatchEvent(event, std::forward(eventHandler)); DispatchEvent(event, eventHandlers...); } From 4b74730b1d7d7b7bbb3374f457d64977facd7e91 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Wed, 9 Aug 2017 00:23:18 -0700 Subject: [PATCH 23/24] Fixed some event code that depends on the SDL version --- SDL2pp/Private/EventHandler.hh | 3 +++ SDL2pp/Private/EventTypeFilters.hh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/SDL2pp/Private/EventHandler.hh b/SDL2pp/Private/EventHandler.hh index fc673c7..be2c31f 100644 --- a/SDL2pp/Private/EventHandler.hh +++ b/SDL2pp/Private/EventHandler.hh @@ -29,6 +29,7 @@ #include #include +#include namespace SDL2pp { /* @@ -40,7 +41,9 @@ namespace Private { */ using ValidEventTypes = std::tuple< SDL_Event, +#if SDL_VERSION_ATLEAST(2, 0, 5) SDL_AudioDeviceEvent, +#endif SDL_ControllerAxisEvent, SDL_ControllerButtonEvent, SDL_ControllerDeviceEvent, diff --git a/SDL2pp/Private/EventTypeFilters.hh b/SDL2pp/Private/EventTypeFilters.hh index 3ff4404..5d7a008 100644 --- a/SDL2pp/Private/EventTypeFilters.hh +++ b/SDL2pp/Private/EventTypeFilters.hh @@ -80,7 +80,7 @@ namespace Private { #if SDL_VERSION_ATLEAST(2, 0, 5) SDL2PP_DEFINE_EVENT_MAPPING(SDL_DropEvent, event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT || event.type == SDL_DROPBEGIN || event.type == SDL_DROPCOMPLETE, event.drop); #else - SDL2PP_DEFINE_EVENT_MAPPING(SDL_DropEvent, event.type == SDL_DROPFILE || event.type == SDL_DROPTEXT, event.drop); + SDL2PP_DEFINE_EVENT_MAPPING(SDL_DropEvent, event.type == SDL_DROPFILE, event.drop); #endif SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyAxisEvent, event.type == SDL_JOYAXISMOTION, event.jaxis); SDL2PP_DEFINE_EVENT_MAPPING(SDL_JoyBallEvent, event.type == SDL_JOYBALLMOTION, event.jball); From 154eed861dd8e20dbdc741670368b5838e9728b1 Mon Sep 17 00:00:00 2001 From: Vraiment Date: Wed, 9 Aug 2017 00:35:34 -0700 Subject: [PATCH 24/24] Fixed event handling/dispatching tests --- tests/test_eventdispatching.cc | 36 +++++++--------------------------- tests/test_eventhandler.cc | 2 ++ tests/test_eventpolling.cc | 4 ++-- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/tests/test_eventdispatching.cc b/tests/test_eventdispatching.cc index 81a2702..feafe3d 100644 --- a/tests/test_eventdispatching.cc +++ b/tests/test_eventdispatching.cc @@ -49,7 +49,7 @@ BEGIN_TEST(int, char*[]) } }; - auto eventHandlerFunctor = EventHandlerFunctor{}; + auto eventHandlerFunctor = EventHandlerFunctor(); DispatchEvent(event, eventHandlerFunctor); EXPECT_EQUAL(event.user.code, eventHandlerFunctor.result); } @@ -64,7 +64,7 @@ BEGIN_TEST(int, char*[]) } }; - auto eventHandlerObject = EventHandlerObject{}; + auto eventHandlerObject = EventHandlerObject(); DispatchEvent(event, eventHandlerObject); EXPECT_EQUAL(event.user.code, eventHandlerObject.result); } @@ -78,8 +78,8 @@ BEGIN_TEST(int, char*[]) executed = true; } }; - auto eventHandlerFunctor1 = EventHandlerFunctor{}; - auto eventHandlerFunctor2 = EventHandlerFunctor{}; + auto eventHandlerFunctor1 = EventHandlerFunctor(); + auto eventHandlerFunctor2 = EventHandlerFunctor(); struct EventHandlerObject { bool executed = false; @@ -88,7 +88,7 @@ BEGIN_TEST(int, char*[]) executed = true; } }; - auto eventHandlerObject = EventHandlerObject{}; + auto eventHandlerObject = EventHandlerObject(); auto lambdaExecuted = false; auto lambda = [&lambdaExecuted](SDL_QuitEvent) { lambdaExecuted = true; }; @@ -115,7 +115,7 @@ BEGIN_TEST(int, char*[]) } }; - auto eventHandler = EventHandler{}; + auto eventHandler = EventHandler(); DispatchEvent(event, eventHandler); EXPECT_TRUE(eventHandler.quitEventExecuted); @@ -147,32 +147,10 @@ BEGIN_TEST(int, char*[]) } }; - auto eventHandler = EventHandler{}; + auto eventHandler = EventHandler(); DispatchEvent(event, eventHandler); EXPECT_TRUE(eventHandler.quitEventFunctorExecuted); EXPECT_TRUE(eventHandler.quitEventObjectExecuted); } - - // Test don't call event handler with annotated types - { - struct EventHandler { - bool quitEventFunctorExecuted = false; - bool quitEventObjectExecuted = false; - - void operator()(SDL_QuitEvent) { - quitEventFunctorExecuted = true; - } - - void HandleEvent(SDL_QuitEvent &) { - quitEventObjectExecuted = true; - } - }; - - auto eventHandler = EventHandler{}; - DispatchEvent(event, eventHandler); - - EXPECT_TRUE(eventHandler.quitEventFunctorExecuted); - EXPECT_TRUE(!eventHandler.quitEventObjectExecuted); - } END_TEST() diff --git a/tests/test_eventhandler.cc b/tests/test_eventhandler.cc index aafb345..d9be3a1 100644 --- a/tests/test_eventhandler.cc +++ b/tests/test_eventhandler.cc @@ -66,4 +66,6 @@ int main(int, char*[]) { !IsEventHandler::value, "IsEventHandler<> shouldn't accept a class without a valid signature" ); + + return 0; } diff --git a/tests/test_eventpolling.cc b/tests/test_eventpolling.cc index fbe24d9..72a2aaa 100644 --- a/tests/test_eventpolling.cc +++ b/tests/test_eventpolling.cc @@ -13,7 +13,7 @@ BEGIN_TEST(int, char*[]) // Empty event poll SDL_Event event; - while (SDL_PollEvent(&event)); + while (SDL_PollEvent(&event)) { } // Poll a single event { @@ -64,7 +64,7 @@ BEGIN_TEST(int, char*[]) event.type = SDL_QUIT; SDL_PushEvent(&event); - auto eventHandler = EventHandler{}; + auto eventHandler = EventHandler(); EXPECT_EQUAL(PollAllEvents(eventHandler), 3); EXPECT_TRUE(!PollEvent()); // Verify no additional events