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 positioner.c
21 *
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao and Mark Overmars
24 * All rights reserved.
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "include/forms.h"
32 #include "flinternal.h"
33 #include "private/ppositioner.h"
34
35 #include <sys/types.h>
36 #include <stdlib.h>
37
38
39 /* The special information for positioners.
40 * ymin is the value at the bottom and ymax is the value at the top */
41
42
43 /***************************************
44 * Performs linear interpolation
45 ***************************************/
46
47 static double
flinear(double val,double smin,double smax,double gmin,double gmax)48 flinear( double val,
49 double smin,
50 double smax,
51 double gmin,
52 double gmax )
53 {
54 if ( smin == smax )
55 return gmax;
56
57 return gmin + ( gmax - gmin ) * ( val - smin ) / ( smax - smin );
58 }
59
60
61 /***************************************
62 ***************************************/
63
64 static void
handle_background(FL_OBJECT * obj,int clear_pms)65 handle_background( FL_OBJECT * obj,
66 int clear_pms )
67 {
68 FLI_POSITIONER_SPEC *sp = obj->spec;
69
70 FL_Coord absbw = FL_abs( obj->bw );
71 FL_Coord x0 = obj->x + absbw + 1,
72 y0 = obj->y + absbw + 1;
73 FL_Coord w = obj->w - 2 * absbw - 2,
74 h = obj->h - 2 * absbw - 2;
75 FL_Coord xo = FL_crnd( flinear( sp->lxval, sp->xmin, sp->xmax,
76 x0, x0 + w - 1 ) ),
77 yo = FL_crnd( flinear( sp->lyval, sp->ymin, sp->ymax,
78 y0 + h - 1, y0 ) ),
79 xn = FL_crnd( flinear( sp->xval, sp->xmin, sp->xmax,
80 x0, x0 + w - 1 ) ),
81 yn = FL_crnd( flinear( sp->yval, sp->ymin, sp->ymax,
82 y0 + h - 1, y0 ) );
83
84 /* Return immediatel if we're called for an invisible positioner or
85 there's no window yet. */
86
87 if ( obj->type == FL_INVISIBLE_POSITIONER || FL_ObjWin( obj ) == None )
88 return;
89
90 /* If no GC has been created do it now. */
91
92 if ( sp->copy_gc == None )
93 sp->copy_gc = XCreateGC( flx->display, FL_ObjWin( obj ), 0, NULL );
94
95 /* If there's a pixmap with what was under the horizontal line copy from
96 it to the window to restore what's under the line. If we're asked to
97 delete the pixmap also do so. */
98
99 if ( sp->xpm != None )
100 {
101 XCopyArea( flx->display, sp->xpm, FL_ObjWin( obj ), sp->copy_gc,
102 0, 0, w, 1, x0, yo );
103
104 if ( clear_pms )
105 {
106 XFreePixmap( flx->display, sp->xpm );
107 sp->xpm = None;
108 }
109 }
110
111 /* Same for vertical line... */
112
113 if ( sp->ypm != None )
114 {
115 XCopyArea( flx->display, sp->ypm, FL_ObjWin( obj ), sp->copy_gc,
116 0, 0, 1, h, xo, y0 );
117
118 if ( clear_pms )
119 {
120 XFreePixmap( flx->display, sp->ypm );
121 sp->ypm = None;
122 }
123 }
124
125 /* If we're not asked to delete the pixmap for storing what's under the
126 horizontal line to be drawn safe the background, if necessary first
127 creating new pixmaps for that. */
128
129 if ( ! clear_pms )
130 {
131 if ( sp->xpm == None )
132 sp->xpm = XCreatePixmap( flx->display, FL_ObjWin( obj ),
133 w, 1, fl_get_visual_depth( ) );
134
135 if ( sp->ypm == None )
136 sp->ypm = XCreatePixmap( flx->display, FL_ObjWin( obj ),
137 1, h, fl_get_visual_depth( ) );
138
139 XCopyArea( flx->display, FL_ObjWin( obj ), sp->xpm, sp->copy_gc,
140 x0, yn, w, 1, 0, 0 );
141 XCopyArea( flx->display, FL_ObjWin( obj ), sp->ypm, sp->copy_gc,
142 xn, y0, 1, h, 0, 0 );
143
144 sp->lxval = sp->xval;
145 sp->lyval = sp->yval;
146 }
147 }
148
149
150 /***************************************
151 ***************************************/
152
153 static void
draw_positioner(FL_OBJECT * obj)154 draw_positioner( FL_OBJECT * obj )
155 {
156 FLI_POSITIONER_SPEC *sp = obj->spec;
157 FL_Coord absbw = FL_abs( obj->bw );
158 FL_Coord x0 = obj->x + absbw + 1,
159 y0 = obj->y + absbw + 1;
160 FL_Coord w = obj->w - 2 * absbw - 2,
161 h = obj->h - 2 * absbw - 2;
162 FL_Coord x = FL_crnd( flinear( sp->xval, sp->xmin, sp->xmax,
163 x0, x0 + w - 1 ) ),
164 y = FL_crnd( flinear( sp->yval, sp->ymin, sp->ymax,
165 y0 + h - 1, y0 ) );
166
167 if ( FL_ObjWin( obj ) == None )
168 return;
169
170 if ( ! sp->partial )
171 {
172 if ( obj->type != FL_OVERLAY_POSITIONER )
173 fl_draw_box( obj->boxtype, obj->x, obj->y, obj->w, obj->h,
174 obj->col1, obj->bw );
175 fl_draw_object_label_outside( obj );
176 }
177
178 handle_background( obj, 0 );
179
180 if ( x > x0 + 1 )
181 fl_diagline( x0, y, x - x0 - 1, 1, obj->col2 );
182 if ( w > x - x0 + 2 )
183 fl_diagline( x + 2, y, w - x + x0 - 2, 1, obj->col2 );
184
185 if ( y > y0 + 1 )
186 fl_diagline( x, y0, 1, y - y0 - 1, obj->col2 );
187 if ( h > y - y0 + 2 )
188 fl_diagline( x, y + 2, 1, h - y + y0 - 2, obj->col2 );
189 }
190
191
192 /***************************************
193 * Handle a mouse position change
194 ***************************************/
195
196 static int
handle_mouse(FL_OBJECT * obj,FL_Coord mx,FL_Coord my)197 handle_mouse( FL_OBJECT * obj,
198 FL_Coord mx,
199 FL_Coord my )
200 {
201 FLI_POSITIONER_SPEC * sp = obj->spec;
202 FL_Coord absbw = FL_abs( obj->bw );
203 FL_Coord x1 = obj->x + absbw + 1,
204 y1 = obj->y + absbw + 1;
205 FL_Coord w1 = obj->w - 2 * absbw - 2,
206 h1 = obj->h - 2 * absbw - 2;
207 double oldx = sp->xval,
208 oldy = sp->yval;
209 double x, y;
210
211 x = flinear( mx, x1, x1 + w1 - 1.0, sp->xmin, sp->xmax );
212 y = flinear( my, y1 + h1 - 1.0, y1, sp->ymin, sp->ymax );
213
214 /* Make sure the position is within bounds */
215
216 if ( ! sp->validator )
217 {
218 if ( sp->xstep != 0.0 )
219 x = FL_nlong( x / sp->xstep ) * sp->xstep;
220 if ( sp->ystep != 0.0 )
221 y = FL_nlong( y / sp->ystep ) * sp->ystep;
222
223 x = fli_clamp( x, sp->xmin, sp->xmax );
224 y = fli_clamp( y, sp->ymin, sp->ymax );
225 }
226 else
227 {
228 double x_repl,
229 y_repl;
230 int ret = sp->validator( obj, x, y, &x_repl, &y_repl );
231
232 if ( ret == FL_POSITIONER_INVALID )
233 return FL_RETURN_NONE;
234 else if ( ret == FL_POSITIONER_REPLACED )
235 {
236 x = x_repl;
237 y = y_repl;
238 }
239 }
240
241 sp->xval = x;
242 sp->yval = y;
243
244 if ( sp->xval != oldx || sp->yval != oldy )
245 {
246 sp->partial = 1;
247 fl_redraw_object( obj );
248
249 if ( ! ( obj->how_return & FL_RETURN_END_CHANGED ) )
250 return FL_RETURN_CHANGED;
251 }
252
253 return FL_RETURN_NONE;
254 }
255
256
257 /***************************************
258 * Handles an event
259 ***************************************/
260
261 static int
handle_positioner(FL_OBJECT * obj,int event,FL_Coord mx,FL_Coord my,int key FL_UNUSED_ARG,void * ev FL_UNUSED_ARG)262 handle_positioner( FL_OBJECT * obj,
263 int event,
264 FL_Coord mx,
265 FL_Coord my,
266 int key FL_UNUSED_ARG,
267 void * ev FL_UNUSED_ARG )
268 {
269 FLI_POSITIONER_SPEC *sp = obj->spec;
270 int ret = FL_RETURN_NONE;
271 static int is_in = 0;
272
273 switch ( event )
274 {
275 case FL_ATTRIB :
276 obj->align = fl_to_outside_lalign( obj->align );
277 handle_background( obj, 1 );
278 break;
279
280 case FL_DRAW:
281 if ( obj->type != FL_INVISIBLE_POSITIONER )
282 draw_positioner( obj );
283 sp->partial = 0;
284 break;
285
286 case FL_DRAWLABEL:
287 fl_draw_object_label_outside( obj );
288 break;
289
290 case FL_PUSH:
291 if ( key < FL_MBUTTON1
292 || key > FL_MBUTTON5
293 || ! sp->react_to[ key - 1 ] )
294 {
295 fli_int.pushobj = NULL;
296 break;
297 }
298
299 sp->mousebut = key;
300 sp->old_x = sp->xval;
301 sp->old_y = sp->yval;
302 /* fall through */
303
304 case FL_MOTION:
305 if ( obj->type != FL_INVISIBLE_POSITIONER )
306 {
307 if ( is_in
308 && ( mx < obj->x || mx > obj->x + obj->w
309 || my < obj->y || my > obj->y + obj->h ) )
310 {
311 is_in = 0;
312 fl_reset_cursor( FL_ObjWin( obj ) );
313 }
314
315 if ( ! is_in
316 && mx >= obj->x && mx <= obj->x + obj->w
317 && my >= obj->y && my <= obj->y + obj->h )
318 {
319 fl_set_cursor( FL_ObjWin( obj ), FL_INVISIBLE_CURSOR );
320 is_in = 1;
321 }
322 }
323
324 ret = handle_mouse( obj, mx, my );
325 break;
326
327 case FL_RELEASE:
328 if ( sp->mousebut != key )
329 {
330 fli_int.pushobj = obj;
331 break;
332 }
333
334 if ( obj->type != FL_INVISIBLE_POSITIONER )
335 fl_reset_cursor( FL_ObjWin( obj ) );
336 ret = FL_RETURN_END;
337 if ( obj->how_return & FL_RETURN_END_CHANGED
338 && ( sp->xval != sp->old_x || sp->yval != sp->old_y ) )
339 ret |= FL_RETURN_CHANGED;
340 is_in = 0;
341 break;
342
343 case FL_FREEMEM:
344 if ( sp->copy_gc != None )
345 {
346 if ( obj->form )
347 handle_background( obj, 1 );
348 else
349 {
350 if ( sp->xpm != None )
351 XFreePixmap( flx->display, sp->xpm );
352 if ( sp->ypm != None )
353 XFreePixmap( flx->display, sp->ypm );
354 }
355 XFreeGC( flx->display, sp->copy_gc );
356 }
357
358 fl_free( obj->spec );
359 break;
360 }
361
362 return ret;
363 }
364
365
366 /***************************************
367 * Creates a posiioner object
368 ***************************************/
369
370 FL_OBJECT *
fl_create_positioner(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)371 fl_create_positioner( int type,
372 FL_Coord x,
373 FL_Coord y,
374 FL_Coord w,
375 FL_Coord h,
376 const char * label )
377 {
378 FL_OBJECT * obj;
379 FLI_POSITIONER_SPEC * sp;
380 int i;
381
382 obj = fl_make_object( FL_POSITIONER, type, x, y, w, h, label,
383 handle_positioner );
384 obj->boxtype = FL_POSITIONER_BOXTYPE;
385 obj->col1 = FL_POSITIONER_COL1;
386 obj->col2 = FL_POSITIONER_COL2;
387 obj->align = FL_POSITIONER_ALIGN;
388 obj->lcol = FL_POSITIONER_LCOL;
389
390 if ( obj->type == FL_OVERLAY_POSITIONER
391 || obj->type == FL_INVISIBLE_POSITIONER )
392 {
393 obj->bw = 0;
394 obj->boxtype = FL_NO_BOX;
395 }
396
397 obj->spec = sp = fl_calloc( 1, sizeof *sp );
398
399 sp->xmin = 0.0;
400 sp->ymin = 0.0;
401 sp->xmax = 1.0;
402 sp->ymax = 1.0;
403 sp->xval = 0.5;
404 sp->yval = 0.5;
405 sp->xpm = sp->ypm = None;
406 sp->copy_gc = None;
407 sp->validator = NULL;
408
409 /* Per default a positioner reacts to the left mouse button only */
410
411 sp->react_to[ 0 ] = 1;
412 for ( i = 1; i < 5; i++ )
413 sp->react_to[ i ] = 0;
414
415 fl_set_object_return( obj, FL_RETURN_CHANGED );
416
417 return obj;
418 }
419
420
421 /***************************************
422 * Adds a positioner object
423 ***************************************/
424
425 FL_OBJECT *
fl_add_positioner(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)426 fl_add_positioner( int type,
427 FL_Coord x,
428 FL_Coord y,
429 FL_Coord w,
430 FL_Coord h,
431 const char * label )
432 {
433 FL_OBJECT *ob = fl_create_positioner( type, x, y, w, h, label );
434
435 fl_add_object( fl_current_form, ob );
436 return ob;
437 }
438
439
440 /***************************************
441 ***************************************/
442
443 int
fl_set_positioner_values(FL_OBJECT * obj,double new_x,double new_y)444 fl_set_positioner_values( FL_OBJECT * obj,
445 double new_x,
446 double new_y )
447 {
448 FLI_POSITIONER_SPEC * sp = obj->spec;
449 int ret;
450 double x = new_x;
451 double y = new_y;
452
453 if ( ! sp->validator )
454 {
455 if ( sp->xstep != 0.0 )
456 x = FL_nlong( x / sp->xstep ) * sp->xstep;
457 x = fli_clamp( x, sp->xmin, sp->xmax );
458
459 if ( sp->ystep != 0.0 )
460 y = FL_nlong( y / sp->ystep ) * sp->ystep;
461 y = fli_clamp( y, sp->ymin, sp->ymax );
462
463 ret = x == new_x && y == new_y ?
464 FL_POSITIONER_VALID : FL_POSITIONER_REPLACED;
465 }
466 else
467 {
468 ret = sp->validator( obj, new_x, new_y, &x, &y );
469
470 if ( ret == FL_POSITIONER_INVALID )
471 return ret;
472 else if ( ret != FL_POSITIONER_REPLACED )
473 {
474 x = new_x;
475 y = new_y;
476 }
477 }
478
479 if ( sp->xval != x || sp->yval != y )
480 {
481 sp->xval = x;
482 sp->yval = y;
483 sp->partial = 1;
484
485 fl_redraw_object( obj );
486 }
487
488 return ret;
489 }
490
491
492 /***************************************
493 ***************************************/
494
495 int
fl_set_positioner_xvalue(FL_OBJECT * obj,double val)496 fl_set_positioner_xvalue( FL_OBJECT * obj,
497 double val)
498 {
499 FLI_POSITIONER_SPEC * sp = obj->spec;
500
501 return fl_set_positioner_values( obj, val, sp->yval );
502 }
503
504
505 /***************************************
506 ***************************************/
507
508 int
fl_set_positioner_yvalue(FL_OBJECT * obj,double val)509 fl_set_positioner_yvalue( FL_OBJECT * obj,
510 double val )
511 {
512 FLI_POSITIONER_SPEC * sp = obj->spec;
513
514 return fl_set_positioner_values( obj, sp->xval, val );
515 }
516
517
518 /***************************************
519 ***************************************/
520
521 void
fl_set_positioner_xbounds(FL_OBJECT * obj,double min,double max)522 fl_set_positioner_xbounds( FL_OBJECT * obj,
523 double min,
524 double max )
525 {
526 FLI_POSITIONER_SPEC * sp = obj->spec;
527
528 if ( min == max )
529 {
530 M_err( "fl_set_positioner_xbounds",
531 "Minimum and maximum value are identical" );
532 return;
533 }
534
535 if ( sp->xmin == min && sp->xmax == max )
536 return;
537
538 sp->xmin = min;
539 sp->xmax = max;
540
541 if ( ! sp->validator )
542 sp->xval = fli_clamp( sp->xval, sp->xmin, sp->xmax );
543 else
544 {
545 double x, y;
546
547 if ( sp->validator( obj, sp->xval, sp->yval, &x, &y )
548 == FL_POSITIONER_REPLACED )
549 {
550 sp->xval = x;
551 sp->yval = y;
552 }
553 }
554
555 fl_redraw_object( obj );
556 }
557
558
559 /***************************************
560 ***************************************/
561
562 void
fl_set_positioner_ybounds(FL_OBJECT * obj,double min,double max)563 fl_set_positioner_ybounds( FL_OBJECT * obj,
564 double min,
565 double max )
566 {
567 FLI_POSITIONER_SPEC * sp = obj->spec;
568
569 if ( min == max )
570 {
571 M_err( "fl_set_positioner_ybounds",
572 "Minimum and maximum value are identical" );
573 return;
574 }
575
576 if ( sp->ymin == min && sp->ymax == max )
577 return;
578
579 sp->ymin = min;
580 sp->ymax = max;
581
582 if ( ! sp->validator )
583 sp->yval = fli_clamp( sp->yval, sp->ymin, sp->ymax );
584 else
585 {
586 double x, y;
587
588 if ( sp->validator( obj, sp->xval, sp->yval, &x, &y )
589 == FL_POSITIONER_REPLACED )
590 {
591 sp->xval = x;
592 sp->yval = y;
593 }
594 }
595
596 fl_redraw_object( obj );
597 }
598
599
600 /***************************************
601 ***************************************/
602
603 double
fl_get_positioner_xvalue(FL_OBJECT * obj)604 fl_get_positioner_xvalue( FL_OBJECT * obj )
605 {
606 return ( ( FLI_POSITIONER_SPEC * ) obj->spec )->xval;
607 }
608
609
610 /***************************************
611 ***************************************/
612
613 double
fl_get_positioner_yvalue(FL_OBJECT * obj)614 fl_get_positioner_yvalue( FL_OBJECT * obj )
615 {
616 return ( ( FLI_POSITIONER_SPEC * ) obj->spec )->yval;
617 }
618
619
620 /***************************************
621 ***************************************/
622
623 void
fl_get_positioner_xbounds(FL_OBJECT * obj,double * min,double * max)624 fl_get_positioner_xbounds( FL_OBJECT * obj,
625 double * min,
626 double * max )
627 {
628 *min = ( ( FLI_POSITIONER_SPEC * ) obj->spec)->xmin;
629 *max = ( ( FLI_POSITIONER_SPEC * ) obj->spec)->xmax;
630 }
631
632 void
fl_get_positioner_ybounds(FL_OBJECT * obj,double * min,double * max)633 fl_get_positioner_ybounds( FL_OBJECT * obj,
634 double * min,
635 double * max)
636 {
637 *min = ( ( FLI_POSITIONER_SPEC * ) obj->spec)->ymin;
638 *max = ( ( FLI_POSITIONER_SPEC * ) obj->spec)->ymax;
639 }
640
641
642 /***************************************
643 * Sets the step size to which values are rounded.
644 ***************************************/
645
646 void
fl_set_positioner_xstep(FL_OBJECT * obj,double value)647 fl_set_positioner_xstep( FL_OBJECT * obj,
648 double value )
649 {
650 ( ( FLI_POSITIONER_SPEC * ) obj->spec )->xstep = value;
651 }
652
653
654 /***************************************
655 * Returns the step size to which values are rounded.
656 ***************************************/
657
658 double
fl_get_positioner_xstep(FL_OBJECT * obj)659 fl_get_positioner_xstep( FL_OBJECT * obj )
660 {
661 return ( ( FLI_POSITIONER_SPEC * ) obj->spec )->xstep;
662 }
663
664
665 /***************************************
666 * Sets the step size to which values are rounded.
667 ***************************************/
668
669 void
fl_set_positioner_ystep(FL_OBJECT * obj,double value)670 fl_set_positioner_ystep( FL_OBJECT * obj,
671 double value )
672 {
673 ( ( FLI_POSITIONER_SPEC * ) obj->spec )->ystep = value;
674 }
675
676
677 /***************************************
678 * Returns the step size to which values are rounded.
679 ***************************************/
680
681 double
fl_get_positioner_ystep(FL_OBJECT * obj)682 fl_get_positioner_ystep( FL_OBJECT * obj )
683 {
684 return ( ( FLI_POSITIONER_SPEC * ) obj->spec )->ystep;
685 }
686
687
688 /***************************************
689 * Sets under which conditions the object is to be returned to the
690 * application. This function should be regarded as deprecated and
691 * fl_set_object_return() should be used instead.
692 * Please note that this function doesn't work like the other
693 * object specific functions for setting the return policy!
694 ***************************************/
695
696 void
fl_set_positioner_return(FL_OBJECT * obj,unsigned int when)697 fl_set_positioner_return( FL_OBJECT * obj,
698 unsigned int when )
699 {
700 if ( when )
701 fl_set_object_return( obj, FL_RETURN_CHANGED );
702 else
703 fl_set_object_return( obj, FL_RETURN_END );
704 }
705
706
707 /***************************************
708 * Function allows to set up to which mouse
709 * buttons the positioner object will react.
710 ***************************************/
711
712 void
fl_set_positioner_mouse_buttons(FL_OBJECT * obj,unsigned int mouse_buttons)713 fl_set_positioner_mouse_buttons( FL_OBJECT * obj,
714 unsigned int mouse_buttons )
715 {
716 FLI_POSITIONER_SPEC *sp = obj->spec;
717 unsigned int i;
718
719 for ( i = 0; i < 5; i++, mouse_buttons >>= 1 )
720 sp->react_to[ i ] = mouse_buttons & 1;
721 }
722
723
724 /***************************************
725 * Function returns a value via 'mouse_buttons', indicating
726 * which mouse buttons the positioner object will react to.
727 ***************************************/
728
729 void
fl_get_positioner_mouse_buttons(FL_OBJECT * obj,unsigned int * mouse_buttons)730 fl_get_positioner_mouse_buttons( FL_OBJECT * obj,
731 unsigned int * mouse_buttons )
732 {
733 FLI_POSITIONER_SPEC *sp;
734 int i;
735 unsigned int k;
736
737 if ( ! obj )
738 {
739 M_err( "fl_get_positioner_mouse_buttons", "NULL object" );
740 return;
741 }
742
743 if ( ! mouse_buttons )
744 return;
745
746 sp = obj->spec;
747
748 *mouse_buttons = 0;
749 for ( i = 0, k = 1; i < 5; i++, k <<= 1 )
750 *mouse_buttons |= sp->react_to[ i ] ? k : 0;
751 }
752
753
754 /***************************************
755 * Returns the number of the last used mouse button.
756 * fl_mouse_button will also return the mouse number
757 ***************************************/
758
759 int
fl_get_positioner_numb(FL_OBJECT * obj)760 fl_get_positioner_numb( FL_OBJECT * obj )
761 {
762 return ( ( FLI_POSITIONER_SPEC * ) obj->spec )->mousebut;
763 }
764
765
766 /***************************************
767 * Allows to set a validator function for new positions
768 ***************************************/
769
770 FL_POSITIONER_VALIDATOR
fl_set_positioner_validator(FL_OBJECT * obj,FL_POSITIONER_VALIDATOR validator)771 fl_set_positioner_validator( FL_OBJECT * obj,
772 FL_POSITIONER_VALIDATOR validator )
773 {
774 FLI_POSITIONER_SPEC *sp = obj->spec;
775
776 FL_POSITIONER_VALIDATOR old_validator = sp->validator;
777
778 if ( ! validator )
779 {
780 if ( sp->xstep != 0.0 )
781 sp->xval = FL_nlong( sp->xval / sp->xstep ) * sp->xstep;
782
783 if ( sp->ystep != 0.0 )
784 sp->yval = FL_nlong( sp->yval / sp->ystep ) * sp->ystep;
785
786 sp->xval = fli_clamp( sp->xval, sp->xmin, sp->xmax );
787 sp->yval = fli_clamp( sp->yval, sp->ymin, sp->ymax );
788 }
789 else
790 {
791 int ret;
792 double x, y;
793
794 ret = validator( obj, sp->xval, sp->yval, &x, &y );
795
796 if ( ret == FL_POSITIONER_INVALID )
797 M_warn( "fl_set_positioner_validator",
798 "Current positioner values not within valid range" );
799 else if ( ret == FL_POSITIONER_REPLACED )
800 {
801 sp->xval = x;
802 sp->yval = y;
803 }
804 }
805
806 sp->validator = validator;
807 fl_redraw_object( obj );
808
809 return old_validator;
810 }
811
812
813 /***************************************
814 * Function to be called for overlay positioners before what it is on top
815 * of is changed: undraws the lines of the positioner - they will get
816 * redrawn once the object under the positioner has been redrawn.
817 ***************************************/
818
819 void
fl_reset_positioner(FL_OBJECT * obj)820 fl_reset_positioner( FL_OBJECT * obj )
821 {
822 if ( obj->type == FL_OVERLAY_POSITIONER )
823 handle_background( obj, 1 );
824 }
825
826
827 /*
828 * Local variables:
829 * tab-width: 4
830 * indent-tabs-mode: nil
831 * End:
832 */
833