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