I don't think I'll bother any more with this, so I'll just make it start
[ld42_outofspace] / src / goatkit / slider.cc
1 /*
2 GoatKit - a themable/animated widget toolkit for games
3 Copyright (C) 2014  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <math.h>
20 #include "slider.h"
21 #include "screen.h"
22
23 namespace goatkit {
24
25 struct SliderImpl {
26         float value, prev_value;
27         float range_min, range_max;
28         float padding;
29         float step;
30         bool dragging;
31         bool cont_change;
32 };
33
34 static float remap(float val, float inlow, float inhigh, float outlow, float outhigh);
35
36 Slider::Slider()
37 {
38         slider = new SliderImpl;
39         slider->value = slider->prev_value = 0.0f;
40         slider->dragging = false;
41         slider->cont_change = true;
42
43         slider->range_min = 0.0;
44         slider->range_max = 1.0;
45         slider->step = 0.0;
46
47         slider->padding = -1.0;
48 }
49
50 Slider::~Slider()
51 {
52         delete slider;
53 }
54
55 const char *Slider::get_type_name() const
56 {
57         return "slider";
58 }
59
60 void Slider::set_value(float val)
61 {
62         slider->value = remap(val, slider->range_min, slider->range_max, 0, 1);
63 }
64
65 float Slider::get_value() const
66 {
67         return remap(slider->value, 0, 1, slider->range_min, slider->range_max);
68 }
69
70 void Slider::set_value_norm(float val)
71 {
72         slider->value = val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
73 }
74
75 float Slider::get_value_norm() const
76 {
77         return slider->value;
78 }
79
80 void Slider::set_padding(float pad)
81 {
82         slider->padding = pad;
83 }
84
85 float Slider::get_padding() const
86 {
87         if(slider->padding < 0.0) {
88                 BBox box = get_box();
89                 return (box.bmax.y - box.bmin.y) * 0.25;
90         }
91         return slider->padding;
92 }
93
94 void Slider::set_continuous_change(bool cont)
95 {
96         slider->cont_change = cont;
97 }
98
99 bool Slider::get_continuous_change() const
100 {
101         return slider->cont_change;
102 }
103
104 void Slider::set_range(float min, float max)
105 {
106         slider->range_min = min;
107         slider->range_max = max;
108 }
109
110 float Slider::get_range_min() const
111 {
112         return slider->range_min;
113 }
114
115 float Slider::get_range_max() const
116 {
117         return slider->range_max;
118 }
119
120 void Slider::set_step(float step)
121 {
122         slider->step = step;
123 }
124
125 float Slider::get_step() const
126 {
127         return slider->step;
128 }
129
130 void Slider::on_mouse_button(const ButtonEvent &ev)
131 {
132         if(ev.button == 0) {
133                 Screen *scr = get_screen();
134
135                 slider->dragging = ev.press;
136                 if(ev.press) {
137                         if(scr) scr->grab_mouse(this);
138                 } else {
139                         if(scr) scr->grab_mouse(0);
140
141                         // on release, if the value has changed send the appropriate event
142                         if(slider->prev_value != slider->value) {
143                                 Event ev;
144                                 ev.type = EV_CHANGE;
145                                 handle_event(ev);
146                                 slider->prev_value = slider->value;
147                         }
148                 }
149         }
150 }
151
152 #define ROUND(x)        floor((x) + 0.5)
153
154 void Slider::on_mouse_motion(const MotionEvent &ev)
155 {
156         if(!slider->dragging) {
157                 return;
158         }
159
160         BBox box = get_box();
161
162         float padding = get_padding();
163         float start = box.bmin.x + padding;
164         float end = box.bmax.x - padding;
165         float new_val = (ev.pos.x - start) / (end - start);
166
167         // if we have a non-zero step, snap to the nearest value
168         if(slider->step > 0.0) {
169                 float range = slider->range_max - slider->range_min;
170                 float st = slider->step / range;
171
172                 new_val = ROUND(new_val / st) * st;
173         }
174
175         if(new_val < 0.0) new_val = 0.0;
176         if(new_val > 1.0) new_val = 1.0;
177
178         if(new_val != slider->value) {
179                 slider->value = new_val;
180                 if(slider->cont_change) {
181                         Event cev;
182                         cev.type = EV_CHANGE;
183                         handle_event(cev);
184                 }
185         }
186 }
187
188 static float remap(float val, float inlow, float inhigh, float outlow, float outhigh)
189 {
190         float t = (val - inlow) / (inhigh - inlow);
191         if(t < 0.0) t = 0.0;
192         if(t > 1.0) t = 1.0;
193         return t * (outhigh - outlow) + outlow;
194 }
195
196 }       // namespace goatkit