Photon microGUI widgets library 0.6.0
phevent.hpp
1#ifndef PH_EVENT_HPP
2#define PH_EVENT_HPP
3
4#include <photon/PtWidget.h>
5
6#include <set>
7#include <map>
8
9
10namespace phevents
11{
12 namespace detail
13 {
14 struct Void {};
15
16 template<typename ValueT, typename ParentT>
17 struct get_parent_func
18 {
19 typedef ValueT value_t;
20 typedef ParentT parent_t;
21 typedef void(parent_t::* adder_t)(value_t);
22 typedef void(parent_t::* remover_t)(value_t);
23
24 static const adder_t &default_adder() { static adder_t adder = adder_t(0); return adder; }
25 static const remover_t &default_remover() { static remover_t remover = remover_t(0); return remover; }
26 };
27
28 template<>
29 struct get_parent_func<void, void>
30 {
31 typedef void value_t;
32 typedef Void parent_t;
33 typedef const int adder_t;
34 typedef const int remover_t;
35
36 static const adder_t &default_adder() { static adder_t adder = 0; return adder; }
37 static const remover_t &default_remover() { static remover_t remover = 0; return remover; }
38 };
39
40 template<typename ValueT>
41 struct get_parent_func<ValueT, void> :
42 public get_parent_func<void, void>
43 {
44 };
45
46 template<typename ParentT>
47 struct get_parent_func<void, ParentT> :
48 public get_parent_func<void, void>
49 {
50 };
51 }
52
53 class phevent
54 {
55 class callback_container
56 {
57 typedef int(*callback_t)( PtWidget_t *, void *, PtCallbackInfo_t * );
58 typedef int(*callback_proxy_t)(const callback_container *, PtWidget_t *, void *, PtCallbackInfo_t * );
59
60 public:
61
62 template<class Param1T, class Param2T, class Param3T>
63 callback_container(int(*callback)( Param1T, Param2T, Param3T)):
64 _callback(reinterpret_cast<callback_t>(callback)),
65 _proxy_call(&callback_container::proxy_call<Param1T, Param2T, Param3T>)
66 {}
67
68 template<class Param1T, class Param2T, class Param3T>
69 void init()
70 {
71 _proxy_call = &callback_container::proxy_call<Param1T, Param2T, Param3T>;
72 }
73
74 inline int operator()(PtWidget_t *p1, void *p2, PtCallbackInfo_t *p3) const
75 {
76 return _proxy_call(this, p1, p2, p3);
77 }
78
79 inline bool operator<(const callback_container &rhs) const
80 {
81 if(std::less<callback_t>()(_callback, rhs._callback))
82 return true;
83 if(std::less<callback_proxy_t>()(_proxy_call, rhs._proxy_call))
84 return true;
85
86 return false;
87 }
88
89 private:
90 callback_t _callback;
91 callback_proxy_t _proxy_call;
92
93 template<class Param1T, class Param2T, class Param3T>
94 static int proxy_call(const callback_container *container, PtWidget_t *p1, void *p2, PtCallbackInfo_t *p3)
95 {
96 return reinterpret_cast<int(*)(Param1T, Param2T, Param3T)>(container->_callback)(p1, reinterpret_cast<Param2T>(p2), p3);
97 }
98 };
99
100 public:
101 class ph_callback_t
102 {
103 class cb_with_data
104 {
105 typedef std::set<callback_container> callback_repo_t;
106
107 public:
108
109 cb_with_data(callback_container cb, void *dt = 0)
110 {
111 std::pair<callback_repo_t::iterator, bool> res = cb_with_data::repo().insert(cb);
112
113 callback = &(*res.first);
114 data = dt;
115 }
116
117 inline int operator()(PtWidget_t *p1, PtCallbackInfo_t *p3) const
118 {
119 return (*callback)(p1, data, p3);
120 }
121
122 inline bool operator<(const cb_with_data &rhs) const
123 {
124 if(std::less<const callback_container*>()(callback, rhs.callback))
125 return true;
126 if(std::less<void*>()(data, rhs.data))
127 return true;
128
129 return false;
130 }
131
132 private:
133 const callback_container *callback;
134 void *data;
135
136 static callback_repo_t &repo() { static callback_repo_t repo; return repo; }
137 };
138
139 typedef std::set<cb_with_data> cb_data_repo_t;
140
141 static cb_data_repo_t &repo() { static cb_data_repo_t repo; return repo; }
142
143 static int proxy_call(PtWidget_t *p1, void *p2, PtCallbackInfo_t *p3)
144 {
145 const cb_with_data &cbwd = *reinterpret_cast<const cb_with_data*>(p2);
146
147 cb_data_repo_t::iterator it = repo().find(cbwd);
148
149 if(repo().end() == it)
150 return 0;
151
152 return cbwd(p1, p3);
153 }
154
155 public:
156 ph_callback_t(const PtCallback_t &callback):
157 _callback(callback)
158 {}
159
160 template<class Param1T, class Param2T, class Param3T>
161 ph_callback_t(int(*value)(Param1T, Param2T, Param3T))
162 {
163 std::pair<cb_data_repo_t::iterator, bool> res = repo().insert(cb_with_data(value));
164
165 _callback.event_f = &proxy_call;
166 _callback.data = const_cast<cb_with_data*>(&(*(res.first)));
167 }
168
169 template<class Param1T, class Param2T, class Param3T>
170 ph_callback_t(int(*value)(Param1T, Param2T, Param3T), Param2T &data)
171 {
172 std::pair<cb_data_repo_t::iterator, bool> res = repo().insert(cb_with_data(value, data));
173
174 _callback.event_f = &proxy_call;
175 _callback.data = const_cast<cb_with_data*>(&(*(res.first)));
176 }
177
178 ~ph_callback_t()
179 {
180 //do NOTHING!
181 }
182
183 inline operator PtCallback_t() const{ return _callback; }
184
185 private:
186 PtCallback_t _callback;
187 };
188
189 template<class ParentT, typename detail::get_parent_func<ph_callback_t, ParentT>::adder_t Adder, typename detail::get_parent_func<ph_callback_t, ParentT>::remover_t Remover = detail::get_parent_func<ph_callback_t, ParentT>::default_remover()>
190 class bind
191 {
192 typedef typename detail::get_parent_func<ph_callback_t, ParentT>::value_t value_t;
193
194 public:
195 bind(ParentT *parent) :
196 _obj(parent)
197 {}
198
199 inline void add(value_t value)
200 {
201 (_obj->*Adder)(value);
202 }
203
204 inline void remove(value_t value)
205 {
206 (_obj->*Remover)(value);
207 }
208
209 inline void operator+=(value_t value)
210 {
211 add(value);
212 }
213
214 inline void operator-=(value_t value)
215 {
216 remove(value);
217 }
218
219
220 private:
221 ParentT *_obj;
222
223 bind(const bind &rhs);
224
225 inline bind &operator=(value_t);
226 inline bind &operator=(bind const &);
227 };
228 };
229
230}
231
232#endif