GUI2/Dispatcher: simplified even further

This commit is contained in:
Charles Dang 2022-04-24 20:24:02 -04:00
parent fd9ee37b43
commit dc48c6dc63
2 changed files with 60 additions and 79 deletions

View file

@ -70,27 +70,27 @@ bool dispatcher::fire(const ui_event event, widget& target)
{ {
assert(is_in_category(event, event_category::general)); assert(is_in_category(event, event_category::general));
switch(event) { switch(event) {
case LEFT_BUTTON_DOUBLE_CLICK: case LEFT_BUTTON_DOUBLE_CLICK:
return fire_event_double_click<LEFT_BUTTON_CLICK, LEFT_BUTTON_DOUBLE_CLICK, return fire_event_double_click<LEFT_BUTTON_CLICK, LEFT_BUTTON_DOUBLE_CLICK,
&event_executor::wants_mouse_left_double_click, signal>(this, &target); &event_executor::wants_mouse_left_double_click>(this, &target);
case MIDDLE_BUTTON_DOUBLE_CLICK: case MIDDLE_BUTTON_DOUBLE_CLICK:
return fire_event_double_click<MIDDLE_BUTTON_CLICK, MIDDLE_BUTTON_DOUBLE_CLICK, return fire_event_double_click<MIDDLE_BUTTON_CLICK, MIDDLE_BUTTON_DOUBLE_CLICK,
&event_executor::wants_mouse_middle_double_click, signal>(this, &target); &event_executor::wants_mouse_middle_double_click>(this, &target);
case RIGHT_BUTTON_DOUBLE_CLICK: case RIGHT_BUTTON_DOUBLE_CLICK:
return fire_event_double_click<RIGHT_BUTTON_CLICK, RIGHT_BUTTON_DOUBLE_CLICK, return fire_event_double_click<RIGHT_BUTTON_CLICK, RIGHT_BUTTON_DOUBLE_CLICK,
&event_executor::wants_mouse_right_double_click, signal>(this, &target); &event_executor::wants_mouse_right_double_click>(this, &target);
default: default:
return fire_event<signal>(event, this, &target); return fire_event<event_category::general>(event, this, &target);
} }
} }
bool dispatcher::fire(const ui_event event, widget& target, const point& coordinate) bool dispatcher::fire(const ui_event event, widget& target, const point& coordinate)
{ {
assert(is_in_category(event, event_category::mouse)); assert(is_in_category(event, event_category::mouse));
return fire_event<signal_mouse>(event, this, &target, coordinate); return fire_event<event_category::mouse>(event, this, &target, coordinate);
} }
bool dispatcher::fire(const ui_event event, bool dispatcher::fire(const ui_event event,
@ -100,43 +100,43 @@ bool dispatcher::fire(const ui_event event,
const std::string& unicode) const std::string& unicode)
{ {
assert(is_in_category(event, event_category::keyboard)); assert(is_in_category(event, event_category::keyboard));
return fire_event<signal_keyboard>(event, this, &target, key, modifier, unicode); return fire_event<event_category::keyboard>(event, this, &target, key, modifier, unicode);
} }
bool dispatcher::fire(const ui_event event, widget& target, const point& pos, const point& distance) bool dispatcher::fire(const ui_event event, widget& target, const point& pos, const point& distance)
{ {
assert(is_in_category(event, event_category::touch_motion)); assert(is_in_category(event, event_category::touch_motion));
return fire_event<signal_touch_motion>(event, this, &target, pos, distance); return fire_event<event_category::touch_motion>(event, this, &target, pos, distance);
} }
bool dispatcher::fire(const ui_event event, widget& target, const point& center, float dTheta, float dDist, uint8_t numFingers) bool dispatcher::fire(const ui_event event, widget& target, const point& center, float dTheta, float dDist, uint8_t numFingers)
{ {
assert(is_in_category(event, event_category::touch_gesture)); assert(is_in_category(event, event_category::touch_gesture));
return fire_event<signal_touch_gesture>(event, this, &target, center, dTheta, dDist, numFingers); return fire_event<event_category::touch_gesture>(event, this, &target, center, dTheta, dDist, numFingers);
} }
bool dispatcher::fire(const ui_event event, widget& target, const SDL_Event& sdlevent) bool dispatcher::fire(const ui_event event, widget& target, const SDL_Event& sdlevent)
{ {
assert(is_in_category(event, event_category::raw_event)); assert(is_in_category(event, event_category::raw_event));
return fire_event<signal_raw_event>(event, this, &target, sdlevent); return fire_event<event_category::raw_event>(event, this, &target, sdlevent);
} }
bool dispatcher::fire(const ui_event event, widget& target, const std::string& text, int32_t start, int32_t len) bool dispatcher::fire(const ui_event event, widget& target, const std::string& text, int32_t start, int32_t len)
{ {
assert(is_in_category(event, event_category::text_input)); assert(is_in_category(event, event_category::text_input));
return fire_event<signal_text_input>(event, this, &target, text, start, len); return fire_event<event_category::text_input>(event, this, &target, text, start, len);
} }
bool dispatcher::fire(const ui_event event, widget& target, void*) bool dispatcher::fire(const ui_event event, widget& target, void*)
{ {
assert(is_in_category(event, event_category::notification)); assert(is_in_category(event, event_category::notification));
return fire_event<signal_notification>(event, this, &target, nullptr); return fire_event<event_category::notification>(event, this, &target, nullptr);
} }
bool dispatcher::fire(const ui_event event, widget& target, const message& msg) bool dispatcher::fire(const ui_event event, widget& target, const message& msg)
{ {
assert(is_in_category(event, event_category::message)); assert(is_in_category(event, event_category::message));
return fire_event<signal_message>(event, this, &target, msg); return fire_event<event_category::message>(event, this, &target, msg);
} }
void dispatcher::register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function& function) void dispatcher::register_hotkey(const hotkey::HOTKEY_COMMAND id, const hotkey_function& function)

