Merge 154eed861dd8e20dbdc741670368b5838e9728b1 into b00d3b9eb98be4fa2eca7ae9d88f96d28796e4f0

This commit is contained in:
Vraiment 2025-04-14 06:30:09 +00:00 committed by GitHub
commit 39f3b27b9f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 996 additions and 1 deletions

View File

@ -106,6 +106,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
@ -119,6 +120,10 @@ set(LIBRARY_HEADERS
SDL2pp/Texture.hh
SDL2pp/Wav.hh
SDL2pp/Window.hh
SDL2pp/Private/EventDispatching.hh
SDL2pp/Private/EventHandler.hh
SDL2pp/Private/EventTypeFilters.hh
SDL2pp/Private/Utility.hh
)
# optional sources

View File

@ -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"

102
SDL2pp/EventPolling.hh Normal file
View File

@ -0,0 +1,102 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2017 Vraiment <jemc44@gmail.com>
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 <SDL2pp/Private/EventDispatching.hh>
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 <typename... EventHandlers>
bool PollEvent(EventHandlers&&... eventHandlers) {
SDL_Event event;
if (!SDL_PollEvent(&event)) {
return false;
}
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 <typename... EventHandlers>
int PollAllEvents(EventHandlers&&... eventHandlers) {
int result;
for (result = 0; PollEvent(eventHandlers...); result++);
return result;
}
}
}
#endif

View File

@ -0,0 +1,166 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2017 Vraiment <jemc44@gmail.com>
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 <SDL2pp/Private/EventTypeFilters.hh>
namespace SDL2pp {
/*
* 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 EventHandlerType.
*
* This will be only called if 'eventHandler(event)' can be called
*/
template <typename EventHandlerType, typename EventType>
auto DispatchEventHandlerFunctor(const EventType &event, EventHandlerType&& eventHandler) -> typename std::enable_if<IsEventHandlerFunctor<EventHandlerType, EventType>::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 EventHandlerType.
*/
template <typename EventHandlerType, typename EventType>
auto DispatchEventHandlerFunctor(const EventType &, EventHandlerType&&) -> typename std::enable_if<!IsEventHandlerFunctor<EventHandlerType, EventType>::value>::type
{
// no-op
}
/*
* 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 <typename EventHandlerType, typename EventType>
auto DispatchEventHandlerObject(const EventType &event, EventHandlerType&& eventHandler) -> typename std::enable_if<IsEventHandlerObject<EventHandlerType, EventType>::value>::type
{
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 <typename EventHandlerType, typename EventType>
auto DispatchEventHandlerObject(const EventType &, EventHandlerType&&) -> typename std::enable_if<!IsEventHandlerObject<EventHandlerType, EventType>::value>::type
{
// no-op
}
/*
* Templated class to dispatch an event to a given 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, EventHandlerType 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 <bool ValidEventHandler, typename EventHandlerType, typename... EventTypes>
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 <bool ValidEventHandler, typename EventHandlerType, typename EventType, typename... EventTypes>
struct EventDispatcher<ValidEventHandler, EventHandlerType, std::tuple<EventType, EventTypes...>> {
static constexpr bool IsValidEventHandler = ValidEventHandler || IsEventHandler<EventHandlerType, EventType>::value;
using Filter = EventTypeFilter<EventType>;
static void DispatchEvent(const SDL_Event &event, EventHandlerType&& eventHandler) {
if (Filter::ShouldHandleEvent(event)) {
DispatchEventHandlerFunctor(Filter::GetEventByType(event), std::forward<EventHandlerType>(eventHandler));
DispatchEventHandlerObject(Filter::GetEventByType(event), std::forward<EventHandlerType>(eventHandler));
}
EventDispatcher<IsValidEventHandler, EventHandlerType, std::tuple<EventTypes...>>::DispatchEvent(event, std::forward<EventHandlerType>(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 <bool ValidEventHandler, typename EventHandlerType>
struct EventDispatcher<ValidEventHandler, EventHandlerType, std::tuple<>> {
static constexpr auto IsValidEventHandler = ValidEventHandler;
static void DispatchEvent(const SDL_Event &, EventHandlerType&&) {
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 <typename... EventHandlerTypes>
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 <typename EventHandlerType, typename... EventHandlerTypes>
void DispatchEvent(const SDL_Event &event, EventHandlerType&& eventHandler, EventHandlerTypes&&... eventHandlers) {
EventDispatcher<false, EventHandlerType, ValidEventTypes>::DispatchEvent(event, std::forward<EventHandlerType>(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
}
}
}
#endif

View File

@ -0,0 +1,153 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2017 Vraiment <jemc44@gmail.com>
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 <SDL2pp/Private/Utility.hh>
#include <functional>
#include <tuple>
#include <type_traits>
#include <SDL_events.h>
#include <SDL_version.h>
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,
#if SDL_VERSION_ATLEAST(2, 0, 5)
SDL_AudioDeviceEvent,
#endif
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 functor.
*/
template <typename, typename, typename = void>
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 <typename EventHandlerType, typename EventType>
struct IsEventHandlerFunctor<
EventHandlerType,
EventType,
typename std::enable_if<
std::is_convertible<EventHandlerType, std::function<void(EventType)>>::value
>::type
> : std::true_type { };
/*
* Templated class to identify a class that is not an event handler object.
*/
template <typename, typename, typename = void>
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 <typename EventHandlerType, typename EventType>
struct IsEventHandlerObject<
EventHandlerType,
EventType,
typename std::enable_if<
std::is_same<
decltype(std::declval<EventHandlerType>().HandleEvent(std::declval<EventType>())),
void
>::value
>::type
> : std::true_type { };
/*
* Templated class to identify a class that is not an event handler.
*/
template <typename, typename, typename = void>
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 <typename EventHandlerType, typename EventType>
struct IsEventHandler<
EventHandlerType,
EventType,
typename std::enable_if<
And<
Or<
IsEventHandlerObject<EventHandlerType, EventType>,
IsEventHandlerFunctor<EventHandlerType, EventType>
>,
TupleHasType<EventType, ValidEventTypes>
>::value
>::type
> : std::true_type { };
}
}
#endif

