]> git.tdb.fi Git - libs/gltk.git/blob - source/container.cpp
Make the DISABLED state actually do something
[libs/gltk.git] / source / container.cpp
1 #include "container.h"
2
3 using namespace std;
4
5 namespace Msp {
6 namespace GLtk {
7
8 hierarchy_error::hierarchy_error(const string &w):
9         logic_error(w)
10 { }
11
12
13 Container::Container():
14         click_focus(0),
15         click_button(0),
16         pointer_focus(0),
17         pointer_grabbed(false),
18         input_focus(0)
19 { }
20
21 Container::~Container()
22 {
23         while(!children.empty())
24                 delete children.front()->widget;
25 }
26
27 void Container::add(Widget &wdg)
28 {
29         wdg.set_parent(this);
30         children.push_back(create_child(&wdg));
31         on_child_added(wdg);
32 }
33
34 void Container::remove(Widget &wdg)
35 {
36         for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
37                 if((*i)->widget==&wdg)
38                 {
39                         wdg.set_parent(0);
40                         delete *i;
41                         children.erase(i);
42                         on_child_removed(wdg);
43                         return;
44                 }
45
46         throw hierarchy_error("widget not in container");
47 }
48
49 Container::Child *Container::create_child(Widget *wdg)
50 {
51         return new Child(*this, wdg);
52 }
53
54 list<Widget *> Container::get_children() const
55 {
56         list<Widget *> result;
57         for(list<Child *>::const_iterator i=children.begin(); i!=children.end(); ++i)
58                 result.push_back((*i)->widget);
59         return result;
60 }
61
62 Widget *Container::get_child_at(int x, int y)
63 {
64         for(list<Child *>::iterator i=children.end(); i!=children.begin();)
65                 if((*--i)->widget->is_visible() && (*i)->widget->get_geometry().is_inside(x, y))
66                         return (*i)->widget;
67
68         return 0;
69 }
70
71 Widget *Container::get_descendant_at(int x, int y)
72 {
73         Widget *wdg = get_child_at(x, y);
74         if(Container *cont = dynamic_cast<Container *>(wdg))
75         {
76                 const Geometry &cgeom = wdg->get_geometry();
77                 Widget *wdg2 = cont->get_descendant_at(x-cgeom.x, y-cgeom.y);
78                 if(wdg2)
79                         return wdg2;
80         }
81         return wdg;
82 }
83
84 void Container::raise(Widget &wdg)
85 {
86         for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
87                 if((*i)->widget==&wdg)
88                 {
89                         children.splice(children.end(), children, i);
90                         return;
91                 }
92
93         throw hierarchy_error("widget not in container");
94 }
95
96 void Container::set_pointer_focus(Widget *wdg)
97 {
98         if(wdg!=pointer_focus)
99         {
100                 if(pointer_focus)
101                         pointer_focus->pointer_leave();
102
103                 pointer_focus = wdg;
104
105                 if(pointer_focus)
106                         pointer_focus->pointer_enter();
107         }
108 }
109
110 void Container::set_input_focus(Widget *wdg)
111 {
112         if(wdg!=input_focus)
113         {
114                 if(input_focus)
115                         input_focus->focus_out();
116
117                 input_focus = wdg;
118
119                 if(input_focus)
120                 {
121                         raise(*wdg);
122                         input_focus->focus_in();
123                 }
124         }
125 }
126
127 Widget *Container::get_final_input_focus() const
128 {
129         if(Container *container = dynamic_cast<Container *>(input_focus))
130                 if(Widget *focus = container->get_final_input_focus())
131                         return focus;
132
133         return input_focus;
134 }
135
136 void Container::button_press(int x, int y, unsigned btn)
137 {
138         if(Widget *child = get_pointer_target(x, y))
139         {
140                 if(!click_focus)
141                 {
142                         set_pointer_focus(child);
143                         if(child->is_focusable())
144                                 set_input_focus(child);
145
146                         click_focus = child;
147                         click_button = btn;
148                 }
149
150                 const Geometry &cgeom = child->get_geometry();
151                 child->button_press(x-cgeom.x, y-cgeom.y, btn);
152         }
153 }
154
155 void Container::button_release(int x, int y, unsigned btn)
156 {
157         if(Widget *child = get_pointer_target(x, y))
158         {
159                 if(child==click_focus && btn==click_button)
160                 {
161                         click_focus = 0;
162                         if(!pointer_focus)
163                                 set_pointer_focus(get_child_at(x, y));
164                 }
165
166                 const Geometry &cgeom = child->get_geometry();
167                 child->button_release(x-cgeom.x, y-cgeom.y, btn);
168         }
169 }
170
171 void Container::pointer_motion(int x, int y)
172 {
173         Widget *child = get_pointer_target(x, y);
174         if(!pointer_grabbed)
175                 set_pointer_focus((!click_focus || child->get_geometry().is_inside(x, y)) ? child : 0);
176
177         if(child)
178         {
179                 const Geometry &cgeom = child->get_geometry();
180                 child->pointer_motion(x-cgeom.x, y-cgeom.y);
181         }
182 }
183
184 Widget *Container::get_pointer_target(int x, int y)
185 {
186         if(pointer_grabbed)
187                 return pointer_focus;
188         else if(click_focus)
189                 return click_focus;
190         else
191         {
192                 Widget *child = get_child_at(x, y);
193                 if(child && child->is_enabled())
194                         return child;
195                 else
196                         return 0;
197         }
198 }
199
200 void Container::pointer_leave()
201 {
202         Widget::pointer_leave();
203         set_pointer_focus(0);
204 }
205
206 void Container::key_press(unsigned key, unsigned mod)
207 {
208         if(input_focus)
209                 input_focus->key_press(key, mod);
210 }
211
212 void Container::key_release(unsigned key, unsigned mod)
213 {
214         if(input_focus)
215                 input_focus->key_release(key, mod);
216 }
217
218 void Container::character(wchar_t ch)
219 {
220         if(input_focus)
221                 input_focus->character(ch);
222 }
223
224 void Container::focus_out()
225 {
226         set_input_focus(0);
227         Widget::focus_out();
228 }
229
230 void Container::on_reparent()
231 {
232         for(list<Child *>::iterator i=children.begin(); i!=children.end(); ++i)
233         {
234                 if(Container *c = dynamic_cast<Container *>((*i)->widget))
235                         c->on_reparent();
236                 (*i)->widget->update_style();
237         }
238 }
239
240
241 Container::Child::Child(Container &c, Widget *w):
242         container(c),
243         widget(w)
244 {
245         widget->signal_visibility_changed.connect(sigc::mem_fun(this, &Child::visibility_changed));
246         widget->signal_request_focus.connect(sigc::mem_fun(this, &Child::request_focus));
247         widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer));
248         widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer));
249 }
250
251 Container::Child::~Child()
252 {
253         visibility_changed(false);
254 }
255
256 void Container::Child::visibility_changed(bool v)
257 {
258         if(!v)
259         {
260                 if(widget==container.click_focus)
261                         container.click_focus = 0;
262                 if(widget==container.pointer_focus)
263                         container.set_pointer_focus(0);
264                 if(widget==container.input_focus)
265                         container.set_input_focus(0);
266         }
267 }
268
269 void Container::Child::request_focus()
270 {
271         container.set_input_focus(widget);
272         if(container.parent && container.visible)
273                 container.set_focus();
274 }
275
276 void Container::Child::grab_pointer()
277 {
278         if(!container.pointer_grabbed)
279         {
280                 container.set_pointer_focus(widget);
281                 container.pointer_grabbed = true;
282                 container.signal_grab_pointer.emit();
283         }
284 }
285
286 void Container::Child::ungrab_pointer()
287 {
288         if(container.pointer_grabbed && container.pointer_focus==widget)
289         {
290                 // XXX Should set to the widget under pointer
291                 container.set_pointer_focus(0);
292                 container.pointer_grabbed = false;
293                 container.signal_ungrab_pointer.emit();
294         }
295 }
296
297 } // namespace GLtk
298 } // namespace Msp