9 hierarchy_error::hierarchy_error(const string &w):
14 Container::Container():
18 pointer_grabbed(false),
23 Container::~Container()
25 while(!children.empty())
26 delete children.front()->widget;
29 void Container::add(Widget &wdg)
32 children.push_back(create_child(&wdg));
36 void Container::remove(Widget &wdg)
38 for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
39 if((*i)->widget==&wdg)
44 on_child_removed(wdg);
48 throw hierarchy_error("widget not in container");
51 Container::Child *Container::create_child(Widget *wdg)
53 return new Child(*this, wdg);
56 Geometry Container::determine_child_geometry(const Widget &child, const Part &part) const
58 Geometry pgeom = part.get_geometry();
59 if(!pgeom.w || !pgeom.h)
62 child.autosize(cgeom);
69 part.get_alignment().apply(pgeom, geom, part.get_margin());
73 void Container::autosize_child(const Widget &child, const Part &part, Geometry &ageom) const
75 Geometry cgeom = determine_child_geometry(child, part);
76 const Sides &margin = part.get_margin();
77 ageom.w = max(ageom.w, cgeom.w+margin.left+margin.right);
78 ageom.h = max(ageom.h, cgeom.h+margin.top+margin.bottom);
81 void Container::reposition_child(Widget &child, const Part &part) const
83 child.set_geometry(determine_child_geometry(child, part));
86 list<Widget *> Container::get_children() const
88 list<Widget *> result;
89 for(list<Child *>::const_iterator i=children.begin(); i!=children.end(); ++i)
90 result.push_back((*i)->widget);
94 Widget *Container::get_child_at(int x, int y) const
96 for(list<Child *>::const_iterator i=children.end(); i!=children.begin();)
97 if((*--i)->widget->is_visible() && (*i)->widget->get_geometry().is_inside(x, y))
103 Widget *Container::get_descendant_at(int x, int y) const
105 Widget *wdg = get_child_at(x, y);
106 if(Container *cont = dynamic_cast<Container *>(wdg))
108 const Geometry &cgeom = wdg->get_geometry();
109 Widget *wdg2 = cont->get_descendant_at(x-cgeom.x, y-cgeom.y);
116 void Container::raise(Widget &wdg)
118 for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
119 if((*i)->widget==&wdg)
121 children.splice(children.end(), children, i);
125 throw hierarchy_error("widget not in container");
128 void Container::set_pointer_focus(Widget *wdg)
130 if(wdg!=pointer_focus)
133 pointer_focus->pointer_leave();
138 pointer_focus->pointer_enter();
142 void Container::set_input_focus(Widget *wdg)
147 input_focus->focus_out();
154 input_focus->focus_in();
159 Widget *Container::get_final_input_focus() const
161 if(Container *container = dynamic_cast<Container *>(input_focus))
162 if(Widget *focus = container->get_final_input_focus())
168 void Container::button_press(int x, int y, unsigned btn)
170 if(Widget *child = get_pointer_target(x, y, false))
174 set_pointer_focus(child);
175 if(child->is_focusable())
176 set_input_focus(child);
182 const Geometry &cgeom = child->get_geometry();
183 child->button_press(x-cgeom.x, y-cgeom.y, btn);
187 void Container::button_release(int x, int y, unsigned btn)
189 if(Widget *child = get_pointer_target(x, y, false))
191 if(child==click_focus && btn==click_button)
195 set_pointer_focus(get_child_at(x, y));
198 const Geometry &cgeom = child->get_geometry();
199 child->button_release(x-cgeom.x, y-cgeom.y, btn);
203 void Container::pointer_motion(int x, int y)
205 Widget *child = get_pointer_target(x, y, false);
207 set_pointer_focus((!click_focus || child->get_geometry().is_inside(x, y)) ? child : 0);
211 const Geometry &cgeom = child->get_geometry();
212 child->pointer_motion(x-cgeom.x, y-cgeom.y);
216 Widget *Container::get_pointer_target(int x, int y, bool touch) const
219 return pointer_focus;
220 else if(!touch && click_focus)
222 else if(touch && touch_focus)
226 Widget *child = get_child_at(x, y);
227 if(child && child->is_enabled())
234 void Container::pointer_leave()
236 Widget::pointer_leave();
237 set_pointer_focus(0);
240 void Container::touch_press(int x, int y, unsigned finger)
242 if(Widget *child = get_pointer_target(x, y, true))
244 // TODO track focus for each finger separately
248 const Geometry &cgeom = child->get_geometry();
249 child->touch_press(x-cgeom.x, y-cgeom.y, finger);
253 void Container::touch_release(int x, int y, unsigned finger)
255 if(Widget *child = get_pointer_target(x, y, true))
257 // TODO track focus for each finger separately
258 if(child==touch_focus)
261 const Geometry &cgeom = child->get_geometry();
262 child->touch_release(x-cgeom.x, y-cgeom.y, finger);
266 void Container::touch_motion(int x, int y, unsigned finger)
268 if(Widget *child = get_pointer_target(x, y, true))
270 const Geometry &cgeom = child->get_geometry();
271 child->touch_motion(x-cgeom.x, y-cgeom.y, finger);
275 bool Container::key_press(unsigned key, unsigned mod)
278 return input_focus->key_press(key, mod);
283 bool Container::key_release(unsigned key, unsigned mod)
286 return input_focus->key_release(key, mod);
291 bool Container::character(wchar_t ch)
294 return input_focus->character(ch);
299 void Container::focus_out()
305 bool Container::navigate(Navigation nav)
307 if(input_focus && input_focus->navigate(nav))
310 if(nav==NAV_UP || nav==NAV_DOWN || nav==NAV_LEFT || nav==NAV_RIGHT)
316 const Geometry &fgeom = input_focus->get_geometry();
317 x = fgeom.x+fgeom.w/2;
318 y = fgeom.y+fgeom.h/2;
322 else if(nav==NAV_DOWN)
324 else if(nav==NAV_RIGHT)
326 else if(nav==NAV_LEFT)
331 for(list<Child *>::const_iterator i=children.begin(); i!=children.end(); ++i)
333 if((*i)->widget==input_focus || !(*i)->widget->is_focusable())
336 const Geometry &cgeom = (*i)->widget->get_geometry();
337 int dx = cgeom.x+cgeom.w/2-x;
338 int dy = cgeom.y+cgeom.h/2-y;
341 if(nav==NAV_UP && dy>0)
342 score = dy+abs(dx)*4;
343 else if(nav==NAV_DOWN && dy<0)
344 score = -dy+abs(dx)*4;
345 else if(nav==NAV_RIGHT && dx>0)
346 score = dx+abs(dy)*4;
347 else if(nav==NAV_LEFT && dx<0)
348 score = -dx+abs(dy)*4;
350 if(score>0 && (!sibling || score<best_score))
352 sibling = (*i)->widget;
359 set_input_focus(sibling);
360 if(Container *container = dynamic_cast<Container *>(sibling))
361 container->navigate(nav);
369 void Container::on_reparent()
371 for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
373 if(Container *c = dynamic_cast<Container *>((*i)->widget))
375 (*i)->widget->update_style();
380 Container::Child::Child(Container &c, Widget *w):
384 widget->signal_visibility_changed.connect(sigc::mem_fun(this, &Child::visibility_changed));
385 widget->signal_request_focus.connect(sigc::mem_fun(this, &Child::request_focus));
386 widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer));
387 widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer));
390 Container::Child::~Child()
392 visibility_changed(false);
395 void Container::Child::visibility_changed(bool v)
399 if(widget==container.click_focus)
400 container.click_focus = 0;
401 if(widget==container.pointer_focus)
402 container.set_pointer_focus(0);
403 if(widget==container.input_focus)
404 container.set_input_focus(0);
408 void Container::Child::request_focus()
410 container.set_input_focus(widget);
411 if(container.parent && container.visible)
412 container.set_focus();
415 void Container::Child::grab_pointer()
417 if(!container.pointer_grabbed)
419 container.set_pointer_focus(widget);
420 container.pointer_grabbed = true;
421 container.signal_grab_pointer.emit();
425 void Container::Child::ungrab_pointer()
427 if(container.pointer_grabbed && container.pointer_focus==widget)
429 // XXX Should set to the widget under pointer
430 container.set_pointer_focus(0);
431 container.pointer_grabbed = false;
432 container.signal_ungrab_pointer.emit();