View File

@ -0,0 +1,107 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2017 Vraiment <jemc44@gmail.com>
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 <SDL2pp/Private/EventHandler.hh>
#include <SDL_version.h>
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 <typename EventType>
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<SDL_Event> {
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<eventType> {\
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.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, 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
}
}
#endif

118
SDL2pp/Private/Utility.hh Normal file
View File

@ -0,0 +1,118 @@
/*
libSDL2pp - C++11 bindings/wrapper for SDL2
Copyright (C) 2017 Vraiment <jemc44@gmail.com>
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 <utility>
#endif
#include <tuple>
#include <type_traits>
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 <typename T,
* typename = typename Or<HasFeatureOne<T>, HasFeatureTwo<T>>
* void UseFeatureOneOrFeatureTwo(T t) {
* // The code will be only compiled if either
* // HasFeatureOne<T> or HasFeatureTwo<T> are type_true
* }
*/
#if __cplusplus >= 201703L
// Use the standard definitions if they are available
template <typename T, typename... Tx>
using Or = typename std::disjunction<T, Tx...>::type;
#else
template <typename...>
struct OrOperation : std::false_type { };
template <typename T>
struct OrOperation<T> : T { };
template <typename T, typename... Tx>
struct OrOperation<T, Tx...> : std::conditional<bool(T::value), T, OrOperation<Tx...>> { };
template <typename T, typename... Tx>
using Or = typename OrOperation<T, Tx...>::type;
#endif
/*
* Templated class to perform an "AND" operation on any amount of types.
*
* Usage is as follows:
* template <typename T,
* typename = typename And<HasFeatureOne<T>, HasFeatureTwo<T>>
* void UseFeatureOneAndFeatureTwo(T t) {
* // The code will be only compiled if both
* // HasFeatureOne<T> and HasFeatureTwo<T> are type_true
* }
*/
#if __cplusplus >= 201703L
// Use the standard definitions if they are available
template <typename T, typename... Tx>
using And = typename std::conjunction<T, Tx...>::type;
#else
template <typename...>
struct AndOperation : std::true_type { };
template <typename T>
struct AndOperation<T> : T { };
template <typename T, typename... Tx>
struct AndOperation<T, Tx...> : std::conditional<bool(T::value), AndOperation<Tx...>, T> { };
template <typename T, typename... Tx>
using And = typename AndOperation<T, Tx...>::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 <typename T, typename Tuple>
struct TupleHasTypeOperation;
template <typename T>
struct TupleHasTypeOperation<T, std::tuple<>> : std::false_type { };
template <typename T, typename U, typename... Tx>
struct TupleHasTypeOperation<T, std::tuple<U, Tx...>> : TupleHasTypeOperation<T, std::tuple<Tx...>> { };
template <typename T, typename... Tx>
struct TupleHasTypeOperation<T, std::tuple<T, Tx...>> : std::true_type { };
template <typename T, typename... Tx>
using TupleHasType = typename TupleHasTypeOperation<T, Tx...>::type;
}
}
#endif

View File

@ -97,6 +97,14 @@
#include <SDL2pp/ContainerRWops.hh>
#include <SDL2pp/StreamRWops.hh>
///////////////////////////////////////////////////////////
/// \defgroup events Event handling
///
/// \brief Functions and classes to easily manage SDL events
///
////////////////////////////////////////////////////////////
#include <SDL2pp/EventPolling.hh>
#ifdef SDL2PP_WITH_TTF
////////////////////////////////////////////////////////////
/// \defgroup ttf SDL_ttf

View File

