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