1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /**
20 * \file scrollbar.c
21 *
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao
24 * All rights reserved.
25 *
26 * Scrollbar
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "include/forms.h"
34 #include "flinternal.h"
35 #include "private/pscrollbar.h"
36
37
38 static void get_geom( FL_OBJECT * );
39
40 static void attrib_change( FL_OBJECT * );
41
42
43 #define IsVThin( t ) ( t == FL_VERT_THIN_SCROLLBAR \
44 || t == FL_VERT_PLAIN_SCROLLBAR )
45 #define IsHThin( t ) ( t == FL_HOR_THIN_SCROLLBAR \
46 || t == FL_HOR_PLAIN_SCROLLBAR )
47 #define IsThin( t ) ( IsVThin( t ) || IsHThin( t ) )
48
49
50 /***************************************
51 ***************************************/
52
53 static int
handle_scrollbar(FL_OBJECT * obj,int event,FL_Coord mx FL_UNUSED_ARG,FL_Coord my FL_UNUSED_ARG,int key FL_UNUSED_ARG,void * ev FL_UNUSED_ARG)54 handle_scrollbar( FL_OBJECT * obj,
55 int event,
56 FL_Coord mx FL_UNUSED_ARG,
57 FL_Coord my FL_UNUSED_ARG,
58 int key FL_UNUSED_ARG,
59 void * ev FL_UNUSED_ARG )
60 {
61 switch ( event )
62 {
63 case FL_ATTRIB :
64 case FL_RESIZED :
65 obj->align = fl_to_outside_lalign( obj->align );
66 attrib_change( obj );
67 get_geom( obj );
68 break;
69
70 case FL_DRAW :
71 if ( IsThin( obj->type ) )
72 fl_draw_box( obj->boxtype, obj->x, obj->y, obj->w, obj->h,
73 obj->col1, obj->bw );
74 /* fall through */
75
76 case FL_DRAWLABEL :
77 fl_draw_object_label_outside( obj );
78 break;
79
80 case FL_FREEMEM :
81 /* children will take care of themselves */
82 fl_free( obj->spec );
83 break;
84 }
85
86 return FL_RETURN_NONE;
87 }
88
89 #define IS_HORIZ( o ) ( ( o )->type & FL_HOR_FLAG )
90
91
92 /***************************************
93 ***************************************/
94
95 static void
attrib_change(FL_OBJECT * obj)96 attrib_change( FL_OBJECT * obj )
97 {
98 FLI_SCROLLBAR_SPEC *sp = obj->spec;
99
100 sp->slider->col1 = obj->col1;
101 sp->slider->col2 = obj->col2;
102 sp->up->col1 = sp->down->col1 = obj->col1;
103 sp->up->col2 = sp->down->col2 = obj->col2;
104 sp->up->boxtype = sp->down->boxtype = sp->slider->boxtype = obj->boxtype;
105
106 fli_notify_object( sp->slider, FL_ATTRIB );
107 }
108
109
110 /***************************************
111 ***************************************/
112
113 static void
get_geom(FL_OBJECT * obj)114 get_geom( FL_OBJECT * obj )
115 {
116 FLI_SCROLLBAR_SPEC *sp = obj->spec;
117 FL_OBJECT *up = sp->up,
118 *down = sp->down,
119 *slider = sp->slider;
120 int x = obj->x,
121 y = obj->y,
122 w = obj->w,
123 h = obj->h;
124 int absbw = FL_abs( obj->bw );
125 int t = obj->type;
126
127 if ( IS_HORIZ( obj ) )
128 {
129 down->x = x;
130 up->x = x + w - h;
131 up->y = down->y = y;
132 down->h = up->h = h;
133 down->w = up->w = FL_min( w, h );
134
135 slider->x = x + h;
136 slider->y = y;
137 slider->h = h;
138
139 if ( ( slider->w = w - 2 * up->w ) < 0 )
140 {
141 slider->w = up->w / 3;
142 slider->x = x + up->w / 3;
143 }
144 }
145 else
146 {
147 up->x = down->x = x;
148 up->y = y;
149 up->w = down->w = w;
150 up->h = down->h = FL_min( w, h );
151
152 slider->x = x;
153 slider->y = y + up->h;
154 slider->w = w;
155
156 if ( ( slider->h = h - 2 * up->h ) < 0 )
157 {
158 slider->h = h / 3;
159 slider->y = y + up->h / 3;
160 }
161
162 down->y = y + h - down->h;
163 }
164
165 up->bw = obj->bw;
166 down->bw = obj->bw;
167 slider->bw = obj->bw;
168
169 if ( absbw > 2 )
170 absbw--;
171
172 if ( obj->bw > 0 )
173 up->bw = down->bw = absbw;
174 else
175 up->bw = down->bw = -absbw;
176
177 if ( IsThin( t ) )
178 {
179 absbw = IS_FLATBOX( obj->boxtype ) ? 1 : absbw;
180
181 up->boxtype = down->boxtype = FL_NO_BOX;
182 up->bw = down->bw = absbw;
183
184 /* Due to slider double buffering we have to be completely clear of
185 the scrollbar bounding box, otherwise the slider will wipe out the
186 scrollbars bounding box */
187
188 if ( IsVThin( t ) )
189 {
190 slider->x += absbw + 1;
191 slider->w -= 2 * absbw + 2;
192 slider->y -= absbw + ( absbw > 1 );
193 slider->h += 2 * absbw + ( absbw > 1 );
194 }
195 else
196 {
197 slider->y += absbw + 1;
198 slider->h -= 2 * absbw + 2;
199 slider->x -= absbw + ( absbw > 1 );
200 slider->w += 2 * absbw + ( absbw > 1 );
201 }
202 }
203
204 fli_notify_object( slider, FL_RESIZED );
205 }
206
207
208 /***************************************
209 * Callback for the slider in the scrollbar
210 ***************************************/
211
212 static void
slider_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)213 slider_cb( FL_OBJECT * obj,
214 long data FL_UNUSED_ARG )
215 {
216 FLI_SCROLLBAR_SPEC *sp = obj->parent->spec;
217
218 if ( obj->returned & FL_RETURN_END )
219 obj->parent->returned |= FL_RETURN_END;
220
221 if ( obj->parent->how_return & FL_RETURN_END_CHANGED
222 && obj->returned & FL_RETURN_END )
223 {
224 double nval = fl_get_slider_value( obj );
225
226 if ( nval != sp->old_val )
227 obj->parent->returned |= FL_RETURN_CHANGED;
228 sp->old_val = nval;
229 }
230 else if ( obj->returned & FL_RETURN_CHANGED )
231 obj->parent->returned |= FL_RETURN_CHANGED;
232 }
233
234
235 /***************************************
236 * Callback for the buttons of the scrollbar
237 ***************************************/
238
239 static void
button_cb(FL_OBJECT * obj,long data)240 button_cb( FL_OBJECT * obj,
241 long data )
242 {
243 FLI_SCROLLBAR_SPEC *sp = obj->parent->spec;
244 double ival = fl_get_slider_value( sp->slider ),
245 nval = ival,
246 slmax,
247 slmin;
248
249 /* Update the slider and get the new value */
250
251 if ( obj->returned == FL_RETURN_TRIGGERED )
252 obj->returned = FL_RETURN_END | FL_RETURN_CHANGED;
253
254 if ( obj->returned & FL_RETURN_CHANGED )
255 {
256 fl_get_slider_bounds( sp->slider, &slmin, &slmax );
257
258 if ( slmax > slmin )
259 nval = ival + data * sp->increment;
260 else
261 nval = ival - data * sp->increment;
262
263 fl_set_slider_value( sp->slider, nval );
264
265 nval = fl_get_slider_value( sp->slider );
266 }
267
268 if ( obj->returned & FL_RETURN_END )
269 obj->parent->returned |= FL_RETURN_END;
270
271 /* If we're supposed to return only on end and change check if the
272 slider value changed since interaction started, if we have to return
273 on everty change check if if it changed this time round */
274
275 if ( obj->parent->how_return & FL_RETURN_END_CHANGED
276 && obj->returned & FL_RETURN_END )
277 {
278 if ( nval != sp->old_val )
279 {
280 obj->parent->returned |= FL_RETURN_CHANGED;
281 sp->old_val = nval;
282 }
283 }
284 else if ( ival != nval )
285 obj->parent->returned |= FL_RETURN_CHANGED;
286 }
287
288
289 /***************************************
290 ***************************************/
291
292 FL_OBJECT *
fl_create_scrollbar(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * l)293 fl_create_scrollbar( int type,
294 FL_Coord x,
295 FL_Coord y,
296 FL_Coord w,
297 FL_Coord h,
298 const char * l )
299 {
300 FLI_SCROLLBAR_SPEC *sp;
301 FL_OBJECT *obj;
302
303 obj = fl_make_object( FL_SCROLLBAR, type, x, y, w, h, l, handle_scrollbar );
304
305 obj->spec = sp = fl_calloc( 1, sizeof *sp );
306 obj->col1 = FL_COL1;
307 obj->col2 = FL_COL1;
308 obj->align = FL_SCROLLBAR_ALIGN;
309 obj->set_return = fl_set_scrollbar_return;
310
311 if ( IsThin( type ) )
312 obj->boxtype = FL_DOWN_BOX;
313 else if ( type == FL_HOR_NICE_SCROLLBAR || type == FL_VERT_NICE_SCROLLBAR )
314 obj->boxtype = FL_FRAME_BOX;
315 else
316 obj->boxtype = FL_UP_BOX;
317
318 if ( IS_HORIZ( obj ) )
319 {
320 fl_set_object_resize( obj, FL_RESIZE_X );
321
322 sp->up = fl_create_scrollbutton( FL_TOUCH_BUTTON, 1, 1, 1, 1, "6" );
323 sp->down = fl_create_scrollbutton( FL_TOUCH_BUTTON, 1, 1, 1, 1, "4" );
324 fl_set_object_callback( sp->up, button_cb, 1 );
325 fl_set_object_callback( sp->down, button_cb, -1 );
326 fl_set_object_resize( sp->up, FL_RESIZE_NONE );
327 fl_set_object_resize( sp->down, FL_RESIZE_NONE );
328
329 if ( type == FL_HOR_SCROLLBAR )
330 sp->slider = fl_create_slider( FL_HOR_BROWSER_SLIDER2,
331 1, 1, 1, 1, "" );
332 else if ( type == FL_HOR_THIN_SCROLLBAR )
333 sp->slider = fl_create_slider( FL_HOR_THIN_SLIDER,
334 1, 1, 1, 1, "" );
335 else if ( type == FL_HOR_PLAIN_SCROLLBAR )
336 sp->slider = fl_create_slider( FL_HOR_BASIC_SLIDER,
337 1, 1, 1, 1, "" );
338 else if ( type == FL_HOR_NICE_SCROLLBAR )
339 sp->slider = fl_create_slider( FL_HOR_NICE_SLIDER2,
340 1, 1, 1, 1, "" );
341
342 fl_set_object_resize( sp->slider, FL_RESIZE_NONE );
343 }
344 else
345 {
346 fl_set_object_resize( obj, FL_RESIZE_Y );
347
348 sp->up = fl_create_scrollbutton( FL_TOUCH_BUTTON, 1, 1, 1, 1, "8" );
349 sp->down = fl_create_scrollbutton( FL_TOUCH_BUTTON, 1, 1, 1, 1, "2" );
350 fl_set_object_callback( sp->up, button_cb, -1 );
351 fl_set_object_callback( sp->down, button_cb, 1 );
352 fl_set_object_resize( sp->up, FL_RESIZE_NONE );
353 fl_set_object_resize( sp->down, FL_RESIZE_NONE );
354
355 if ( type == FL_VERT_SCROLLBAR )
356 sp->slider = fl_create_slider( FL_VERT_BROWSER_SLIDER2, 1, 1,
357 1, 1, "" );
358 else if ( type == FL_VERT_THIN_SCROLLBAR )
359 sp->slider = fl_create_slider( FL_VERT_THIN_SLIDER, 1, 1,
360 1, 1, "" );
361 else if ( type == FL_VERT_PLAIN_SCROLLBAR )
362 sp->slider = fl_create_slider( FL_VERT_BASIC_SLIDER, 1, 1,
363 1, 1, "" );
364 else if ( type == FL_VERT_NICE_SCROLLBAR )
365 sp->slider = fl_create_slider( FL_VERT_NICE_SLIDER2, 1, 1,
366 1, 1, "" );
367 else
368 M_err( "fl_create_scrollbar", "Unknown type %d", type );
369
370 fl_set_object_resize( sp->slider, FL_RESIZE_NONE );
371 }
372
373 sp->increment = 0.02;
374 fl_set_slider_increment( sp->slider, 5 * sp->increment, sp->increment );
375 fl_set_object_callback( sp->slider, slider_cb, 0 );
376 fl_set_slider_bounds( sp->slider, 0.0, 1.0 );
377
378 sp->old_val = fl_get_slider_value( sp->slider );
379
380 fl_add_child( obj, sp->slider );
381 fl_add_child( obj, sp->down );
382 fl_add_child( obj, sp->up );
383
384 /* In older versions scrollbars and browsers didn't return to the
385 application on e.g. fl_do_forms() but still a callback associated
386 with the object got called. To emulate the old behaviour we have
387 to set the return policy to default to FL_RETURN_NONE and only
388 change that to FL_RETURN_CHANGED when a callback is installed
389 (which is done in fl_set_object_callback()) */
390
391 #if ! USE_BWC_BS_HACK
392 fl_set_object_return( obj, FL_RETURN_CHANGED );
393 #else
394 fl_set_object_return( obj, FL_RETURN_NONE );
395 #endif
396
397 return obj;
398 }
399
400
401 /*
402 * User routines
403 */
404
405 #define ISSCROLLBAR( o ) ( ( o ) && ( o )->objclass == FL_SCROLLBAR )
406
407
408 /***************************************
409 ***************************************/
410
411 FL_OBJECT *
fl_add_scrollbar(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * l)412 fl_add_scrollbar( int type,
413 FL_Coord x,
414 FL_Coord y,
415 FL_Coord w,
416 FL_Coord h,
417 const char * l )
418 {
419 FL_OBJECT *obj = fl_create_scrollbar( type, x, y, w, h, l );
420
421 attrib_change( obj );
422 get_geom( obj );
423 fl_add_object( fl_current_form, obj );
424
425 return obj;
426 }
427
428
429 /***************************************
430 ***************************************/
431
432 double
fl_get_scrollbar_value(FL_OBJECT * obj)433 fl_get_scrollbar_value( FL_OBJECT * obj )
434 {
435 FLI_SCROLLBAR_SPEC *sp = obj->spec;
436
437 if ( ! ISSCROLLBAR( obj ) )
438 {
439 M_err( "fl_get_scrollbar_value", "%s not a scrollbar",
440 obj ? obj->label : "Object" );
441 return - HUGE_VAL;
442 }
443
444 return fl_get_slider_value( sp->slider );
445 }
446
447
448 /***************************************
449 ***************************************/
450
451 void
fl_set_scrollbar_value(FL_OBJECT * obj,double val)452 fl_set_scrollbar_value( FL_OBJECT * obj,
453 double val )
454 {
455 FLI_SCROLLBAR_SPEC *sp = obj->spec;
456
457 if ( ! ISSCROLLBAR( obj ) )
458 {
459 M_err( "fl_set_scrollbar_value", "%s not a scrollbar",
460 obj ? obj->label : "Object" );
461 return;
462 }
463
464 sp->old_val = val;
465 fl_set_slider_value( sp->slider, val );
466 }
467
468
469 /***************************************
470 * Sets the size of the knob of the scrollbar
471 * (the function name is a bit of misnomer)
472 ***************************************/
473
474 void
fl_set_scrollbar_size(FL_OBJECT * obj,double val)475 fl_set_scrollbar_size( FL_OBJECT * obj,
476 double val )
477 {
478 FLI_SCROLLBAR_SPEC *sp = obj->spec;
479
480 fl_set_slider_size( sp->slider, val );
481 get_geom( obj );
482 }
483
484
485 /***************************************
486 * Sets the size of the knob of the scrollbar
487 * (the function name is a bit of misnomer)
488 ***************************************/
489
490 double
fl_get_scrollbar_size(FL_OBJECT * obj)491 fl_get_scrollbar_size( FL_OBJECT * obj )
492 {
493 return fl_get_slider_size( ( ( FLI_SCROLLBAR_SPEC * ) obj->spec )->slider );
494 }
495
496
497 /***************************************
498 ***************************************/
499
500 void
fl_set_scrollbar_increment(FL_OBJECT * obj,double l,double r)501 fl_set_scrollbar_increment( FL_OBJECT * obj,
502 double l,
503 double r )
504 {
505 FLI_SCROLLBAR_SPEC *sp = obj->spec;
506
507 fl_set_slider_increment( sp->slider, l, r );
508 sp->increment = r;
509 }
510
511
512 /***************************************
513 ***************************************/
514
515 void
fl_get_scrollbar_increment(FL_OBJECT * obj,double * a,double * b)516 fl_get_scrollbar_increment( FL_OBJECT * obj,
517 double * a,
518 double * b )
519 {
520 FLI_SCROLLBAR_SPEC *sp = obj->spec;
521
522 fl_get_slider_increment( sp->slider, a, b );
523 }
524
525
526 /***************************************
527 ***************************************/
528
529 void
fl_set_scrollbar_bounds(FL_OBJECT * obj,double b1,double b2)530 fl_set_scrollbar_bounds( FL_OBJECT * obj,
531 double b1,
532 double b2 )
533 {
534 FLI_SCROLLBAR_SPEC *sp = obj->spec;
535
536 if ( ! ISSCROLLBAR( obj ) )
537 {
538 M_err( "fl_set_scrollbar_bounds", "%s not a scrollbar",
539 obj ? obj->label : "Object" );
540 return;
541 }
542
543 fl_set_slider_bounds( sp->slider, b1, b2 );
544 }
545
546
547 /***************************************
548 ***************************************/
549
550 void
fl_get_scrollbar_bounds(FL_OBJECT * obj,double * b1,double * b2)551 fl_get_scrollbar_bounds( FL_OBJECT * obj,
552 double * b1,
553 double * b2 )
554 {
555 FLI_SCROLLBAR_SPEC *sp = obj->spec;
556
557 fl_get_slider_bounds( sp->slider, b1, b2 );
558 }
559
560
561 /***************************************
562 * Sets under which conditions the object is to be returned to the
563 * application. This function should be regarded as for internal use
564 * only and fl_set_object_return() should be used instead (which then
565 * will call this function).
566 ***************************************/
567
568 void
fl_set_scrollbar_return(FL_OBJECT * obj,unsigned int when)569 fl_set_scrollbar_return( FL_OBJECT * obj,
570 unsigned int when )
571 {
572 FLI_SCROLLBAR_SPEC *sp = obj->spec;
573
574 if ( when & FL_RETURN_END_CHANGED )
575 when &= ~ ( FL_RETURN_NONE | FL_RETURN_CHANGED );
576
577 obj->how_return = when;
578
579 fl_set_object_return( sp->slider, FL_RETURN_ALWAYS );
580 fl_set_object_return( sp->up, FL_RETURN_ALWAYS );
581 fl_set_object_return( sp->down, FL_RETURN_ALWAYS );
582
583 /* We may need the value of the slider at this moment in the
584 callback function... */
585
586 sp->old_val = fl_get_slider_value( sp->slider );
587 }
588
589
590 /***************************************
591 ***************************************/
592
593 void
fl_set_scrollbar_step(FL_OBJECT * obj,double step)594 fl_set_scrollbar_step( FL_OBJECT * obj,
595 double step )
596 {
597 FLI_SCROLLBAR_SPEC *sp = obj->spec;
598
599 fl_set_slider_step( sp->slider, step );
600 }
601
602
603 /***************************************
604 ***************************************/
605
606 int
fl_get_scrollbar_repeat(FL_OBJECT * obj)607 fl_get_scrollbar_repeat( FL_OBJECT * obj )
608 {
609 return
610 fl_get_slider_repeat( ( ( FLI_SCROLLBAR_SPEC * ) obj->spec )->slider );
611 }
612
613
614 /***************************************
615 ***************************************/
616
617 void
fl_set_scrollbar_repeat(FL_OBJECT * obj,int millisec)618 fl_set_scrollbar_repeat( FL_OBJECT * obj,
619 int millisec )
620 {
621 fl_set_slider_repeat( ( ( FLI_SCROLLBAR_SPEC * ) obj->spec )->slider,
622 millisec );
623 }
624
625
626 /*
627 * Local variables:
628 * tab-width: 4
629 * indent-tabs-mode: nil
630 * End:
631 */
632