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