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