@ -3,10 +3,14 @@ set(CLI_TESTS
test_color
test_color_constexpr
test_error
test_eventdispatching
test_eventhandler
test_eventpolling
test_optional
test_pointrect
test_pointrect_constexpr
test_rwops
test_utility
test_wav
)

View File

@ -0,0 +1,156 @@
#include <SDL_main.h>
#include <SDL2pp/Private/EventDispatching.hh>
#include "testing.h"
using namespace SDL2pp::Private;
namespace TestFreeFunctions {
static auto globalResult = Sint32{0};
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.common.timestamp = 98;
event.type = SDL_QUIT;
event.user.code = 31;
// Test dispatching with no event handler
DispatchEvent(event);
// 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);
}
// Test dispatching with function as event handler
{
DispatchEvent(event, TestFreeFunctions::handler);
EXPECT_EQUAL(event.user.code, TestFreeFunctions::globalResult);
}
// Test dispatching with a functor as event handler
{
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);
}
// 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();
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);
}
// 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;
SDL_Event keyboardEvent;
keyboardEvent.type = SDL_KEYUP;
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);
}
END_TEST()

View File

@ -0,0 +1,71 @@
#include <SDL_main.h>
#include <SDL2pp/Private/EventHandler.hh>
using namespace SDL2pp::Private;
void EventHandlerFunction(SDL_Event);
struct EventHandlerFunctor {
void operator()(SDL_Event);
};
struct EventHandler {
void HandleEvent(SDL_Event);
};
struct InvalidEventHandler {
void handleEvent(SDL_Event);
};
int main(int, char*[]) {
auto lambda = [](SDL_Event) { };
// Test IsEventHandlerFunctor
static_assert(
IsEventHandlerFunctor<decltype(EventHandlerFunction), SDL_Event>::value,
"IsEventHandlerFunctor<> should accept functions like void(SDL_Event)"
);
static_assert(
IsEventHandlerFunctor<decltype(lambda), SDL_Event>::value,
"IsEventHandlerFunctor<> should accept functions like void(SDL_Event)"
);
static_assert(
IsEventHandlerFunctor<EventHandlerFunctor, SDL_Event>::value,
"IsEventHandlerFunctor<> shouldn accept a class with operator(SDL_Event)"
);
// Test IsEventHandlerObject
static_assert(
IsEventHandlerObject<EventHandler, SDL_Event>::value,
"IsEventHandlerObject<> should accept a class with HandleEvent(SDL_Event)"
);
static_assert(
!IsEventHandlerObject<InvalidEventHandler, SDL_Event>::value,
"IsEventHandlerObject<> shouldn't accept a class without a valid signature"
);
// Test IsEventHandler
static_assert(
IsEventHandler<decltype(EventHandlerFunction), SDL_Event>::value,
"IsEventHandler<> should accept functions like void(SDL_Event)"
);
static_assert(
IsEventHandler<decltype(lambda), SDL_Event>::value,
"IsEventHandler<> should accept functions like void(SDL_Event)"
);
static_assert(
IsEventHandler<EventHandlerFunctor, SDL_Event>::value,
"IsEventHandler<> should accept a class with operator(SDL_Event)"
);
static_assert(
IsEventHandler<EventHandler, SDL_Event>::value,
"IsEventHandler<> should accept a class with HandleEvent(SDL_Event)"
);
static_assert(
!IsEventHandler<InvalidEventHandler, SDL_Event>::value,
"IsEventHandler<> shouldn't accept a class without a valid signature"
);
return 0;
}

View File

@ -0,0 +1,76 @@
#include <SDL.h>
#include <SDL2pp/SDL.hh>
#include <SDL2pp/EventPolling.hh>
#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()

28
tests/test_utility.cc Normal file
View File

@ -0,0 +1,28 @@
#include <SDL_main.h>
#include <SDL2pp/Private/Utility.hh>
using namespace SDL2pp::Private;
using namespace std;
int main(int, char*[]) {
static_assert(Or<true_type, true_type>::value, "OR(true, true) should be true");
static_assert(Or<true_type, false_type>::value, "OR(true, false) should be true");
static_assert(Or<false_type, true_type>::value, "OR(false, true) should be true");
static_assert(!Or<false_type, false_type>::value, "OR(false, false) should be false");
static_assert(And<true_type, true_type>::value, "AND(true, true) should be true");
static_assert(!And<true_type, false_type>::value, "AND(true, false) should be false");
static_assert(!And<false_type, true_type>::value, "AND(false, true) should be false");
static_assert(!And<false_type, false_type>::value, "AND(false, false) should be false");
struct A { };
struct B { };
struct C { };
static_assert(TupleHasType<A, tuple<A, B>>::value, "");
static_assert(TupleHasType<B, tuple<A, B>>::value, "");
static_assert(!TupleHasType<C, tuple<A, B>>::value, "");
return 0;
}