blob: 341589b798627d49ad2b539ccfc4f41f069cf8e9 [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: Fl_Slider.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $"
3//
4// Slider widget for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2011 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28#include <FL/Fl.H>
29#include <FL/Fl_Slider.H>
30#include <FL/fl_draw.H>
31#include <math.h>
32#include "flstring.h"
33
34#if defined(FL_DLL) // really needed for c'tors for MS VC++ only
35#include <FL/Fl_Hor_Slider.H>
36#endif
37
38void Fl_Slider::_Fl_Slider() {
39 slider_size_ = 0;
40 slider_ = 0; // FL_UP_BOX;
41}
42
43/**
44 Creates a new Fl_Slider widget using the given position,
45 size, and label string. The default boxtype is FL_DOWN_BOX.
46*/
47Fl_Slider::Fl_Slider(int X, int Y, int W, int H, const char* L)
48: Fl_Valuator(X, Y, W, H, L) {
49 box(FL_DOWN_BOX);
50 _Fl_Slider();
51}
52
53/**
54 Creates a new Fl_Slider widget using the given box type, position,
55 size, and label string.
56*/
57Fl_Slider::Fl_Slider(uchar t, int X, int Y, int W, int H, const char* L)
58 : Fl_Valuator(X, Y, W, H, L) {
59 type(t);
60 box(t==FL_HOR_NICE_SLIDER || t==FL_VERT_NICE_SLIDER ?
61 FL_FLAT_BOX : FL_DOWN_BOX);
62 _Fl_Slider();
63}
64
65void Fl_Slider::slider_size(double v) {
66 if (v < 0) v = 0;
67 if (v > 1) v = 1;
68 if (slider_size_ != float(v)) {
69 slider_size_ = float(v);
70 damage(FL_DAMAGE_EXPOSE);
71 }
72}
73
74/**
75 Sets the minimum (a) and maximum (b) values for the valuator widget.
76 if at least one of the values is changed, a partial redraw is asked.
77*/
78void Fl_Slider::bounds(double a, double b) {
79 if (minimum() != a || maximum() != b) {
80 Fl_Valuator::bounds(a, b);
81 damage(FL_DAMAGE_EXPOSE);
82 }
83}
84
85/**
86 Sets the size and position of the sliding knob in the box.
87 \param[in] pos position of first line displayed
88 \param[in] size size of window in lines
89 \param[in] first number of first line
90 \param[in] total total number of lines
91 Returns Fl_Valuator::value(p)
92 */
93int Fl_Slider::scrollvalue(int pos, int size, int first, int total) {
94 step(1, 1);
95 if (pos+size > first+total) total = pos+size-first;
96 slider_size(size >= total ? 1.0 : double(size)/double(total));
97 bounds(first, total-size+first);
98 return value(pos);
99}
100
101// All slider interaction is done as though the slider ranges from
102// zero to one, and the left (bottom) edge of the slider is at the
103// given position. Since when the slider is all the way to the
104// right (top) the left (bottom) edge is not all the way over, a
105// position on the widget itself covers a wider range than 0-1,
106// actually it ranges from 0 to 1/(1-size).
107
108void Fl_Slider::draw_bg(int X, int Y, int W, int H) {
109 fl_push_clip(X, Y, W, H);
110 draw_box();
111 fl_pop_clip();
112
113 Fl_Color black = active_r() ? FL_FOREGROUND_COLOR : FL_INACTIVE_COLOR;
114 if (type() == FL_VERT_NICE_SLIDER) {
115 draw_box(FL_THIN_DOWN_BOX, X+W/2-2, Y, 4, H, black);
116 } else if (type() == FL_HOR_NICE_SLIDER) {
117 draw_box(FL_THIN_DOWN_BOX, X, Y+H/2-2, W, 4, black);
118 }
119}
120
121void Fl_Slider::draw(int X, int Y, int W, int H) {
122
123 double val;
124 if (minimum() == maximum())
125 val = 0.5;
126 else {
127 val = (value()-minimum())/(maximum()-minimum());
128 if (val > 1.0) val = 1.0;
129 else if (val < 0.0) val = 0.0;
130 }
131
132 int ww = (horizontal() ? W : H);
133 int xx, S;
134 if (type()==FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) {
135 S = int(val*ww+.5);
136 if (minimum()>maximum()) {S = ww-S; xx = ww-S;}
137 else xx = 0;
138 } else {
139 S = int(slider_size_*ww+.5);
140 int T = (horizontal() ? H : W)/2+1;
141 if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4;
142 if (S < T) S = T;
143 xx = int(val*(ww-S)+.5);
144 }
145 int xsl, ysl, wsl, hsl;
146 if (horizontal()) {
147 xsl = X+xx;
148 wsl = S;
149 ysl = Y;
150 hsl = H;
151 } else {
152 ysl = Y+xx;
153 hsl = S;
154 xsl = X;
155 wsl = W;
156 }
157
158 draw_bg(X, Y, W, H);
159
160 Fl_Boxtype box1 = slider();
161 if (!box1) {box1 = (Fl_Boxtype)(box()&-2); if (!box1) box1 = FL_UP_BOX;}
162 if (type() == FL_VERT_NICE_SLIDER) {
163 draw_box(box1, xsl, ysl, wsl, hsl, FL_GRAY);
164 int d = (hsl-4)/2;
165 draw_box(FL_THIN_DOWN_BOX, xsl+2, ysl+d, wsl-4, hsl-2*d,selection_color());
166 } else if (type() == FL_HOR_NICE_SLIDER) {
167 draw_box(box1, xsl, ysl, wsl, hsl, FL_GRAY);
168 int d = (wsl-4)/2;
169 draw_box(FL_THIN_DOWN_BOX, xsl+d, ysl+2, wsl-2*d, hsl-4,selection_color());
170 } else {
171 if (wsl>0 && hsl>0) draw_box(box1, xsl, ysl, wsl, hsl, selection_color());
172
173 if (type()!=FL_HOR_FILL_SLIDER && type() != FL_VERT_FILL_SLIDER &&
174 Fl::scheme_ && !strcmp(Fl::scheme_, "gtk+")) {
175 if (W>H && wsl>(hsl+8)) {
176 // Draw horizontal grippers
177 int yy, hh;
178 hh = hsl-8;
179 xx = xsl+(wsl-hsl-4)/2;
180 yy = ysl+3;
181
182 fl_color(fl_darker(selection_color()));
183 fl_line(xx, yy+hh, xx+hh, yy);
184 fl_line(xx+6, yy+hh, xx+hh+6, yy);
185 fl_line(xx+12, yy+hh, xx+hh+12, yy);
186
187 xx++;
188 fl_color(fl_lighter(selection_color()));
189 fl_line(xx, yy+hh, xx+hh, yy);
190 fl_line(xx+6, yy+hh, xx+hh+6, yy);
191 fl_line(xx+12, yy+hh, xx+hh+12, yy);
192 } else if (H>W && hsl>(wsl+8)) {
193 // Draw vertical grippers
194 int yy;
195 xx = xsl+4;
196 ww = wsl-8;
197 yy = ysl+(hsl-wsl-4)/2;
198
199 fl_color(fl_darker(selection_color()));
200 fl_line(xx, yy+ww, xx+ww, yy);
201 fl_line(xx, yy+ww+6, xx+ww, yy+6);
202 fl_line(xx, yy+ww+12, xx+ww, yy+12);
203
204 yy++;
205 fl_color(fl_lighter(selection_color()));
206 fl_line(xx, yy+ww, xx+ww, yy);
207 fl_line(xx, yy+ww+6, xx+ww, yy+6);
208 fl_line(xx, yy+ww+12, xx+ww, yy+12);
209 }
210 }
211 }
212
213 draw_label(xsl, ysl, wsl, hsl);
214 if (Fl::focus() == this) {
215 if (type() == FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) draw_focus();
216 else draw_focus(box1, xsl, ysl, wsl, hsl);
217 }
218}
219
220void Fl_Slider::draw() {
221 if (damage()&FL_DAMAGE_ALL) draw_box();
222 draw(x()+Fl::box_dx(box()),
223 y()+Fl::box_dy(box()),
224 w()-Fl::box_dw(box()),
225 h()-Fl::box_dh(box()));
226}
227
228int Fl_Slider::handle(int event, int X, int Y, int W, int H) {
229 // Fl_Widget_Tracker wp(this);
230 switch (event) {
231 case FL_PUSH: {
232 Fl_Widget_Tracker wp(this);
233 if (!Fl::event_inside(X, Y, W, H)) return 0;
234 handle_push();
235 if (wp.deleted()) return 1; }
236 // fall through ...
237 case FL_DRAG: {
238
239 double val;
240 if (minimum() == maximum())
241 val = 0.5;
242 else {
243 val = (value()-minimum())/(maximum()-minimum());
244 if (val > 1.0) val = 1.0;
245 else if (val < 0.0) val = 0.0;
246 }
247
248 int ww = (horizontal() ? W : H);
249 int mx = (horizontal() ? Fl::event_x()-X : Fl::event_y()-Y);
250 int S;
251 static int offcenter;
252
253 if (type() == FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) {
254
255 S = 0;
256 if (event == FL_PUSH) {
257 int xx = int(val*ww+.5);
258 offcenter = mx-xx;
259 if (offcenter < -10 || offcenter > 10) offcenter = 0;
260 else return 1;
261 }
262
263 } else {
264
265 S = int(slider_size_*ww+.5); if (S >= ww) return 0;
266 int T = (horizontal() ? H : W)/2+1;
267 if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4;
268 if (S < T) S = T;
269 if (event == FL_PUSH) {
270 int xx = int(val*(ww-S)+.5);
271 offcenter = mx-xx;
272 if (offcenter < 0) offcenter = 0;
273 else if (offcenter > S) offcenter = S;
274 else return 1;
275 }
276 }
277
278 int xx = mx-offcenter;
279 double v;
280 char tryAgain = 1;
281 while (tryAgain)
282 {
283 tryAgain = 0;
284 if (xx < 0) {
285 xx = 0;
286 offcenter = mx; if (offcenter < 0) offcenter = 0;
287 } else if (xx > (ww-S)) {
288 xx = ww-S;
289 offcenter = mx-xx; if (offcenter > S) offcenter = S;
290 }
291 v = round(xx*(maximum()-minimum())/(ww-S) + minimum());
292 // make sure a click outside the sliderbar moves it:
293 if (event == FL_PUSH && v == value()) {
294 offcenter = S/2;
295 event = FL_DRAG;
296 tryAgain = 1;
297 }
298 }
299 handle_drag(clamp(v));
300 } return 1;
301 case FL_RELEASE:
302 handle_release();
303 return 1;
304 case FL_KEYBOARD:
305 { Fl_Widget_Tracker wp(this);
306 switch (Fl::event_key()) {
307 case FL_Up:
308 if (horizontal()) return 0;
309 handle_push();
310 if (wp.deleted()) return 1;
311 handle_drag(clamp(increment(value(),-1)));
312 if (wp.deleted()) return 1;
313 handle_release();
314 return 1;
315 case FL_Down:
316 if (horizontal()) return 0;
317 handle_push();
318 if (wp.deleted()) return 1;
319 handle_drag(clamp(increment(value(),1)));
320 if (wp.deleted()) return 1;
321 handle_release();
322 return 1;
323 case FL_Left:
324 if (!horizontal()) return 0;
325 handle_push();
326 if (wp.deleted()) return 1;
327 handle_drag(clamp(increment(value(),-1)));
328 if (wp.deleted()) return 1;
329 handle_release();
330 return 1;
331 case FL_Right:
332 if (!horizontal()) return 0;
333 handle_push();
334 if (wp.deleted()) return 1;
335 handle_drag(clamp(increment(value(),1)));
336 if (wp.deleted()) return 1;
337 handle_release();
338 return 1;
339 default:
340 return 0;
341 }
342 }
343 // break not required because of switch...
344 case FL_FOCUS :
345 case FL_UNFOCUS :
346 if (Fl::visible_focus()) {
347 redraw();
348 return 1;
349 } else return 0;
350 case FL_ENTER :
351 case FL_LEAVE :
352 return 1;
353 default:
354 return 0;
355 }
356}
357
358int Fl_Slider::handle(int event) {
359 if (event == FL_PUSH && Fl::visible_focus()) {
360 Fl::focus(this);
361 redraw();
362 }
363
364 return handle(event,
365 x()+Fl::box_dx(box()),
366 y()+Fl::box_dy(box()),
367 w()-Fl::box_dw(box()),
368 h()-Fl::box_dh(box()));
369}
370
371/*
372 The following constructor must not be in the header file if we
373 build a shared object (DLL). Instead it is defined here to force
374 the constructor (and default destructor as well) to be defined
375 in the DLL and exported (STR #2632).
376
377 Note: if you the ctor here, do the same changes in the specific
378 header file as well. This redundant definition was chosen to enable
379 inline constructors in the header files (for static linking) as well
380 as the one here for dynamic linking (Windows DLL).
381*/
382
383#if defined(FL_DLL)
384
385Fl_Hor_Slider::Fl_Hor_Slider(int X,int Y,int W,int H,const char *l)
386 : Fl_Slider(X,Y,W,H,l) {type(FL_HOR_SLIDER);}
387
388#endif // FL_DLL
389
390//
391// End of "$Id: Fl_Slider.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $".
392//