]> git.tdb.fi Git - libs/gltk.git/blob - source/panel.cpp
Store the Resources reference only in Root widget
[libs/gltk.git] / source / panel.cpp
1 /* $Id$
2
3 This file is part of libmspgltk
4 Copyright © 2007-2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <algorithm>
9 #include <msp/core/refptr.h>
10 #include "button.h"
11 #include "dropdown.h"
12 #include "entry.h"
13 #include "hslider.h"
14 #include "indicator.h"
15 #include "label.h"
16 #include "list.h"
17 #include "panel.h"
18 #include "part.h"
19 #include "table.h"
20 #include "toggle.h"
21 #include "vslider.h"
22
23 using namespace std;
24
25 namespace Msp {
26 namespace GLtk {
27
28 Panel::Panel():
29         pointer_focus(0),
30         pointer_grabbed(false),
31         input_focus(0)
32 { }
33
34 void Panel::raise(Widget &wdg)
35 {
36         for(list<Container::Child *>::iterator i=children.begin(); i!=children.end(); ++i)
37                 if((*i)->widget==&wdg)
38                 {
39                         children.splice(children.end(), children, i);
40                         return;
41                 }
42
43         throw InvalidState("That Widget is not in this Panel");
44 }
45
46 Widget *Panel::get_final_input_focus() const
47 {
48         if(Panel *panel = dynamic_cast<Panel *>(input_focus))
49         {
50                 Widget *focus = panel->get_final_input_focus();
51                 if(focus)
52                         return focus;
53         }
54         return input_focus;
55 }
56
57 void Panel::button_press(int x, int y, unsigned btn)
58 {
59         if(pointer_grabbed)
60         {
61                 const Geometry &cgeom = pointer_focus->get_geometry();
62                 pointer_focus->button_press(x-cgeom.x, y-cgeom.y, btn);
63         }
64         else
65         {
66                 if(Widget *wdg = get_child_at(x, y))
67                 {
68                         set_pointer_focus(wdg);
69                         if(wdg->is_focusable())
70                                 set_input_focus(wdg);
71                 }
72                 Container::button_press(x, y, btn);
73         }
74 }
75
76 void Panel::button_release(int x, int y, unsigned btn)
77 {
78         if(pointer_grabbed)
79         {
80                 const Geometry &cgeom = pointer_focus->get_geometry();
81                 pointer_focus->button_release(x-cgeom.x, y-cgeom.y, btn);
82         }
83         else
84                 Container::button_release(x, y, btn);
85 }
86
87 void Panel::pointer_motion(int x, int y)
88 {
89         if(pointer_grabbed)
90         {
91                 const Geometry &cgeom = pointer_focus->get_geometry();
92                 pointer_focus->pointer_motion(x-cgeom.x, y-cgeom.y);
93         }
94         else
95         {
96                 set_pointer_focus(get_child_at(x, y));
97                 Container::pointer_motion(x, y);
98         }
99 }
100
101 void Panel::pointer_leave()
102 {
103         Container::pointer_leave();
104         set_pointer_focus(0);
105 }
106
107 void Panel::key_press(unsigned key, unsigned mod, wchar_t ch)
108 {
109         if(input_focus)
110                 input_focus->key_press(key, mod, ch);
111 }
112
113 void Panel::key_release(unsigned key, unsigned mod)
114 {
115         if(input_focus)
116                 input_focus->key_release(key, mod);
117 }
118
119 void Panel::focus_out()
120 {
121         set_input_focus(0);
122 }
123
124 void Panel::render_special(const Part &part) const
125 {
126         if(part.get_name()=="children")
127         {
128                 for(list<Container::Child *>::const_iterator i=children.begin(); i!=children.end(); ++i)
129                         if((*i)->widget->is_visible())
130                                 (*i)->widget->render();
131         }
132 }
133
134 Panel::Child *Panel::create_child(Widget *wdg)
135 {
136         return new Child(*this, wdg);
137 }
138
139 void Panel::set_pointer_focus(Widget *wdg)
140 {
141         if(wdg!=pointer_focus)
142         {
143                 if(pointer_focus)
144                         pointer_focus->pointer_leave();
145
146                 pointer_focus = wdg;
147
148                 if(pointer_focus)
149                         pointer_focus->pointer_enter();
150         }
151 }
152
153 void Panel::set_input_focus(Widget *wdg)
154 {
155         if(wdg!=input_focus)
156         {
157                 if(input_focus)
158                         input_focus->focus_out();
159
160                 input_focus = wdg;
161
162                 if(input_focus)
163                 {
164                         raise(*wdg);
165                         input_focus->focus_in();
166                 }
167         }
168 }
169
170
171 Panel::Loader::Loader(Panel &p, map<string, Widget *> &m):
172         Widget::Loader(p),
173         pnl(p),
174         wdg_map(m)
175 {
176         add("button",    &Loader::child<Button>);
177         add("dropdown",  &Loader::child<Dropdown>);
178         add("entry",     &Loader::child<Entry>);
179         add("hslider",   &Loader::child<HSlider>);
180         add("indicator", &Loader::child<Indicator>);
181         add("label",     &Loader::child<Label>);
182         add("list",      &Loader::child<List>);
183         add("panel",     &Loader::panel);
184         add("table",     &Loader::child<Table>);
185         add("toggle",    &Loader::child<Toggle>);
186         add("vslider",   &Loader::child<VSlider>);
187 }
188
189 template<typename T>
190 void Panel::Loader::child(const string &n)
191 {
192         RefPtr<T> chl = new T();
193         load_sub(*chl);
194         pnl.add(*chl.get());
195         wdg_map[n] = chl.release();
196 }
197
198 void Panel::Loader::panel(const string &n)
199 {
200         RefPtr<Panel> p = new Panel();
201         load_sub(*p, wdg_map);
202         pnl.add(*p.get());
203         wdg_map[n] = p.release();
204 }
205
206
207 Panel::Child::Child(Panel &p, Widget *w):
208         Container::Child(p, w)
209 {
210         widget->signal_visibility_changed.connect(sigc::mem_fun(this, &Child::visibility_changed));
211         widget->signal_request_focus.connect(sigc::mem_fun(this, &Child::request_focus));
212         widget->signal_grab_pointer.connect(sigc::mem_fun(this, &Child::grab_pointer));
213         widget->signal_ungrab_pointer.connect(sigc::mem_fun(this, &Child::ungrab_pointer));
214 }
215
216 Panel::Child::~Child()
217 {
218         visibility_changed(false);
219 }
220
221 void Panel::Child::visibility_changed(bool v)
222 {
223         if(!v)
224         {
225                 Panel &panel = static_cast<Panel &>(container);
226                 if(widget==panel.pointer_focus)
227                         panel.set_pointer_focus(0);
228                 if(widget==panel.input_focus)
229                         panel.set_input_focus(0);
230         }
231 }
232
233 void Panel::Child::request_focus()
234 {
235         Panel &panel = static_cast<Panel &>(container);
236         panel.set_input_focus(widget);
237         if(panel.parent && panel.visible)
238                 panel.set_focus();
239 }
240
241 void Panel::Child::grab_pointer()
242 {
243         Panel &panel = static_cast<Panel &>(container);
244         if(!panel.pointer_grabbed)
245         {
246                 panel.set_pointer_focus(widget);
247                 panel.pointer_grabbed = true;
248                 panel.signal_grab_pointer.emit();
249         }
250 }
251
252 void Panel::Child::ungrab_pointer()
253 {
254         Panel &panel = static_cast<Panel &>(container);
255         if(panel.pointer_grabbed && panel.pointer_focus==widget)
256         {
257                 // XXX Should set to the widget under pointer
258                 panel.set_pointer_focus(0);
259                 panel.pointer_grabbed = false;
260                 panel.signal_ungrab_pointer.emit();
261         }
262 }
263
264 } // namespace GLtk
265 } // namespace Msp