Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI2/Dispatcher: refactored [dis]connect_signal to use constexpr-if #5456

Merged
merged 1 commit into from
Apr 1, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
349 changes: 69 additions & 280 deletions src/gui/core/event/dispatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@

#include "gui/core/event/handler.hpp"
#include "hotkey/hotkey_command.hpp"
#include <functional>

#include <SDL2/SDL_events.h>

#include <cassert>
#include <functional>
#include <list>
#include <map>
#include <type_traits>
Expand Down Expand Up @@ -484,310 +485,98 @@ class dispatcher
back_post_child
};

/**
* Connect a signal for callback in set_event.
*
* The function uses some enable_if magic to avoid registering the wrong
* function, but the common way to use this function is:
* widget->connect_signal<EVENT_ID>(
* std::bind(&tmy_dialog::my_member, this));
* This allows simply adding a member of a dialog to be used as a callback
* for widget without a lot of magic. Note most widgets probably will get a
* callback like
* connect_signal_mouse_left_click(const signal_function& callback)
* which hides this function for the average use.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_general_event(E)>
connect_signal(const signal_function& signal, const queue_position position = back_child)
{
signal_queue_.connect_signal(E, position, signal);
}
/** Helper macro to wrap the result of a macro concatnation in a string. */
#define STR(RES) #RES

/**
* Disconnect a signal for callback in set_event.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_general_event(E)>
disconnect_signal(const signal_function& signal, const queue_position position = back_child)
{
signal_queue_.disconnect_signal(E, position, signal);
}
#define VALIDATE_AND_ADD_TO_QUEUE(QUEUE) \
static_assert(std::is_convertible_v<F, QUEUE##_function>, \
"connect_signal: function signature does not match " STR(QUEUE##_function)); \
QUEUE##_queue_.connect_signal(E, position, func);

/**
* Connect a signal for callback in set_event_mouse.
* Adds a callback to the appropriate queue based on event type.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_mouse_event(E)>
connect_signal(const signal_mouse_function& signal, const queue_position position = back_child)
{
signal_mouse_queue_.connect_signal(E, position, signal);
}

/**
* Disconnect a signal for callback in set_event_mouse.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_mouse_event(E)>
disconnect_signal(const signal_mouse_function& signal, const queue_position position = back_child)
{
signal_mouse_queue_.disconnect_signal(E, position, signal);
}

/**
* Connect a signal for callback in set_event_keyboard.
* @tparam F The event signature. This must match the
* appropriate queue's callback signature.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_keyboard_event(E)>
connect_signal(const signal_keyboard_function& signal, const queue_position position = back_child)
{
signal_keyboard_queue_.connect_signal(E, position, signal);
}

/**
* Disconnect a signal for callback in set_event_keyboard.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_keyboard_event(E)>
disconnect_signal(const signal_keyboard_function& signal, const queue_position position = back_child)
{
signal_keyboard_queue_.disconnect_signal(E, position, signal);
}

/**
* Connect a signal for callback in set_event_touch_motion.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param func The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_touch_motion_event(E)>
connect_signal(const signal_touch_motion_function& signal, const queue_position position = back_child)
template<ui_event E, typename F>
void connect_signal(const F& func, const queue_position position = back_child)
{
signal_touch_motion_queue_.connect_signal(E, position, signal);
}

/**
* Disconnect a signal for callback in set_event_touch_motion.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_touch_motion_event(E)>
disconnect_signal(const signal_touch_motion_function& signal, const queue_position position = back_child)
{
signal_touch_motion_queue_.disconnect_signal(E, position, signal);
}

/**
* Connect a signal for callback in set_event_touch_gesture.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_touch_gesture_event(E)>
connect_signal(const signal_touch_gesture_function& signal, const queue_position position = back_child)
{
signal_touch_gesture_queue_.connect_signal(E, position, signal);
}

/**
* Disconnect a signal for callback in set_event_touch_gesture.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_touch_gesture_event(E)>
disconnect_signal(const signal_touch_gesture_function& signal, const queue_position position = back_child)
{
signal_touch_gesture_queue_.disconnect_signal(E, position, signal);
}

/**
* Connect a signal for callback in set_event_notification.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback. Since
* the message is send to a widget directly
* the pre and post positions make no sense
* and shouldn't be used.
*/
template<ui_event E>
std::enable_if_t<is_notification_event(E)>
connect_signal(const signal_notification_function& signal, const queue_position position = back_child)
{
signal_notification_queue_.connect_signal(E, position, signal);
}

