Add a new helper file for the dispatcher.
The file isn't used yet.
This commit is contained in:
parent
81b94610c3
commit
7aeb53a523
1 changed files with 456 additions and 0 deletions
456
src/gui/auxiliary/event/dispatcher_private.hpp
Normal file
456
src/gui/auxiliary/event/dispatcher_private.hpp
Normal file
|
@ -0,0 +1,456 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2009 by Mark de Wever <koraq@xs4all.nl>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef GUI_WIDGETS_AUXILIARY_EVENT_DISPATCHER_PRIVATE_HPP_INCLUDED
|
||||
#define GUI_WIDGETS_AUXILIARY_EVENT_DISPATCHER_PRIVATE_HPP_INCLUDED
|
||||
|
||||
#include "gui/auxiliary/event/dispatcher.hpp"
|
||||
|
||||
#include "gui/widgets/widget.hpp"
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
|
||||
namespace gui2 {
|
||||
|
||||
namespace event {
|
||||
|
||||
struct tdispatcher_implementation
|
||||
{
|
||||
/**
|
||||
* Returns the signal structure for a tsignal_function.
|
||||
*
|
||||
* There are several functions that only overload the return value, in
|
||||
* order to do so they use SFINAE.
|
||||
*
|
||||
* @tparam F tsignal_function.
|
||||
* @param dispatcher The dispatcher whose signal queue is used.
|
||||
* @param event The event to get the signal for.
|
||||
*
|
||||
* @returns The signal of the type
|
||||
* tdispatcher::tsignal<tsignal_function>
|
||||
*/
|
||||
template<class F>
|
||||
static typename boost::enable_if<
|
||||
boost::is_same<F, tsignal_function>
|
||||
, tdispatcher::tsignal<tsignal_function>
|
||||
>::type&
|
||||
event_signal(tdispatcher& dispatcher, const tevent event)
|
||||
{
|
||||
return dispatcher.signal_queue_.queue[event];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signal structure for a key in tset_event.
|
||||
*
|
||||
* There are several functions that only overload the return value, in
|
||||
* order to do so they use SFINAE.
|
||||
*
|
||||
* @tparam K A key in tset_event.
|
||||
* @param dispatcher The dispatcher whose signal queue is used.
|
||||
* @param event The event to get the signal for.
|
||||
*
|
||||
* @returns The signal of the type
|
||||
* tdispatcher::tsignal<tsignal_function>
|
||||
*/
|
||||
template<class K>
|
||||
static typename boost::enable_if<
|
||||
boost::mpl::has_key<tset_event, K>
|
||||
, tdispatcher::tsignal<tsignal_function>
|
||||
>::type&
|
||||
event_signal(tdispatcher& dispatcher, const tevent event)
|
||||
{
|
||||
return dispatcher.signal_queue_.queue[event];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signal structure for a tsignal_mouse_function.
|
||||
*
|
||||
* There are several functions that only overload the return value, in
|
||||
* order to do so they use SFINAE.
|
||||
*
|
||||
* @tparam F tsignal_mouse_function.
|
||||
* @param dispatcher The dispatcher whose signal queue is used.
|
||||
* @param event The event to get the signal for.
|
||||
*
|
||||
* @returns The signal of the type
|
||||
* tdispatcher::tsignal<tsignal_mouse_function>
|
||||
*/
|
||||
template<class F>
|
||||
static typename boost::enable_if<
|
||||
boost::is_same<F, tsignal_mouse_function>
|
||||
, tdispatcher::tsignal<tsignal_mouse_function>
|
||||
>::type&
|
||||
event_signal(tdispatcher& dispatcher, const tevent event)
|
||||
{
|
||||
return dispatcher.signal_mouse_queue_.queue[event];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signal structure for a key in tset_event_mouse.
|
||||
*
|
||||
* There are several functions that only overload the return value, in
|
||||
* order to do so they use SFINAE.
|
||||
*
|
||||
* @tparam K A key in tset_event._mouse
|
||||
* @param dispatcher The dispatcher whose signal queue is used.
|
||||
* @param event The event to get the signal for.
|
||||
*
|
||||
* @returns The signal of the type
|
||||
* tdispatcher::tsignal<tsignal_mouse_function>
|
||||
*/
|
||||
template<class K>
|
||||
static typename boost::enable_if<
|
||||
boost::mpl::has_key<tset_event_mouse, K >
|
||||
, tdispatcher::tsignal<tsignal_mouse_function>
|
||||
>::type&
|
||||
event_signal(tdispatcher& dispatcher,const tevent event)
|
||||
{
|
||||
return dispatcher.signal_mouse_queue_.queue[event];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signal structure for a key in tset_event_keyboard.
|
||||
*
|
||||
* There are several functions that only overload the return value, in
|
||||
* order to do so they use SFINAE.
|
||||
*
|
||||
* @tparam K A key in tset_event._mouse
|
||||
* @param dispatcher The dispatcher whose signal queue is used.
|
||||
* @param event The event to get the signal for.
|
||||
*
|
||||
* @returns The signal of the type
|
||||
* tdispatcher::
|
||||
* tsignal<tsignal_keyboard_function>
|
||||
*/
|
||||
template<class K>
|
||||
static typename boost::enable_if<
|
||||
boost::mpl::has_key<tset_event_keyboard, K >
|
||||
, tdispatcher::tsignal<tsignal_keyboard_function>
|
||||
>::type&
|
||||
event_signal(tdispatcher& dispatcher, const tevent event)
|
||||
{
|
||||
return dispatcher.signal_keyboard_queue_.queue[event];
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class to find out wheter dispatcher has an handler for a
|
||||
* certain event.
|
||||
*/
|
||||
class thas_handler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param event_type The type of event to look for.
|
||||
* @param dispatcher The dispatcher whose signal queue is used.
|
||||
*/
|
||||
thas_handler(const tdispatcher::tevent_type event_type
|
||||
, tdispatcher& dispatcher)
|
||||
: event_type_(event_type)
|
||||
, dispatcher_(dispatcher)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Tests whether a handler for an event is available.
|
||||
*
|
||||
* It tests for both the event and the event_type send in the
|
||||
* constructor.
|
||||
*
|
||||
* @tparam T A key from an event set used to instanciate
|
||||
* the proper @ref event_signal function.
|
||||
* @param event The event to get the signal for.
|
||||
*
|
||||
* @returns Whether or not the handler is found.
|
||||
*/
|
||||
template<class T>
|
||||
bool operator()(tevent event)
|
||||
{
|
||||
if((event_type_ & tdispatcher::pre)
|
||||
&& !event_signal<T>(dispatcher_, event).pre_child.empty()) {
|
||||
return true;
|
||||
}
|
||||
if((event_type_ & tdispatcher::child)
|
||||
&& !event_signal<T>(dispatcher_, event).child.empty()) {
|
||||
return true;
|
||||
}
|
||||
if((event_type_ & tdispatcher::post)
|
||||
&& !event_signal<T>(dispatcher_, event).post_child.empty()){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
tdispatcher::tevent_type event_type_;
|
||||
tdispatcher& dispatcher_;
|
||||
};
|
||||
};
|
||||
|
||||
/** Contains the implementation details of the find function. */
|
||||
namespace implementation {
|
||||
|
||||
/** Specialized class when itor == end */
|
||||
template<bool done = true>
|
||||
struct find
|
||||
{
|
||||
template<
|
||||
typename itor
|
||||
, typename end
|
||||
, typename E
|
||||
, typename F
|
||||
>
|
||||
static bool execute(
|
||||
itor*
|
||||
, end*
|
||||
, E
|
||||
, F
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** Specialized class when itor != end */
|
||||
template<>
|
||||
struct find<false>
|
||||
{
|
||||
template<
|
||||
typename itor
|
||||
, typename end
|
||||
, typename E
|
||||
, typename F
|
||||
>
|
||||
static bool execute(
|
||||
itor*
|
||||
, end*
|
||||
, E event
|
||||
, F functor
|
||||
)
|
||||
{
|
||||
typedef typename boost::mpl::deref<itor>::type item;
|
||||
typedef typename
|
||||
boost::mpl::apply1<boost::mpl::identity<>, item>::type arg;
|
||||
|
||||
boost::value_initialized<arg> x;
|
||||
|
||||
if(boost::get(x) == event) {
|
||||
return functor.template operator()<item>(event);
|
||||
} else {
|
||||
typedef typename boost::mpl::next<itor>::type itor;
|
||||
return find<boost::is_same<itor, end>::value>
|
||||
::execute((itor*)0, (end*)0, event, functor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace implementation
|
||||
|
||||
/**
|
||||
* Tests whether an event handler is available.
|
||||
*
|
||||
* The code is based on boost::mpl_for_each, which doesn't allow to call a
|
||||
* template function with the dereferred iterator as template parameter.
|
||||
*
|
||||
* The function first tries to match whether the value in the sequence matches
|
||||
* event, once that matched it will execute the functor with the key found as
|
||||
* template parameter and the event as parameter.
|
||||
*
|
||||
* @tparam sequence The sequence to test upon.
|
||||
* @tparam E The value type of the item in the sequence
|
||||
* @tparam F Type of the functor.
|
||||
*
|
||||
* @param event The event to look for.
|
||||
* @param functor The predicate which should is executed if the
|
||||
* event is matched.
|
||||
*
|
||||
* @returns Whether or not the function found a result.
|
||||
*/
|
||||
template<
|
||||
typename sequence
|
||||
, typename E
|
||||
, typename F
|
||||
>
|
||||
inline bool find(E event, F functor)
|
||||
{
|
||||
typedef typename boost::mpl::begin<sequence>::type begin;
|
||||
typedef typename boost::mpl::end<sequence>::type end;
|
||||
|
||||
return implementation::find<boost::is_same<begin, end>::value>
|
||||
::execute((begin*)0, (end*)0, event, functor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the event chain.
|
||||
*
|
||||
* The event chain is a chain of events starting from the first parent of the
|
||||
* widget until (and including) the wanted parent. For all these widgets it
|
||||
* will be tested whether they have either a pre or post handler for the event.
|
||||
* This ways there will be list of widgets to try to send the events to.
|
||||
* If there's no line from widget to parent the result is undefined.
|
||||
* (If widget == dispatcher the result will always be empty.)
|
||||
*
|
||||
* @pre dispatcher != NULL
|
||||
* @pre widget != NULL
|
||||
*
|
||||
* @param event The event to test.
|
||||
* @param dispatcher The final widget to test, this is also the
|
||||
* dispatcher the sends the event.
|
||||
* @param widget The widget should parent(s) to check.
|
||||
*
|
||||
* @returns The list of widgets with a handler.
|
||||
*/
|
||||
inline std::vector<twidget*> build_event_chain(const tevent event
|
||||
, twidget* dispatcher
|
||||
, twidget* widget)
|
||||
{
|
||||
assert(dispatcher);
|
||||
assert(widget);
|
||||
|
||||
std::vector<twidget*> result;
|
||||
|
||||
while(widget != dispatcher) {
|
||||
widget = widget->parent();
|
||||
assert(widget);
|
||||
|
||||
if(widget->has_event(event, tdispatcher::tevent_type(
|
||||
tdispatcher::pre | tdispatcher::post))) {
|
||||
|
||||
result.push_back(widget);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Fires an event.
|
||||
*
|
||||
* A helper to allow the common event firing code to be shared between the
|
||||
* different signal function types.
|
||||
*
|
||||
* @pre dispatcher != NULL
|
||||
* @pre widget != NULL
|
||||
*
|
||||
* @tparam T The signal type of the event to handle.
|
||||
* @tparem F The type of the functor.
|
||||
*
|
||||
*
|
||||
* @param event The event to fire.
|
||||
* @param dispatcher The dispatcher that handles the event.
|
||||
* @param widget The widget that should receive the event.
|
||||
* @param functor The functor to execute the actual event.
|
||||
* Since some functions need different
|
||||
* parameters this functor stores them before
|
||||
* firing the event.
|
||||
*
|
||||
* @returns Whether or not the event was handled.
|
||||
*/
|
||||
template<class T, class F>
|
||||
inline bool fire_event(const tevent event
|
||||
, twidget* dispatcher
|
||||
, twidget* widget
|
||||
, F functor)
|
||||
{
|
||||
assert(dispatcher);
|
||||
assert(widget);
|
||||
|
||||
std::vector<twidget*> event_chain =
|
||||
build_event_chain(event, dispatcher, widget);
|
||||
|
||||
bool handled = false;
|
||||
bool halt = false;
|
||||
|
||||
/***** ***** ***** Pre ***** ***** *****/
|
||||
for(std::vector<twidget*>::iterator itor_widget = event_chain.begin();
|
||||
itor_widget != event_chain.end();
|
||||
++itor_widget) {
|
||||
|
||||
tdispatcher::tsignal<T>& signal = tdispatcher_implementation
|
||||
::event_signal<T>(**itor_widget, event);
|
||||
|
||||
for(typename std::vector<T>::iterator itor = signal.pre_child.begin();
|
||||
itor != signal.pre_child.end();
|
||||
++itor) {
|
||||
|
||||
functor(*itor, event, handled, halt);
|
||||
if(halt) {
|
||||
assert(handled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(handled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/***** ***** ***** Child ***** ***** *****/
|
||||
if(widget->has_event(event, tdispatcher::child)) {
|
||||
|
||||
tdispatcher::tsignal<T>& signal = tdispatcher_implementation
|
||||
::event_signal<T>(*widget, event);
|
||||
|
||||
for(typename std::vector<T>::iterator itor = signal.child.begin();
|
||||
itor != signal.child.end();
|
||||
++itor) {
|
||||
|
||||
functor(*itor, event, handled, halt);
|
||||
|
||||
if(halt) {
|
||||
assert(handled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(handled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/***** ***** ***** Post ***** ***** *****/
|
||||
for(std::vector<twidget*>::reverse_iterator ritor_widget
|
||||
= event_chain.rbegin();
|
||||
ritor_widget != event_chain.rend();
|
||||
++ritor_widget) {
|
||||
|
||||
tdispatcher::tsignal<T>& signal = tdispatcher_implementation
|
||||
::event_signal<T>(**ritor_widget, event);
|
||||
|
||||
for(typename std::vector<T>::iterator itor = signal.post_child.begin();
|
||||
itor != signal.post_child.end();
|
||||
++itor) {
|
||||
|
||||
functor(*itor, event, handled, halt);
|
||||
if(halt) {
|
||||
assert(handled);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(handled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**** ***** ***** Unhandled ***** ***** *****/
|
||||
assert(handled == false);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace event
|
||||
|
||||
} // namespace gui2
|
||||
|
||||
#endif
|
||||
|
Loading…
Add table
Reference in a new issue