1 //
2 // "$Id: Fl_Scrollbar.cxx 6042 2008-02-25 13:00:53Z matt $"
3 //
4 // Scroll bar widget for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
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_Scrollbar.H>
30 #include <FL/fl_draw.H>
31 #include <math.h>
32 #include "flstring.h"
33 
34 #define INITIALREPEAT .5
35 #define REPEAT .05
36 
increment_cb()37 void Fl_Scrollbar::increment_cb() {
38   int ls = maximum()>=minimum() ? linesize_ : -linesize_;
39   int i;
40   switch (pushed_) {
41   case 1:
42     i = -ls;
43     break;
44   default:
45     i =  ls;
46     break;
47   case 5:
48     i = -int((maximum()-minimum())*slider_size()/(1.0-slider_size())) + ls;
49     if (i > -ls) i = -ls;
50     break;
51   case 6:
52     i =  int((maximum()-minimum())*slider_size()/(1.0-slider_size())) - ls;
53     if (i < ls) i = ls;
54     break;
55   }
56   handle_drag(clamp(value() + i));
57 }
58 
timeout_cb(void * v)59 void Fl_Scrollbar::timeout_cb(void* v) {
60   Fl_Scrollbar* s = (Fl_Scrollbar*)v;
61   s->increment_cb();
62   Fl::add_timeout(REPEAT, timeout_cb, s);
63 }
64 
handle(int event)65 int Fl_Scrollbar::handle(int event) {
66   // area of scrollbar:
67   int area;
68   int X=x(); int Y=y(); int W=w(); int H=h();
69 
70   // adjust slider area to be inside the arrow buttons:
71   if (horizontal()) {
72     if (W >= 3*H) {X += H; W -= 2*H;}
73   } else {
74     if (H >= 3*W) {Y += W; H -= 2*W;}
75   }
76 
77   // which widget part is highlighted?
78   int relx;
79   int ww;
80   if (horizontal()) {
81     relx = Fl::event_x()-X;
82     ww = W;
83   } else {
84     relx = Fl::event_y()-Y;
85     ww = H;
86   }
87   if (relx < 0) area = 1;
88   else if (relx >= ww) area = 2;
89   else {
90     int S = int(slider_size()*ww+.5);
91     int T = (horizontal() ? H : W)/2+1;
92     if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4;
93     if (S < T) S = T;
94     double val =
95       (maximum()-minimum()) ? (value()-minimum())/(maximum()-minimum()) : 0.5;
96     int sliderx;
97     if (val >= 1.0) sliderx = ww-S;
98     else if (val <= 0.0) sliderx = 0;
99     else sliderx = int(val*(ww-S)+.5);
100     if (Fl::event_button() == FL_MIDDLE_MOUSE) area = 8;
101     else if (relx < sliderx) area = 5;
102     else if (relx >= sliderx+S) area = 6;
103     else area = 8;
104   }
105 
106   switch (event) {
107   case FL_ENTER:
108   case FL_LEAVE:
109     return 1;
110   case FL_RELEASE:
111       damage(FL_DAMAGE_ALL);
112     if (pushed_) {
113       Fl::remove_timeout(timeout_cb, this);
114       pushed_ = 0;
115     }
116     handle_release();
117     return 1;
118   case FL_PUSH:
119     if (pushed_) return 1;
120     if (area != 8) pushed_ = area;
121     if (pushed_) {
122       handle_push();
123       Fl::add_timeout(INITIALREPEAT, timeout_cb, this);
124       increment_cb();
125       damage(FL_DAMAGE_ALL);
126       return 1;
127     }
128     return Fl_Slider::handle(event, X,Y,W,H);
129   case FL_DRAG:
130     if (pushed_) return 1;
131     return Fl_Slider::handle(event, X,Y,W,H);
132   case FL_MOUSEWHEEL :
133     if (horizontal()) {
134       if (Fl::e_dx==0) return 0;
135       handle_drag(clamp(value() + linesize_ * Fl::e_dx));
136       return 1;
137     } else {
138       if (Fl::e_dy==0) return 0;
139       handle_drag(clamp(value() + linesize_ * Fl::e_dy));
140       return 1;
141     }
142   case FL_SHORTCUT:
143   case FL_KEYBOARD: {
144     int v = value();
145     int ls = maximum()>=minimum() ? linesize_ : -linesize_;
146     if (horizontal()) {
147       switch (Fl::event_key()) {
148       case FL_Left:
149 	v -= ls;
150 	break;
151       case FL_Right:
152 	v += ls;
153 	break;
154       default:
155 	return 0;
156       }
157     } else { // vertical
158       switch (Fl::event_key()) {
159       case FL_Up:
160 	v -= ls;
161 	break;
162       case FL_Down:
163 	v += ls;
164 	break;
165       case FL_Page_Up:
166 	if (slider_size() >= 1.0) return 0;
167 	v -= int((maximum()-minimum())*slider_size()/(1.0-slider_size()));
168 	v += ls;
169 	break;
170       case FL_Page_Down:
171 	if (slider_size() >= 1.0) return 0;
172 	v += int((maximum()-minimum())*slider_size()/(1.0-slider_size()));
173 	v -= ls;
174 	break;
175       case FL_Home:
176 	v = int(minimum());
177 	break;
178       case FL_End:
179 	v = int(maximum());
180 	break;
181       default:
182 	return 0;
183       }
184     }
185     v = int(clamp(v));
186     if (v != value()) {
187       Fl_Slider::value(v);
188       value_damage();
189       set_changed();
190       do_callback();
191     }
192     return 1;}
193   }
194   return 0;
195 }
196 
draw()197 void Fl_Scrollbar::draw() {
198   if (damage()&FL_DAMAGE_ALL) draw_box();
199   int X = x()+Fl::box_dx(box());
200   int Y = y()+Fl::box_dy(box());
201   int W = w()-Fl::box_dw(box());
202   int H = h()-Fl::box_dh(box());
203   if (horizontal()) {
204     if (W < 3*H) {Fl_Slider::draw(X,Y,W,H); return;}
205     Fl_Slider::draw(X+H,Y,W-2*H,H);
206     if (damage()&FL_DAMAGE_ALL) {
207       draw_box((pushed_==1) ? fl_down(slider()) : slider(),
208 	       X, Y, H, H, selection_color());
209       draw_box((pushed_==2) ? fl_down(slider()) : slider(),
210 	       X+W-H, Y, H, H, selection_color());
211       if (active_r())
212         fl_color(labelcolor());
213       else
214         fl_color(fl_inactive(labelcolor()));
215       int w1 = (H-4)/3; if (w1 < 1) w1 = 1;
216       int x1 = X+(H-w1-1)/2;
217       int yy1 = Y+(H-2*w1-1)/2;
218       if (Fl::scheme_ && !strcmp(Fl::scheme_, "gtk+")) {
219 	fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1-1, yy1+w1, x1+w1, yy1);
220 	x1 += (W-H);
221 	fl_polygon(x1, yy1, x1+1, yy1+w1, x1, yy1+2*w1, x1+w1, yy1+w1);
222       } else {
223 	fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1, yy1);
224 	x1 += (W-H);
225 	fl_polygon(x1, yy1, x1, yy1+2*w1, x1+w1, yy1+w1);
226       }
227     }
228   } else { // vertical
229     if (H < 3*W) {Fl_Slider::draw(X,Y,W,H); return;}
230     Fl_Slider::draw(X,Y+W,W,H-2*W);
231     if (damage()&FL_DAMAGE_ALL) {
232       draw_box((pushed_==1) ? fl_down(slider()) : slider(),
233 	       X, Y, W, W, selection_color());
234       draw_box((pushed_==2) ? fl_down(slider()) : slider(),
235 	       X, Y+H-W, W, W, selection_color());
236       if (active_r())
237         fl_color(labelcolor());
238       else
239         fl_color(fl_inactive(labelcolor()));
240       int w1 = (W-4)/3; if (w1 < 1) w1 = 1;
241       int x1 = X+(W-2*w1-1)/2;
242       int yy1 = Y+(W-w1-1)/2;
243       if (Fl::scheme_ && !strcmp(Fl::scheme_, "gtk+")) {
244 	fl_polygon(x1, yy1+w1, x1+w1, yy1+w1-1, x1+2*w1, yy1+w1, x1+w1, yy1);
245 	yy1 += H-W;
246 	fl_polygon(x1, yy1, x1+w1, yy1+1, x1+w1, yy1+w1);
247 	fl_polygon(x1+w1, yy1+1, x1+2*w1, yy1, x1+w1, yy1+w1);
248       } else {
249 	fl_polygon(x1, yy1+w1, x1+2*w1, yy1+w1, x1+w1, yy1);
250 	yy1 += H-W;
251 	fl_polygon(x1, yy1, x1+w1, yy1+w1, x1+2*w1, yy1);
252       }
253     }
254   }
255 }
256 
Fl_Scrollbar(int X,int Y,int W,int H,const char * L)257 Fl_Scrollbar::Fl_Scrollbar(int X, int Y, int W, int H, const char* L)
258   : Fl_Slider(X, Y, W, H, L)
259 {
260   box(FL_FLAT_BOX);
261   color(FL_DARK2);
262   slider(FL_UP_BOX);
263   linesize_ = 16;
264   pushed_ = 0;
265   step(1);
266 }
267 
~Fl_Scrollbar()268 Fl_Scrollbar::~Fl_Scrollbar()
269 {
270   if (pushed_)
271     Fl::remove_timeout(timeout_cb, this);
272 }
273 
274 
275 //
276 // End of "$Id: Fl_Scrollbar.cxx 6042 2008-02-25 13:00:53Z matt $".
277 //
278