themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_Slider.cxx
blob862a0daeed726f79521579af02625d698fee4102
1 //
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.
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.
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.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
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"
34 #if defined(FL_DLL) // really needed for c'tors for MS VC++ only
35 #include <FL/Fl_Hor_Slider.H>
36 #endif
38 void Fl_Slider::_Fl_Slider() {
39 slider_size_ = 0;
40 slider_ = 0; // FL_UP_BOX;
43 /**
44 Creates a new Fl_Slider widget using the given position,
45 size, and label string. The default boxtype is FL_DOWN_BOX.
47 Fl_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();
53 /**
54 Creates a new Fl_Slider widget using the given box type, position,
55 size, and label string.
57 Fl_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();
65 void 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);
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.
78 void Fl_Slider::bounds(double a, double b) {
79 if (minimum() != a || maximum() != b) {
80 Fl_Valuator::bounds(a, b);
81 damage(FL_DAMAGE_EXPOSE);
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)
93 int 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);
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).
108 void 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();
113 Fl_Color black = active_r() ? FL_BLACK : 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);
121 void Fl_Slider::draw(int X, int Y, int W, int H) {
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;
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);
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;
158 draw_bg(X, Y, W, H);
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());
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;
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);
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;
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);
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);
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);
220 void 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()));
228 int 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: {
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;
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;
253 if (type() == FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) {
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;
263 } else {
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;
278 int xx = mx-offcenter;
279 double v;
280 char tryAgain = 1;
281 while (tryAgain)
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;
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;
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;
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 case FL_MOUSEWHEEL :
355 if ( this != Fl::belowmouse() )
356 return 0;
357 if (Fl::e_dy==0)
358 return 0;
360 const int steps = Fl::event_ctrl() ? 128 : 16;
362 const float step = fabs( maximum() - minimum() ) / (float)steps;
364 int dy = Fl::e_dy;
366 /* slider is in 'upside down' configuration, invert meaning of mousewheel */
367 if ( minimum() > maximum() )
368 dy = 0 - dy;
370 handle_drag(clamp(value() + step * dy));
371 return 1;
373 default:
374 return 0;
378 int Fl_Slider::handle(int event) {
379 if (event == FL_PUSH && Fl::visible_focus()) {
380 Fl::focus(this);
381 redraw();
384 return handle(event,
385 x()+Fl::box_dx(box()),
386 y()+Fl::box_dy(box()),
387 w()-Fl::box_dw(box()),
388 h()-Fl::box_dh(box()));
392 The following constructor must not be in the header file if we
393 build a shared object (DLL). Instead it is defined here to force
394 the constructor (and default destructor as well) to be defined
395 in the DLL and exported (STR #2632).
397 Note: if you the ctor here, do the same changes in the specific
398 header file as well. This redundant definition was chosen to enable
399 inline constructors in the header files (for static linking) as well
400 as the one here for dynamic linking (Windows DLL).
403 #if defined(FL_DLL)
405 Fl_Hor_Slider::Fl_Hor_Slider(int X,int Y,int W,int H,const char *l)
406 : Fl_Slider(X,Y,W,H,l) {type(FL_HOR_SLIDER);}
408 #endif // FL_DLL
411 // End of "$Id: Fl_Slider.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $".