]> git.tdb.fi Git - libs/gltk.git/blob - source/root.cpp
Use a Camera rather than direct matrix manipulation
[libs/gltk.git] / source / root.cpp
1 #include <msp/gl/blend.h>
2 #include <msp/input/keys.h>
3 #include <msp/time/units.h>
4 #include <msp/time/utils.h>
5 #include "label.h"
6 #include "style.h"
7 #include "root.h"
8
9 namespace Msp {
10 namespace GLtk {
11
12 Root::Root(const Resources &r, Graphics::Window &window):
13         resources(r),
14         keyboard(new Input::Keyboard(window)),
15         mouse(new Input::Mouse(window)),
16         own_input(true)
17 {
18         init(&window);
19 }
20
21 Root::Root(const Resources &r, Graphics::Window *window, Input::Keyboard *k, Input::Mouse *m):
22         resources(r),
23         keyboard(k),
24         mouse(m),
25         own_input(false)
26 {
27         init(window);
28 }
29
30 void Root::init(Graphics::Window *window)
31 {
32         if(window)
33                 set_geometry(Geometry(0, 0, window->get_width(), window->get_height()));
34
35         lbl_tooltip = 0;
36         tooltip_target = 0;
37
38         camera.set_orthographic(geom.w, geom.h);
39         update_camera();
40
41         update_style();
42
43         if(mouse)
44         {
45                 mouse->signal_button_press.connect(sigc::mem_fun(this, &Root::button_press_event));
46                 mouse->signal_button_release.connect(sigc::mem_fun(this, &Root::button_release_event));
47                 mouse->signal_axis_motion.connect(sigc::mem_fun(this, &Root::axis_motion_event));
48         }
49
50         if(keyboard)
51         {
52                 keyboard->signal_button_press.connect(sigc::mem_fun(this, &Root::key_press_event));
53                 keyboard->signal_button_release.connect(sigc::mem_fun(this, &Root::key_release_event));
54                 keyboard->signal_character.connect(sigc::mem_fun(this, &Root::character_event));
55         }
56 }
57
58 Root::~Root()
59 {
60         if(own_input)
61         {
62                 delete keyboard;
63                 delete mouse;
64         }
65 }
66
67 void Root::tick()
68 {
69         if(tooltip_timeout && Time::now()>tooltip_timeout)
70         {
71                 std::string tip;
72                 if(Widget *wdg = get_descendant_at(pointer_x, pointer_y))
73                 {
74                         tip = wdg->get_tooltip();
75                         tooltip_target = wdg;
76                 }
77                 else
78                 {
79                         tip = signal_tooltip.emit(pointer_x, pointer_y);
80                         tooltip_target = this;
81                 }
82
83                 if(!tip.empty())
84                 {
85                         if(!lbl_tooltip)
86                         {
87                                 lbl_tooltip = new Label;
88                                 add(*lbl_tooltip);
89                                 lbl_tooltip->set_style("tooltip");
90                         }
91
92                         lbl_tooltip->set_text(tip);
93                         lbl_tooltip->autosize();
94                         const Geometry &tip_geom = lbl_tooltip->get_geometry();
95                         unsigned x = pointer_x+10;
96                         unsigned y = pointer_y-10-lbl_tooltip->get_geometry().h;
97                         if(x+tip_geom.w>geom.w)
98                         {
99                                 if(pointer_x>static_cast<int>(tip_geom.w+2))
100                                         x = pointer_x-2-tip_geom.w;
101                                 else
102                                         x = geom.w-tip_geom.w;
103                         }
104                         lbl_tooltip->set_position(x, y);
105                         raise(*lbl_tooltip);
106                         lbl_tooltip->set_visible(true);
107                 }
108
109                 tooltip_timeout = Time::TimeStamp();
110         }
111 }
112
113 void Root::render() const
114 {
115         GL::Bind bind_blend(GL::Blend::alpha());
116
117         GL::Renderer renderer(&camera);
118         Widget::render(renderer);
119 }
120
121 bool Root::button_press_event(unsigned btn)
122 {
123         if(visible)
124         {
125                 Widget *old_focus = pointer_focus;
126
127                 int x, y;
128                 get_pointer(x, y);
129                 button_press(x, y, btn);
130
131                 if(pointer_focus || old_focus)
132                         return true;
133         }
134
135         return false;
136 }
137
138 bool Root::button_release_event(unsigned btn)
139 {
140         if(visible)
141         {
142                 Widget *old_focus = pointer_focus;
143
144                 int x, y;
145                 get_pointer(x, y);
146                 button_release(x, y, btn);
147
148                 if(pointer_focus || old_focus)
149                         return true;
150         }
151
152         return false;
153 }
154
155 bool Root::axis_motion_event(unsigned, float, float)
156 {
157         if(visible)
158         {
159                 int x, y;
160                 get_pointer(x, y);
161                 pointer_motion(x, y);
162
163                 if(!tooltip_target)
164                 {
165                         pointer_x = x;
166                         pointer_y = y;
167                         tooltip_timeout = Time::now()+700*Time::msec;
168                 }
169                 else if(get_descendant_at(x, y)!=tooltip_target)
170                 {
171                         if(lbl_tooltip)
172                                 lbl_tooltip->set_visible(false);
173                         tooltip_target = 0;
174                 }
175
176                 if(pointer_focus)
177                         return true;
178         }
179
180         return false;
181 }
182
183 bool Root::key_press_event(unsigned key)
184 {
185         // XXX Modifiers
186         if(visible)
187         {
188                 Widget *old_focus = input_focus;
189
190                 key_press(key, 0);
191
192                 if(input_focus || old_focus)
193                         return true;
194         }
195
196         return false;
197 }
198
199 bool Root::key_release_event(unsigned key)
200 {
201         if(visible)
202         {
203                 Widget *old_focus = input_focus;
204
205                 key_release(key, 0);
206
207                 if(input_focus || old_focus)
208                         return true;
209         }
210
211         return false;
212 }
213
214 bool Root::character_event(StringCodec::unichar ch)
215 {
216         if(visible)
217         {
218                 Widget *old_focus = input_focus;
219
220                 character(ch);
221
222                 if(input_focus || old_focus)
223                         return true;
224         }
225
226         return false;
227 }
228
229 void Root::get_pointer(int &x, int &y)
230 {
231         x = (mouse->get_axis_value(0)*0.5+0.5)*geom.w;
232         y = (mouse->get_axis_value(1)*0.5+0.5)*geom.h;
233 }
234
235 void Root::update_camera()
236 {
237         camera.set_position(GL::Vector3(geom.w/2.0f, geom.h/2.0f, geom.h/2.0f));
238         camera.set_depth_clip(geom.h*0.1f, geom.h*0.9f);
239         camera.set_orthographic(geom.w, geom.h);
240 }
241
242 void Root::on_geometry_change()
243 {
244         Panel::on_geometry_change();
245         update_camera();
246 }
247
248 void Root::on_child_added(Widget &wdg)
249 {
250         if(&wdg!=lbl_tooltip)
251                 Panel::on_child_added(wdg);
252 }
253
254 } // namespace GLtk
255 } // namespace Msp