View file

@ -28,46 +28,19 @@ namespace gui2::event
{ {
struct dispatcher_implementation struct dispatcher_implementation
{ {
#define FUNCTION_QUEUE_CHECK(TYPE) \
else if constexpr(std::is_same_v<F, signal_##TYPE>) { \
return dispatcher.signal_##TYPE##_queue_.queue[event]; \
}
/** /**
* Returns the appropriate signal queue for an event by function signature. * Returns the appropriate signal queue for an event by category.
* *
* @tparam F For example, signal. * @tparam C For example, general.
* @param dispatcher The dispatcher whose signal queue is used. * @param dispatcher The dispatcher whose signal queue is used.
* @param event The event to get the signal for. * @param event The event to get the signal for.
* *
* @returns The signal of the type dispatcher::signal_type<F> * @returns The signal of the type dispatcher::signal_type<T>
*/ */
template<typename F> template<event_category C>
static auto& event_signal(dispatcher& dispatcher, const ui_event event) static auto& event_signal(dispatcher& dispatcher, const ui_event event)
{ {
if constexpr(std::is_same_v<F, signal>) { return dispatcher.get_signal_queue<C>().queue[event];
return dispatcher.signal_queue_.queue[event];
}
FUNCTION_QUEUE_CHECK(mouse)
FUNCTION_QUEUE_CHECK(keyboard)
FUNCTION_QUEUE_CHECK(touch_motion)
FUNCTION_QUEUE_CHECK(touch_gesture)
FUNCTION_QUEUE_CHECK(notification)
FUNCTION_QUEUE_CHECK(message)
FUNCTION_QUEUE_CHECK(raw_event)
FUNCTION_QUEUE_CHECK(text_input)
else {
static_assert(utils::dependent_false_v<F>, "No matching signal queue found for function");
}
}
#undef FUNCTION_QUEUE_CHECK
#define RUNTIME_EVENT_SIGNAL_CHECK(TYPE) \
else if(is_in_category(event, event_category::TYPE)) { \
return queue_check(dispatcher.signal_##TYPE##_queue_); \
} }
/** /**
@ -85,23 +58,30 @@ struct dispatcher_implementation
return !queue_set.queue[event].empty(queue_type); return !queue_set.queue[event].empty(queue_type);
}; };
if(is_in_category(event, event_category::general)) { // We can't just use get_signal_queue since there's no way to know the event at compile time.
switch(get_event_category(event)) {
case event_category::general:
return queue_check(dispatcher.signal_queue_); return queue_check(dispatcher.signal_queue_);
case event_category::mouse:
return queue_check(dispatcher.signal_mouse_queue_);
case event_category::keyboard:
return queue_check(dispatcher.signal_keyboard_queue_);
case event_category::touch_motion:
return queue_check(dispatcher.signal_touch_motion_queue_);
case event_category::touch_gesture:
return queue_check(dispatcher.signal_touch_gesture_queue_);
case event_category::notification:
return queue_check(dispatcher.signal_notification_queue_);;
case event_category::message:
return queue_check(dispatcher.signal_message_queue_);
case event_category::raw_event:
return queue_check(dispatcher.signal_raw_event_queue_);
case event_category::text_input:
return queue_check(dispatcher.signal_text_input_queue_);
default:
throw std::invalid_argument("Event is not categorized");
} }
RUNTIME_EVENT_SIGNAL_CHECK(mouse)
RUNTIME_EVENT_SIGNAL_CHECK(keyboard)
RUNTIME_EVENT_SIGNAL_CHECK(touch_motion)
RUNTIME_EVENT_SIGNAL_CHECK(touch_gesture)
RUNTIME_EVENT_SIGNAL_CHECK(notification)
RUNTIME_EVENT_SIGNAL_CHECK(message)
RUNTIME_EVENT_SIGNAL_CHECK(raw_event)
RUNTIME_EVENT_SIGNAL_CHECK(text_input)
return false;
} }
#undef RUNTIME_EVENT_SIGNAL_CHECK
}; };
namespace implementation namespace implementation
@ -155,7 +135,7 @@ namespace implementation
* * container 1 * * container 1
* * dispatcher * * dispatcher
*/ */
template<typename T> template<event_category C>
std::vector<std::pair<widget*, ui_event>> std::vector<std::pair<widget*, ui_event>>
build_event_chain(const ui_event event, widget* dispatcher, widget* w) build_event_chain(const ui_event event, widget* dispatcher, widget* w)
{ {
@ -191,7 +171,7 @@ build_event_chain(const ui_event event, widget* dispatcher, widget* w)
*/ */
template<> template<>
std::vector<std::pair<widget*, ui_event>> std::vector<std::pair<widget*, ui_event>>
build_event_chain<signal_notification>(const ui_event event, widget* dispatcher, widget* w) build_event_chain<event_category::notification>(const ui_event event, widget* dispatcher, widget* w)
{ {
assert(dispatcher); assert(dispatcher);
assert(w); assert(w);
@ -220,7 +200,7 @@ build_event_chain<signal_notification>(const ui_event event, widget* dispatcher,
*/ */
template<> template<>
std::vector<std::pair<widget*, ui_event>> std::vector<std::pair<widget*, ui_event>>
build_event_chain<signal_message>(const ui_event event, widget* dispatcher, widget* w) build_event_chain<event_category::message>(const ui_event event, widget* dispatcher, widget* w)
{ {
assert(dispatcher); assert(dispatcher);
assert(w); assert(w);
@ -246,7 +226,7 @@ build_event_chain<signal_message>(const ui_event event, widget* dispatcher, widg
* This is called with the same parameters as fire_event except for the * This is called with the same parameters as fire_event except for the
* event_chain, which contains the widgets with the events to call for them. * event_chain, which contains the widgets with the events to call for them.
*/ */
template<typename T, typename... F> template<event_category C, typename... F>
bool fire_event(const ui_event event, bool fire_event(const ui_event event,
const std::vector<std::pair<widget*, ui_event>>& event_chain, const std::vector<std::pair<widget*, ui_event>>& event_chain,
widget* dispatcher, widget* dispatcher,
@ -258,7 +238,7 @@ bool fire_event(const ui_event event,
/***** ***** ***** Pre ***** ***** *****/ /***** ***** ***** Pre ***** ***** *****/
for(const auto& [chain_target, chain_event] : utils::reversed_view(event_chain)) { for(const auto& [chain_target, chain_event] : utils::reversed_view(event_chain)) {
const auto& signal = dispatcher_implementation::event_signal<T>(*chain_target, chain_event); const auto& signal = dispatcher_implementation::event_signal<C>(*chain_target, chain_event);
for(const auto& pre_func : signal.pre_child) { for(const auto& pre_func : signal.pre_child) {
pre_func(*dispatcher, chain_event, handled, halt, std::forward<F>(params)...); pre_func(*dispatcher, chain_event, handled, halt, std::forward<F>(params)...);
@ -276,7 +256,7 @@ bool fire_event(const ui_event event,
/***** ***** ***** Child ***** ***** *****/ /***** ***** ***** Child ***** ***** *****/
if(w->has_event(event, dispatcher::child)) { if(w->has_event(event, dispatcher::child)) {
const auto& signal = dispatcher_implementation::event_signal<T>(*w, event); const auto& signal = dispatcher_implementation::event_signal<C>(*w, event);
for(const auto& func : signal.child) { for(const auto& func : signal.child) {
func(*dispatcher, event, handled, halt, std::forward<F>(params)...); func(*dispatcher, event, handled, halt, std::forward<F>(params)...);
@ -294,7 +274,7 @@ bool fire_event(const ui_event event,
/***** ***** ***** Post ***** ***** *****/ /***** ***** ***** Post ***** ***** *****/
for(const auto& [chain_target, chain_event] : event_chain) { for(const auto& [chain_target, chain_event] : event_chain) {
const auto& signal = dispatcher_implementation::event_signal<T>(*chain_target, chain_event); const auto& signal = dispatcher_implementation::event_signal<C>(*chain_target, chain_event);
for(const auto& post_func : signal.post_child) { for(const auto& post_func : signal.post_child) {
post_func(*dispatcher, chain_event, handled, halt, std::forward<F>(params)...); post_func(*dispatcher, chain_event, handled, halt, std::forward<F>(params)...);
@ -326,7 +306,7 @@ bool fire_event(const ui_event event,
* @pre d != nullptr * @pre d != nullptr
* @pre w != nullptr * @pre w != nullptr
* *
* @tparam T The signal type of the event to handle. * @tparam C The category of the event to handle.
* @tparam F The parameter pack type. * @tparam F The parameter pack type.
* *
* *
@ -338,7 +318,7 @@ bool fire_event(const ui_event event,
* *
* @returns Whether or not the event was handled. * @returns Whether or not the event was handled.
*/ */
template<typename T, typename... F> template<event_category C, typename... F>
bool fire_event(const ui_event event, dispatcher* d, widget* w, F&&... params) bool fire_event(const ui_event event, dispatcher* d, widget* w, F&&... params)
{ {
assert(d); assert(d);
@ -347,15 +327,14 @@ bool fire_event(const ui_event event, dispatcher* d, widget* w, F&&... params)
widget* dispatcher_w = dynamic_cast<widget*>(d); widget* dispatcher_w = dynamic_cast<widget*>(d);
std::vector<std::pair<widget*, ui_event>> event_chain = std::vector<std::pair<widget*, ui_event>> event_chain =
implementation::build_event_chain<T>(event, dispatcher_w, w); implementation::build_event_chain<C>(event, dispatcher_w, w);
return implementation::fire_event<T>(event, event_chain, dispatcher_w, w, std::forward<F>(params)...); return implementation::fire_event<C>(event, event_chain, dispatcher_w, w, std::forward<F>(params)...);
} }
template<ui_event click, template<ui_event click,
ui_event double_click, ui_event double_click,
bool (event_executor::*wants_double_click)() const, bool (event_executor::*wants_double_click)() const,
typename T,
typename... F> typename... F>
bool fire_event_double_click(dispatcher* dsp, widget* wgt, F&&... params) bool fire_event_double_click(dispatcher* dsp, widget* wgt, F&&... params)
{ {
@ -382,9 +361,11 @@ bool fire_event_double_click(dispatcher* dsp, widget* wgt, F&&... params)
} }
if(std::invoke(wants_double_click, wgt)) { if(std::invoke(wants_double_click, wgt)) {
return implementation::fire_event<T>(double_click, event_chain, d, wgt, std::forward<F>(params)...); constexpr auto C = get_event_category(double_click);
return implementation::fire_event<C>(double_click, event_chain, d, wgt, std::forward<F>(params)...);
} else { } else {
return implementation::fire_event<T>(click, event_chain, d, wgt, std::forward<F>(params)...); constexpr auto C = get_event_category(click);
return implementation::fire_event<C>(click, event_chain, d, wgt, std::forward<F>(params)...);
} }
} }