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 void Container::on_reparent()
307 for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
309 if(Container *c = dynamic_cast<Container *>((*i)->widget))
311 (*i)->widget->update_style();
316 Container::Child::Child(Container &c, Widget *w):
320 widget->signal_visibility_changed.connect(sigc::mem_fun(this, &Child::visibility_changed));
321 widget->signal_request_focus.connect(sigc::mem_fun(this, &Child::request_focus));
322 widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer));
323 widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer));
326 Container::Child::~Child()
328 visibility_changed(false);
331 void Container::Child::visibility_changed(bool v)
335 if(widget==container.click_focus)
336 container.click_focus = 0;
337 if(widget==container.pointer_focus)
338 container.set_pointer_focus(0);
339 if(widget==container.input_focus)
340 container.set_input_focus(0);
344 void Container::Child::request_focus()
346 container.set_input_focus(widget);
347 if(container.parent && container.visible)
348 container.set_focus();
351 void Container::Child::grab_pointer()
353 if(!container.pointer_grabbed)
355 container.set_pointer_focus(widget);
356 container.pointer_grabbed = true;
357 container.signal_grab_pointer.emit();
361 void Container::Child::ungrab_pointer()
363 if(container.pointer_grabbed && container.pointer_focus==widget)
365 // XXX Should set to the widget under pointer
366 container.set_pointer_focus(0);
367 container.pointer_grabbed = false;
368 container.signal_ungrab_pointer.emit();