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));
switch(event) {
case 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);
case LEFT_BUTTON_DOUBLE_CLICK:
return fire_event_double_click<LEFT_BUTTON_CLICK, LEFT_BUTTON_DOUBLE_CLICK,
&event_executor::wants_mouse_left_double_click>(this, &target);
case 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);
case MIDDLE_BUTTON_DOUBLE_CLICK:
return fire_event_double_click<MIDDLE_BUTTON_CLICK, MIDDLE_BUTTON_DOUBLE_CLICK,
&event_executor::wants_mouse_middle_double_click>(this, &target);
case 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);
case RIGHT_BUTTON_DOUBLE_CLICK:
return fire_event_double_click<RIGHT_BUTTON_CLICK, RIGHT_BUTTON_DOUBLE_CLICK,
&event_executor::wants_mouse_right_double_click>(this, &target);
default:
return fire_event<signal>(event, this, &target);
default:
return fire_event<event_category::general>(event, this, &target);
}
}
bool dispatcher::fire(const ui_event event, widget& target, const point& coordinate)
{
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,
@ -100,43 +100,43 @@ bool dispatcher::fire(const ui_event event,
const std::string& unicode)
{
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)
{
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)
{
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)
{
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)
{
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*)
{
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)
{
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)

View file

@ -28,46 +28,19 @@ namespace gui2::event
{
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 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)
{
if constexpr(std::is_same_v<F, signal>) {
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_); \
return dispatcher.get_signal_queue<C>().queue[event];
}
/**
@ -85,23 +58,30 @@ struct dispatcher_implementation
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_);
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
@ -155,7 +135,7 @@ namespace implementation
* * container 1
* * dispatcher
*/
template<typename T>
template<event_category C>
std::vector<std::pair<widget*, ui_event>>
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<>
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(w);
@ -220,7 +200,7 @@ build_event_chain<signal_notification>(const ui_event event, widget* dispatcher,
*/
template<>
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(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
* 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,
const std::vector<std::pair<widget*, ui_event>>& event_chain,
widget* dispatcher,
@ -258,7 +238,7 @@ bool fire_event(const ui_event event,
/***** ***** ***** Pre ***** ***** *****/
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) {
pre_func(*dispatcher, chain_event, handled, halt, std::forward<F>(params)...);
@ -276,7 +256,7 @@ bool fire_event(const ui_event event,
/***** ***** ***** 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) {
func(*dispatcher, event, handled, halt, std::forward<F>(params)...);
@ -294,7 +274,7 @@ bool fire_event(const ui_event event,
/***** ***** ***** Post ***** ***** *****/
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) {
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 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.
*
*
@ -338,7 +318,7 @@ bool fire_event(const ui_event event,
*
* @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)
{
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);
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,
ui_event double_click,
bool (event_executor::*wants_double_click)() const,
typename T,
typename... F>
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)) {
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 {
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)...);
}
}