diff options
author | 杨宇千 <crupest@outlook.com> | 2019-08-11 01:09:49 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-08-11 01:09:49 +0800 |
commit | 0e35b2c022599bca2df61488945f07e4d6b4eb35 (patch) | |
tree | 71daef6f9725a250b9fcaf97fdecc9bdf46bd6e3 /src/ui/routed_event_dispatch.hpp | |
parent | 9eed31954c14f2d60c906adb5b49b58fbee4ff7f (diff) | |
download | cru-0e35b2c022599bca2df61488945f07e4d6b4eb35.tar.gz cru-0e35b2c022599bca2df61488945f07e4d6b4eb35.tar.bz2 cru-0e35b2c022599bca2df61488945f07e4d6b4eb35.zip |
...
Diffstat (limited to 'src/ui/routed_event_dispatch.hpp')
-rw-r--r-- | src/ui/routed_event_dispatch.hpp | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/src/ui/routed_event_dispatch.hpp b/src/ui/routed_event_dispatch.hpp new file mode 100644 index 00000000..3427441b --- /dev/null +++ b/src/ui/routed_event_dispatch.hpp @@ -0,0 +1,60 @@ +#pragma once +#include "cru/ui/control.hpp" + +namespace cru::ui { +// Dispatch the event. +// +// This will raise routed event of the control and its parent and parent's +// parent ... (until "last_receiver" if it's not nullptr) with appropriate args. +// +// First tunnel from top to bottom possibly stopped by "handled" flag in +// EventArgs. Second bubble from bottom to top possibly stopped by "handled" +// flag in EventArgs. Last direct to each control. +// +// Args is of type "EventArgs". The first init argument is "sender", which is +// automatically bound to each receiving control. The second init argument is +// "original_sender", which is unchanged. And "args" will be perfectly forwarded +// as the rest arguments. +template <typename EventArgs, typename... Args> +void DispatchEvent(Control* const original_sender, + event::RoutedEvent<EventArgs>* (Control::*event_ptr)(), + Control* const last_receiver, Args&&... args) { + std::list<Control*> receive_list; + + auto parent = original_sender; + while (parent != last_receiver) { + receive_list.push_back(parent); + parent = parent->GetParent(); + } + + auto handled = false; + + // tunnel + for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) { + EventArgs event_args(*i, original_sender, std::forward<Args>(args)...); + static_cast<Event<EventArgs>*>(((*i)->*event_ptr)()->tunnel.get()) + ->Raise(event_args); + if (event_args.IsHandled()) { + handled = true; + break; + } + } + + // bubble + if (!handled) { + for (auto i : receive_list) { + EventArgs event_args(i, original_sender, std::forward<Args>(args)...); + static_cast<Event<EventArgs>*>((i->*event_ptr)()->bubble.get()) + ->Raise(event_args); + if (event_args.IsHandled()) break; + } + } + + // direct + for (auto i : receive_list) { + EventArgs event_args(i, original_sender, std::forward<Args>(args)...); + static_cast<Event<EventArgs>*>((i->*event_ptr)()->direct.get()) + ->Raise(event_args); + } +} +} // namespace cru::ui |