ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/dclient/src/backend/ndk/transport.cpp
Revision: 1.2
Committed: Mon Oct 18 06:54:03 2010 UTC (16 years ago) by sf-pippijn
Branch: MAIN
Changes since 1.1: +5 -5 lines
Log Message:
gcc 4.5; moved some code; background colour support

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/assert.hh>
16     #include <ncurses/panel.hh>
17    
18     #include <adt/string.h>
19    
20     #include <curses.h>
21    
22     using namespace ndk;
23    
24     namespace
25     {
26     template<typename EventT>
27     struct run_impl
28     {
29     /**< functor to run callback functions */
30     run_impl (const EventT &e)
31     : e_ (e)
32     {
33     }
34    
35     template<typename CallbackT>
36     event::result operator () (CallbackT &callback)
37     {
38     return callback (e_);
39     }
40    
41     const EventT &e_;
42     };
43    
44     template<typename EventT>
45     run_impl<EventT>
46     run_callback (const EventT &e)
47     {
48     return run_impl<EventT> (e);
49     }
50    
51     template<typename Ret, typename Tp, typename Arg1T>
52     struct mem_fun1_impl
53     {
54     /**< simple helper binder of member function */
55     mem_fun1_impl (Ret (Tp::*f)(Arg1T), Arg1T arg)
56     : f_ (f)
57     , arg_ (arg)
58     {
59     }
60    
61     Ret operator () (Tp *obj)
62     {
63     return (obj->*f_)(arg_);
64     }
65    
66     Ret (Tp::*f_)(Arg1T);
67     Arg1T arg_;
68     };
69    
70     template<typename Ret, typename Tp, typename Arg1T, typename Arg2T>
71     struct mem_fun2_impl
72     {
73     /**< simple helper binder of member function */
74     mem_fun2_impl (Ret (Tp::*f)(Arg1T, Arg2T), Arg1T arg1, Arg2T arg2)
75     : f_ (f)
76     , arg1_ (arg1)
77     , arg2_ (arg2)
78     {
79     }
80    
81     Ret operator () (Tp *obj)
82     {
83     return (obj->*f_)(arg1_, arg2_);
84     }
85    
86     Ret (Tp::*f_)(Arg1T, Arg2T);
87     Arg1T arg1_;
88     Arg2T arg2_;
89     };
90     }
91    
92    
93     bool
94     mouse::over (const ncurses::panel &p) const
95     {
96     if (p.hidden ())
97     return false;
98     else
99     return p.x () <= x () && x () <= p.right_x () - 1 &&
100     p.y () <= y () && y () <= p.bottom_y () - 1;
101    
102     }
103    
104     engine::engine (engine *parent, ncurses::panel *geometry)
105     : geometry_ (geometry)
106     , in_focus_ (this)
107     , accept_ (true)
108     {
109     parent_ = parent ? parent : app ().events (); /* by default head is application */
110     parent_->add_child (this);
111     }
112    
113     engine::engine ()
114     : parent_ (0)
115     , geometry_ (0)
116     , in_focus_ (this)
117     , accept_ (true)
118     {
119     }
120    
121     engine::~engine ()
122     {
123     if (parent_)
124     parent_->del_child (this);
125     }
126    
127     void
128     engine::in_focus (engine *item)
129     {
130     if (std::find (childs_.begin (), childs_.end (), item) != childs_.end ())
131     {
132     in_focus_ = item;
133     in_focus_->system (event (enter_focus)); /* notify item */
134     }
135     else
136     throw std::runtime_error ("unable to set focus to unknown widget");
137     }
138    
139     engine *
140     engine::head () /**< @return main head of the transport tree */
141     {
142     engine *head = this; /* find local event loop head */
143    
144     while (head->parent_)
145     head = head->parent_;
146     return head;
147     }
148    
149     void
150     engine::update ()
151     {
152     update_panels (); /* update current status */
153     doupdate ();
154     }
155    
156     void
157     engine::process (int const ch)
158     {
159     key code = parsekey (esc_, ch);
160     if (code == key::mouse)
161     {
162     mouse ev = getmouse (esc_);
163     process (ev);
164     }
165     else if (code != key::intermediate)
166     {
167     keyboard ev (code);
168     process (ev);
169     }
170    
171     doupdate (); /* commit all changes to the screen */
172     }
173    
174     void
175     engine::on_keyboard (const keyboard_event &callback, bool front)
176     {
177     if (front)
178     keyboard_.push_front (callback);
179     else
180     keyboard_.push_back (callback);
181     }
182    
183     void
184     engine::on_mouse (mouse_event const &callback, bool front)
185     {
186     if (front)
187     mouse_.push_front (callback);
188     else
189     mouse_.push_back (callback);
190     }
191    
192     void
193     engine::on_system (const system_event &callback, bool front)
194     {
195     if (front)
196     system_.push_front (callback);
197     else
198     system_.push_back (callback);
199     }
200    
201     void
202     engine::rat (mouse const &ev)
203     {
204 sf-pippijn 1.2 foreach (mouse_event &m, mouse_)
205 sf-pippijn 1.1 m (ev);
206     }
207    
208     event::result
209     engine::kbd (const keyboard &ev)
210     {
211     event::result res = event::ignored;
212     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     engine::system (const event &ev)
229     {
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     child_items list; /* hierachly we need to walk to produce a big switch */
280    
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     beep ();
316     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     engine::process (const keyboard &ev)
358     {
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     while (current->in_focus_ != current)
366     current = current->in_focus_;
367     if (current->kbd (ev) != event::accepted) /* if widget ignore processing then we can process it itself */
368     if (ev.code () == key::tab)
369     {
370     child_items list;
371     find_leafs (&list); /* collect all leaves of the transport subtree //FIXME: start search not from head, but from current in_focus */
372    
373     if (list.empty ())
374     return; /* nothing to switch to */
375    
376     engine *next; /* calculate next candidate to switch */
377     child_items::iterator it = std::find (list.begin (), list.end (), current);
378     if (it == list.end ()) /* first item by default */
379     next = list.at (0);
380     else
381     next = (++it == list.end ()) ? *list.begin () : *it;
382    
383     big_switch (next);
384     }
385     }
386    
387     void
388     engine::emit (int type)
389     {
390     head ()->process_system (event (type, this));
391     }
392    
393     event::result
394     engine::process_system (const event &ev)
395     {
396     /* find are some child accept this event */
397     child_items::const_iterator item =
398     std::find_if (childs_.begin (),
399     childs_.end (),
400     mem_fun1_impl<event::result, engine, const event &> (&engine::process_system, ev));
401    
402     return (item != childs_.end ()) ? event::accepted : system (ev);
403     }
404    
405     /* send event to object and all it's childs */
406     void
407     engine::leave_all ()
408     {
409     system (event (leave_focus));
410 sf-pippijn 1.2 foreach (engine *child, childs_)
411 sf-pippijn 1.1 child->leave_all ();
412     }
413    
414     void
415     engine::enter_all ()
416     {
417     engine *current = this;
418    
419     while (current->in_focus_ != current)
420     {
421     current->system (event (enter_focus));
422     current = current->in_focus_;
423     }
424     current->system (event (enter_focus));
425     }
426    
427     void
428     engine::set_accept (bool val)
429     {
430     accept_ = val;
431     }
432    
433     bool
434     engine::accept () const
435     {
436     return accept_;
437     }