ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/dclient/src/backend/ndk/transport.cpp
Revision: 1.5
Committed: Mon Oct 18 16:38:03 2010 UTC (16 years ago) by sf-pippijn
Branch: MAIN
Changes since 1.4: +0 -1 lines
Log Message:
support msg colours

File Contents

# User Rev Content
1 sf-pippijn 1.1 /* transport.cc
2     * This file is part of NDK++ library
3     * Copyright (c) 2003 by Stanislav Ievlev
4     *
5     * This file is covered by the GNU Library General Public License,
6     * which should be included with libndk++ as the file COPYING.
7     */
8    
9     #include <ndk++/transport.hh>
10    
11     #include <ndk++/application.hh>
12     #include <ndk++/events.hh>
13     #include <ndk++/keymap.hh>
14    
15     #include <ncurses/panel.hh>
16    
17     #include <adt/string.h>
18    
19     #include <curses.h>
20    
21     using namespace ndk;
22    
23     namespace
24     {
25     template<typename EventT>
26     struct run_impl
27     {
28     /**< functor to run callback functions */
29 sf-pippijn 1.4 run_impl (EventT const &e)
30 sf-pippijn 1.1 : e_ (e)
31     {
32     }
33    
34     template<typename CallbackT>
35     event::result operator () (CallbackT &callback)
36     {
37     return callback (e_);
38     }
39    
40 sf-pippijn 1.4 EventT const &e_;
41 sf-pippijn 1.1 };
42    
43     template<typename EventT>
44     run_impl<EventT>
45 sf-pippijn 1.4 run_callback (EventT const &e)
46 sf-pippijn 1.1 {
47     return run_impl<EventT> (e);
48     }
49    
50     template<typename Ret, typename Tp, typename Arg1T>
51     struct mem_fun1_impl
52     {
53     /**< simple helper binder of member function */
54     mem_fun1_impl (Ret (Tp::*f)(Arg1T), Arg1T arg)
55     : f_ (f)
56     , arg_ (arg)
57     {
58     }
59    
60     Ret operator () (Tp *obj)
61     {
62     return (obj->*f_)(arg_);
63     }
64    
65     Ret (Tp::*f_)(Arg1T);
66     Arg1T arg_;
67     };
68    
69     template<typename Ret, typename Tp, typename Arg1T, typename Arg2T>
70     struct mem_fun2_impl
71     {
72     /**< simple helper binder of member function */
73     mem_fun2_impl (Ret (Tp::*f)(Arg1T, Arg2T), Arg1T arg1, Arg2T arg2)
74     : f_ (f)
75     , arg1_ (arg1)
76     , arg2_ (arg2)
77     {
78     }
79    
80     Ret operator () (Tp *obj)
81     {
82     return (obj->*f_)(arg1_, arg2_);
83     }
84    
85     Ret (Tp::*f_)(Arg1T, Arg2T);
86     Arg1T arg1_;
87     Arg2T arg2_;
88     };
89     }
90    
91    
92     bool
93 sf-pippijn 1.4 mouse::over (ncurses::panel const &p) const
94 sf-pippijn 1.1 {
95     if (p.hidden ())
96     return false;
97     else
98     return p.x () <= x () && x () <= p.right_x () - 1 &&
99     p.y () <= y () && y () <= p.bottom_y () - 1;
100    
101     }
102    
103     engine::engine (engine *parent, ncurses::panel *geometry)
104     : geometry_ (geometry)
105     , in_focus_ (this)
106     , accept_ (true)
107     {
108     parent_ = parent ? parent : app ().events (); /* by default head is application */
109     parent_->add_child (this);
110     }
111    
112     engine::engine ()
113     : parent_ (0)
114     , geometry_ (0)
115     , in_focus_ (this)
116     , accept_ (true)
117     {
118     }
119    
120     engine::~engine ()
121     {
122     if (parent_)
123     parent_->del_child (this);
124     }
125    
126     void
127     engine::in_focus (engine *item)
128     {
129     if (std::find (childs_.begin (), childs_.end (), item) != childs_.end ())
130     {
131     in_focus_ = item;
132     in_focus_->system (event (enter_focus)); /* notify item */
133     }
134     else
135     throw std::runtime_error ("unable to set focus to unknown widget");
136     }
137    
138     engine *
139     engine::head () /**< @return main head of the transport tree */
140     {
141     engine *head = this; /* find local event loop head */
142    
143     while (head->parent_)
144     head = head->parent_;
145     return head;
146     }
147    
148     void
149     engine::update ()
150     {
151     update_panels (); /* update current status */
152 sf-pippijn 1.3 return_unless (doupdate () == OK);
153 sf-pippijn 1.1 }
154    
155     void
156     engine::process (int const ch)
157     {
158     key code = parsekey (esc_, ch);
159     if (code == key::mouse)
160     {
161     mouse ev = getmouse (esc_);
162     process (ev);
163     }
164     else if (code != key::intermediate)
165     {
166     keyboard ev (code);
167     process (ev);
168     }
169    
170 sf-pippijn 1.3 return_unless (doupdate () == OK); /* commit all changes to the screen */
171 sf-pippijn 1.1 }
172    
173     void
174 sf-pippijn 1.4 engine::on_keyboard (keyboard_event const &callback, bool front)
175 sf-pippijn 1.1 {
176     if (front)
177     keyboard_.push_front (callback);
178     else
179     keyboard_.push_back (callback);
180     }
181    
182     void
183     engine::on_mouse (mouse_event const &callback, bool front)
184     {
185     if (front)
186     mouse_.push_front (callback);
187     else
188     mouse_.push_back (callback);
189     }
190    
191     void
192 sf-pippijn 1.4 engine::on_system (system_event const &callback, bool front)
193 sf-pippijn 1.1 {
194     if (front)
195     system_.push_front (callback);
196     else
197     system_.push_back (callback);
198     }
199    
200     void
201     engine::rat (mouse const &ev)
202     {
203 sf-pippijn 1.2 foreach (mouse_event &m, mouse_)
204 sf-pippijn 1.1 m (ev);
205     }
206    
207     event::result
208 sf-pippijn 1.4 engine::kbd (keyboard const &kev)
209 sf-pippijn 1.1 {
210     event::result res = event::ignored;
211 sf-pippijn 1.4 keyboard const ev (kev.code (), geometry_);
212 sf-pippijn 1.1 kbd_events::iterator it = std::find_if (keyboard_.begin (),
213     keyboard_.end (),
214     run_callback (ev));
215    
216     if (it != keyboard_.end ())
217     {
218     res = event::accepted;
219     std::for_each (++it,
220     keyboard_.end (),
221     run_callback (ev));
222     }
223    
224     return res;
225     }
226    
227     event::result
228 sf-pippijn 1.4 engine::system (event const &ev)
229 sf-pippijn 1.1 {
230     event::result res = event::ignored;
231     sys_events::iterator it = std::find_if (system_.begin (),
232     system_.end (),
233     run_callback (ev));
234    
235     if (it != system_.end ())
236     {
237     res = event::accepted;
238     std::for_each (++it,
239     system_.end (),
240     run_callback (ev));
241     }
242    
243     return res;
244     }
245    
246     void
247     engine::add_child (engine *p)
248     {
249     childs_.push_back (p);
250     }
251    
252     void
253     engine::del_child (engine *p)
254     {
255     childs_.erase (std::remove (childs_.begin (),
256     childs_.end (),
257     p), childs_.end ());
258     }
259    
260     void
261     engine::little_switch (engine *item)
262     {
263     if (item == in_focus_ || !item->accept ())
264     return; /* nothing to switch */
265    
266     /* all permissions ok - let's switch focus now */
267     if (in_focus_ != this)
268     in_focus_->leave_all ();
269     in_focus_ = item;
270     if (in_focus_ != this)
271     in_focus_->enter_all ();
272    
273 sf-pippijn 1.2 update_panels (); /* update panel's status */
274 sf-pippijn 1.1 }
275    
276     void
277     engine::big_switch (engine *item)
278     {
279 sf-pippijn 1.4 child_items list; /* hierarchy we need to walk to produce a big switch */
280 sf-pippijn 1.1
281     /* first cycle determine widgets we need to switch */
282     for (; item != this; item = item->parent_)
283     list.push_back (item);
284    
285     for (child_items::reverse_iterator it = list.rbegin (); it != list.rend (); it++)
286     (*it)->parent_->little_switch (*it);
287     }
288    
289     void
290     engine::switch_to (engine *item)
291     {
292     head ()->big_switch (item);
293     }
294    
295     void
296     engine::find_over (mouse const &ev, child_items *list)
297     {
298     if (geometry_ && ev.over (*geometry_))
299     list->push_back (this);
300    
301 sf-pippijn 1.2 foreach (engine *child, childs_)
302 sf-pippijn 1.1 child->find_over (ev, list);
303     }
304    
305     void
306     engine::process (mouse const &ev)
307     {
308     /* walk throw the all objects and find all objects under mouse pointer */
309     child_items list;
310    
311     find_over (ev, &list);
312    
313     if (list.empty ())
314     {
315 sf-pippijn 1.3 flash ();
316 sf-pippijn 1.1 return;
317     }
318    
319     /* then find widget over all visible widgets */
320     child_items::iterator top = std::max_element (list.begin (),
321     list.end (),
322     higher);
323    
324     big_switch (*top); /* then made a big switch to top widget */
325    
326     /*
327     * let's widget process it's event
328     * find latest widget who can process mouse event
329     */
330     engine *current = *top;
331     while (!current->accept () && current->parent_)
332     current = current->parent_;
333     if (current->parent_)
334     current->rat (ev);
335     }
336    
337     void
338     engine::find_leafs (child_items *list)
339     {
340     child_items active_childs;
341    
342 sf-pippijn 1.2 foreach (engine *child, childs_)
343 sf-pippijn 1.1 child->find_leafs (&active_childs);
344    
345     /*
346     * if we cannot find active childs, but have active father
347     * then add father if it's not hidden now
348     */
349     if (active_childs.empty () && accept_ && geometry_ && !geometry_->hidden ())
350     list->push_back (this);
351     else
352     /* append active childs to the big list */
353     list->insert (list->end (), active_childs.begin (), active_childs.end ());
354     }
355    
356     void
357 sf-pippijn 1.4 engine::process (keyboard const &ev)
358 sf-pippijn 1.1 {
359     /*
360     * call at_event only for itself else call process event to pass messages
361     * to subwidgets, last widget always have in_focus_ equals "this"
362     */
363     engine *current = this;
364    
365 sf-pippijn 1.3 if (ev.code () == key::error)
366     throw "ERR";
367    
368 sf-pippijn 1.1 while (current->in_focus_ != current)
369     current = current->in_focus_;
370     if (current->kbd (ev) != event::accepted) /* if widget ignore processing then we can process it itself */
371     if (ev.code () == key::tab)
372     {
373     child_items list;
374     find_leafs (&list); /* collect all leaves of the transport subtree //FIXME: start search not from head, but from current in_focus */
375    
376     if (list.empty ())
377     return; /* nothing to switch to */
378    
379     engine *next; /* calculate next candidate to switch */
380     child_items::iterator it = std::find (list.begin (), list.end (), current);
381     if (it == list.end ()) /* first item by default */
382     next = list.at (0);
383     else
384     next = (++it == list.end ()) ? *list.begin () : *it;
385    
386     big_switch (next);
387     }
388     }
389    
390     void
391     engine::emit (int type)
392     {
393     head ()->process_system (event (type, this));
394     }
395    
396     event::result
397 sf-pippijn 1.4 engine::process_system (event const &ev)
398 sf-pippijn 1.1 {
399     /* find are some child accept this event */
400     child_items::const_iterator item =
401     std::find_if (childs_.begin (),
402     childs_.end (),
403 sf-pippijn 1.4 mem_fun1_impl<event::result, engine, event const &> (&engine::process_system, ev));
404 sf-pippijn 1.1
405     return (item != childs_.end ()) ? event::accepted : system (ev);
406     }
407    
408     /* send event to object and all it's childs */
409     void
410     engine::leave_all ()
411     {
412     system (event (leave_focus));
413 sf-pippijn 1.2 foreach (engine *child, childs_)
414 sf-pippijn 1.1 child->leave_all ();
415     }
416    
417     void
418     engine::enter_all ()
419     {
420     engine *current = this;
421    
422     while (current->in_focus_ != current)
423     {
424     current->system (event (enter_focus));
425     current = current->in_focus_;
426     }
427     current->system (event (enter_focus));
428     }
429    
430     void
431     engine::set_accept (bool val)
432     {
433     accept_ = val;
434     }
435    
436     bool
437     engine::accept () const
438     {
439     return accept_;
440     }