/**
* Disconnect a signal for callback in set_event_notification.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back, but it needs
* to know the proper queue so it's save to
* add with front_child and remove with
* back_child. But it's not save to add with
* front_child and remove with
* front_pre_child)
*/
template<ui_event E>
std::enable_if_t<is_notification_event(E)>
disconnect_signal(const signal_notification_function& signal, const queue_position position = back_child)
{
signal_notification_queue_.disconnect_signal(E, position, signal);
}

/**
* Connect a signal for callback in set_event_message.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback. Since
* the message is send to a widget directly
* the pre and post positions make no sense
* and shouldn't be used.
*/
template<ui_event E>
std::enable_if_t<is_message_event(E)>
connect_signal(const signal_message_function& signal, const queue_position position = back_child)
{
signal_message_queue_.connect_signal(E, position, signal);
if constexpr(is_general_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal)
} else if constexpr(is_mouse_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_mouse)
} else if constexpr(is_keyboard_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_keyboard)
} else if constexpr(is_touch_motion_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_touch_motion)
} else if constexpr(is_touch_gesture_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_touch_gesture)
} else if constexpr(is_notification_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_notification)
} else if constexpr(is_message_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_message)
} else if constexpr(is_raw_event_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_raw_event)
} else if constexpr(is_text_input_event(E)) {
VALIDATE_AND_ADD_TO_QUEUE(signal_text_input)
} else {
assert(false && "No matching signal queue found for event");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Has this replaced a compile-time check with a runtime check?

}
}

/**
* Disconnect a signal for callback in set_event_message.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back, but it needs
* to know the proper queue so it's save to
* add with front_child and remove with
* back_child. But it's not save to add with
* front_child and remove with
* front_pre_child)
*/
template<ui_event E>
std::enable_if_t<is_message_event(E)>
disconnect_signal(const signal_message_function& signal, const queue_position position = back_child)
{
signal_message_queue_.disconnect_signal(E, position, signal);
}
#define VALIDATE_AND_REMOVE_FROM_QUEUE(QUEUE) \
static_assert(std::is_convertible_v<F, QUEUE##_function>, \
"disconnect_signal: function signature does not match " STR(QUEUE##_function)); \
QUEUE##_queue_.disconnect_signal(E, position, func);

/**
* Connect a signal for callback in set_raw_event.
* Removes a callback from the appropriate queue based on event type.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_raw_event_event(E)>
connect_signal(const signal_raw_event_function& signal, const queue_position position = back_child)
{
signal_raw_event_queue_.connect_signal(E, position, signal);
}

/**
* Disconnect a signal for callback in set_raw_event.
* @tparam F The event signature. This must match the
* appropriate queue's callback signature.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param func The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_raw_event_event(E)>
disconnect_signal(const signal_raw_event_function& signal, const queue_position position = back_child)
template<ui_event E, typename F>
void disconnect_signal(const F& func, const queue_position position = back_child)
{
signal_raw_event_queue_.disconnect_signal(E, position, signal);
if constexpr(is_general_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal)
} else if constexpr(is_mouse_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_mouse)
} else if constexpr(is_keyboard_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_keyboard)
} else if constexpr(is_touch_motion_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_touch_motion)
} else if constexpr(is_touch_gesture_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_touch_gesture)
} else if constexpr(is_notification_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_notification)
} else if constexpr(is_message_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_message)
} else if constexpr(is_raw_event_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_raw_event)
} else if constexpr(is_text_input_event(E)) {
VALIDATE_AND_REMOVE_FROM_QUEUE(signal_text_input)
} else {
assert(false && "No matching signal queue found for event");
}
}

/**
* Connect a signal for callback in set_text_input.
*
* @tparam E The event the callback needs to react to.
* @param signal The callback function.
* @param position The position to place the callback.
*/
template<ui_event E>
std::enable_if_t<is_text_input_event(E)>
connect_signal(const signal_text_input_function& signal, const queue_position position = back_child)
{
signal_text_input_queue_.connect_signal(E, position, signal);
}
#undef VALIDATE_AND_ADD_TO_QUEUE
#undef VALIDATE_AND_REMOVE_FROM_QUEUE

/**
* Disconnect a signal for callback in set_text_input.
*
* @tparam E The event the callback was used for.
* @param signal The callback function.
* @param position The place where the function was added.
* Needed remove the event from the right
* place. (The function doesn't care whether
* was added in front or back.)
*/
template<ui_event E>
std::enable_if_t<is_text_input_event(E)>
disconnect_signal(const signal_text_input_function& signal, const queue_position position = back_child)
{
signal_text_input_queue_.disconnect_signal(E, position, signal);
}
#undef STR

/**
* The behavior of the mouse events.
Expand Down