ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/cf.schmorp.de/dclient/src/backend/ndk/transport.cpp
Revision: 1.4
Committed: Mon Oct 18 15:34:23 2010 UTC (16 years ago) by sf-pippijn
Branch: MAIN
Changes since 1.3: +13 -16 lines
Log Message:
first attempt to support maximising windows

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 sf-pippijn 1.4 run_impl (EventT const &e)
31 sf-pippijn 1.1 : e_ (e)
32     {
33     }
34    
35     template<typename CallbackT>
36     event::result operator () (CallbackT &callback)
37     {
38     return callback (e_);
39     }
40    
41 sf-pippijn 1.4 EventT const &e_;
42 sf-pippijn 1.1 };
43    
44     template<typename EventT>
45     run_impl<EventT>
46 sf-pippijn 1.4 run_callback (EventT const &e)
47 sf-pippijn 1.1 {
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 sf-pippijn 1.4 mouse::over (ncurses::panel const &p) const
95 sf-pippijn 1.1 {
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 sf-pippijn 1.3 return_unless (doupdate () == OK);
154 sf-pippijn 1.1 }
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 sf-pippijn 1.3 return_unless (doupdate () == OK); /* commit all changes to the screen */
172 sf-pippijn 1.1 }
173    
174     void
175 sf-pippijn 1.4 engine::on_keyboard (keyboard_event const &callback, bool front)
176 sf-pippijn 1.1 {
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 sf-pippijn 1.4 engine::on_system (system_event const &callback, bool front)
194 sf-pippijn 1.1 {
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 sf-pippijn 1.4 engine::kbd (keyboard const &kev)
210 sf-pippijn 1.1 {
211     event::result res = event::ignored;
212 sf-pippijn 1.4 keyboard const ev (kev.code (), geometry_);
213 sf-pippijn 1.1 kbd_events::iterator it = std::find_if (keyboard_.begin (),
214     keyboard_.end (),
215     run_callback (ev));
216    
217     if (it != keyboard_.end ())
218     {
219     res = event::accepted;
220     std::for_each (++it,
221     keyboard_.end (),
222     run_callback (ev));
223     }
224    
225     return res;
226     }
227    
228     event::result
229 sf-pippijn 1.4 engine::system (event const &ev)
230 sf-pippijn 1.1 {
231     event::result res = event::ignored;
232     sys_events::iterator it = std::find_if (system_.begin (),
233     system_.end (),
234     run_callback (ev));
235    
236     if (it != system_.end ())
237     {
238     res = event::accepted;
239     std::for_each (++it,
240     system_.end (),
241     run_callback (ev));
242     }
243    
244     return res;
245     }
246    
247     void
248     engine::add_child (engine *p)
249     {
250     childs_.push_back (p);
251     }
252    
253     void
254     engine::del_child (engine *p)
255     {
256     childs_.erase (std::remove (childs_.begin (),
257     childs_.end (),
258     p), childs_.end ());
259     }
260    
261     void
262     engine::little_switch (engine *item)
263     {
264     if (item == in_focus_ || !item->accept ())
265     return; /* nothing to switch */
266    
267     /* all permissions ok - let's switch focus now */
268     if (in_focus_ != this)
269     in_focus_->leave_all ();
270     in_focus_ = item;
271     if (in_focus_ != this)
272     in_focus_->enter_all ();
273    
274 sf-pippijn 1.2 update_panels (); /* update panel's status */
275 sf-pippijn 1.1 }
276    
277     void
278     engine::big_switch (engine *item)
279     {
280 sf-pippijn 1.4 child_items list; /* hierarchy we need to walk to produce a big switch */
281 sf-pippijn 1.1
282     /* first cycle determine widgets we need to switch */
283     for (; item != this; item = item->parent_)
284     list.push_back (item);
285    
286     for (child_items::reverse_iterator it = list.rbegin (); it != list.rend (); it++)
287     (*it)->parent_->little_switch (*it);
288     }
289    
290     void
291     engine::switch_to (engine *item)
292     {
293     head ()->big_switch (item);
294     }
295    
296     void
297     engine::find_over (mouse const &ev, child_items *list)
298     {
299     if (geometry_ && ev.over (*geometry_))
300     list->push_back (this);
301    
302 sf-pippijn 1.2 foreach (engine *child, childs_)
303 sf-pippijn 1.1 child->find_over (ev, list);
304     }
305    
306     void
307     engine::process (mouse const &ev)
308     {
309     /* walk throw the all objects and find all objects under mouse pointer */
310     child_items list;
311    
312     find_over (ev, &list);
313    
314     if (list.empty ())
315     {
316 sf-pippijn 1.3 flash ();
317 sf-pippijn 1.1 return;
318     }
319    
320     /* then find widget over all visible widgets */
321     child_items::iterator top = std::max_element (list.begin (),
322     list.end (),
323     higher);
324    
325     big_switch (*top); /* then made a big switch to top widget */
326    
327     /*
328     * let's widget process it's event
329     * find latest widget who can process mouse event
330     */
331     engine *current = *top;
332     while (!current->accept () && current->parent_)
333     current = current->parent_;
334     if (current->parent_)
335     current->rat (ev);
336     }
337    
338     void
339     engine::find_leafs (child_items *list)
340     {
341     child_items active_childs;
342    
343 sf-pippijn 1.2 foreach (engine *child, childs_)
344 sf-pippijn 1.1 child->find_leafs (&active_childs);
345    
346     /*
347     * if we cannot find active childs, but have active father
348     * then add father if it's not hidden now
349     */
350     if (active_childs.empty () && accept_ && geometry_ && !geometry_->hidden ())
351     list->push_back (this);
352     else
353     /* append active childs to the big list */
354     list->insert (list->end (), active_childs.begin (), active_childs.end ());
355     }
356    
357     void
358 sf-pippijn 1.4 engine::process (keyboard const &ev)
359 sf-pippijn 1.1 {
360     /*
361     * call at_event only for itself else call process event to pass messages
362     * to subwidgets, last widget always have in_focus_ equals "this"
363     */
364     engine *current = this;
365    
366 sf-pippijn 1.3 if (ev.code () == key::error)
367     throw "ERR";
368    
369 sf-pippijn 1.1 while (current->in_focus_ != current)
370     current = current->in_focus_;
371     if (current->kbd (ev) != event::accepted) /* if widget ignore processing then we can process it itself */
372     if (ev.code () == key::tab)
373     {
374     child_items list;
375     find_leafs (&list); /* collect all leaves of the transport subtree //FIXME: start search not from head, but from current in_focus */
376    
377     if (list.empty ())
378     return; /* nothing to switch to */
379    
380     engine *next; /* calculate next candidate to switch */
381     child_items::iterator it = std::find (list.begin (), list.end (), current);
382     if (it == list.end ()) /* first item by default */
383     next = list.at (0);
384     else
385     next = (++it == list.end ()) ? *list.begin () : *it;
386    
387     big_switch (next);
388     }
389     }
390    
391     void
392     engine::emit (int type)
393     {
394     head ()->process_system (event (type, this));
395     }
396    
397     event::result
398 sf-pippijn 1.4 engine::process_system (event const &ev)
399 sf-pippijn 1.1 {
400     /* find are some child accept this event */
401     child_items::const_iterator item =
402     std::find_if (childs_.begin (),
403     childs_.end (),
404 sf-pippijn 1.4 mem_fun1_impl<event::result, engine, event const &> (&engine::process_system, ev));
405 sf-pippijn 1.1
406     return (item != childs_.end ()) ? event::accepted : system (ev);
407     }
408    
409     /* send event to object and all it's childs */
410     void
411     engine::leave_all ()
412     {
413     system (event (leave_focus));
414 sf-pippijn 1.2 foreach (engine *child, childs_)
415 sf-pippijn 1.1 child->leave_all ();
416     }
417    
418     void
419     engine::enter_all ()
420     {
421     engine *current = this;
422    
423     while (current->in_focus_ != current)
424     {
425     current->system (event (enter_focus));
426     current = current->in_focus_;
427     }
428     current->system (event (enter_focus));
429     }
430    
431     void
432     engine::set_accept (bool val)
433     {
434     accept_ = val;
435     }
436    
437     bool
438     engine::accept () const
439     {
440     return accept_;
441     }