1 /*
2 * slider.h
3 * DIN Is Noise is copyright (c) 2006-2021 Jagannathan Sampath
4 * For more information, please visit http://dinisnoise.org/
5 */
6 
7 
8 #ifndef __slider
9 #define __slider
10 
11 #include "widget.h"
12 #include "viewwin.h"
13 #include "utils.h"
14 #include "filled_button.h"
15 
16 #include <algorithm>
17 #include <vector>
18 
19 extern int mousex;
20 extern viewport view;
21 extern int lmb;
22 
23 template <typename S> struct after_slide_lis {
24 	virtual void slided (S& s) = 0;
25 };
26 
27 template <typename S> struct start_slide_lis {
28 	virtual void start_slide (S& s) = 0;
29 };
30 
31 template <typename T> struct values {
32 
33 	T low, high, delta, val;
34 	float amount;
35 
36 	values (T l = 0, T h = 1, T v = 0) {
37 		set_limits (l, h);
38 		*this = v;
39 	}
40 
Tvalues41 	operator T() {
42 		return ((T) val);
43 	}
44 
set_limitsvalues45 	void set_limits (T l, T h) {
46 		low = l;
47 		high = h;
48 		delta = high - low;
49 	}
50 
get_limitsvalues51 	void get_limits (T& l, T& h) {
52 		l = low;
53 		h = high;
54 	}
55 
operatorvalues56 	T operator() () const { return val; }
57 	values& operator= (const T& v) {
58 		val = v;
59 		clamp<T> (low, val, high);
60 		if (delta) amount = (val - low) * 1.0f / delta; else amount = 0;
61 		return *this;
62 	}
63 
set_amountvalues64 	void set_amount (float a) {
65 		amount = a;
66 		clamp<float> (0.0f, amount, 1.0f);
67 		val = (T) (low + delta * amount);
68 	}
69 
get_amountvalues70 	float get_amount () const { return amount; }
71 
72 };
73 
74 template <typename T> struct slider : widget, move_listener {
75 
76 	values<T> vx;
77 	int dx;
78 
79 	int sliding;
80 	int lmb_clicked;
81 
82 	change_listener<slider> *chgl;
83 	after_slide_lis<slider> *asl;
84 	start_slide_lis<slider> *ssl;
85 
86 	filled_button sizer;
87 	static const int spc = 10;
88 
89 	slider (int sv = 0, int w = 64, int h = 16) : widget (0, 0, w, h), vx (0, 0, 0), sliding(0), lmb_clicked(0) {
90 		chgl = 0;
91 		asl = 0;
92 		set_sizer_visible (sv);
93 	}
94 
set_sizer_visibleslider95 	void set_sizer_visible (int sv) {
96 		sizer.visible = sv;
97 		if (sizer.visible) {
98 			sizer.set_moveable (1);
99 			sizer.movlis = this;
100 		} else {
101 			sizer.set_moveable (0);
102 			sizer.movlis = 0;
103 		}
104 	}
105 
set_posslider106 	void set_pos (int x, int y) {
107 		widget::set_pos (x, y);
108 		sizer.set_pos (extents.right + spc, extents.bottom);
109 	}
110 
set_rightslider111 	void set_right (int r) {
112 		set_extents (extents.left, extents.bottom, r, extents.top);
113 		dx = vx.get_amount () * extents.width;
114 	}
115 
movedslider116 	void moved () {
117 		int mpx = mousex - movr.prevx;
118 		if (mpx) {
119 			sizer.set_pos (mousex, extents.bottom);
120 			int msx = mousex - spc;
121 			if (msx > extents.left) set_right (msx);
122 		}
123 	}
124 
handle_inputslider125 	int handle_input () {
126 
127 		widget::handle_input ();
128 
129 		if (sizer.visible && sizer.handle_input ()) return 1;
130 
131 		int ret = 0;
132 
133 		if (lmb) {
134 			if (lmb_clicked == 0) {
135 				if (sliding) {
136 					sliding = 0;
137 					if (asl) asl->slided (*this);
138 					defocus (this);
139 					ret = 1;
140 				} else {
141 					if (hover) {
142 						sliding = 1;
143 						if (ssl) ssl->start_slide (*this);
144 						widget::focus = this;
145 						ret = 1;
146 					}
147 				}
148 				lmb_clicked = 1;
149 			}
150 		} else {
151 			if (sliding) {
152 				int nu_dx = mousex - extents.left;
153 				clamp (0, nu_dx, extents.width);
154 				if (nu_dx != dx) {
155 					dx = nu_dx;
156 					vx.set_amount (dx * extents.width_1);
157 					if (chgl) chgl->changed (*this);
158 				}
159 			} else ret = 0;
160 			lmb_clicked = 0;
161 		}
162 
163 		return ret;
164 
165 	}
166 
drawslider167 	void draw () {
168 
169 		widget::draw ();
170 
171 		glEnable (GL_BLEND);
172 		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
173 
174 		const color& c = clr;
175 
176 		glColor4f (c.r, c.g, c.b, (GLfloat) 0.15f);
177 
178 		const box<int>& e = extents;
179 			glRecti (e.left, e.bottom, e.right, e.top);
180 
181 		glColor4f (c.r, c.g, c.b, 1);
182 			glRecti (e.left, e.bottom, e.left + dx, e.top);
183 
184 		glDisable (GL_BLEND);
185 
186 		if (sizer.visible) sizer.draw ();
187 
188 	}
189 
updateslider190 	void update () {
191 		float amount = vx.get_amount ();
192 		const box<int>& e = extents;
193 		dx = (int) (amount * e.width);
194 	}
195 
196 	void set_listener (change_listener<slider>* _chgl, start_slide_lis<slider>* _ssl = 0, after_slide_lis<slider>* _asl = 0) {
197 		chgl = _chgl;
198 		ssl = _ssl;
199 		asl = _asl;
200 	}
201 
operatorslider202 	T operator() () const {return vx (); }
203 
set_valslider204 	void set_val (const T& t) {
205 		vx = t;
206 		update ();
207 	}
208 
set_limitsslider209 	void set_limits (T l, T h) {
210 		vx = values<T> (l, h, vx());
211 		update ();
212 	}
213 
get_limitsslider214 	void get_limits (T& l, T& h) {
215 		vx.get_limits (l, h);
216 	}
217 };
218 
219 #define MAKE_SLIDER_LISTENER(name,var) struct name : change_listener< slider<float> > { void changed (slider<float>& s); }; name var;
220 #define SLIDER_CHANGED(scope,name) void scope::name::changed (slider<float>& s)
221 #define MAKE_AFTER_SLIDE_LISTENER(name,type,var) struct name : after_slide_lis< type > { void slided (type& s); }; name var;
222 #define SLIDED(scope,name,type) void scope::name::slided (type& s)
223 #define MAKE_START_SLIDE_LISTENER(name,type,var) struct name : start_slide_lis< type > { void start_slide (type& s); }; name var;
224 #define START_SLIDE(scope,name,type) void scope::name::start_slide (type& s)
225 
226 #endif
227