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 menu.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  *  XForms Class FL_MENU.
27  *    call PopUp to handle the actual random access
28  *
29  *  possible optimization:
30  *   upon first creation of the popup, set extern_menu to the popup ID
31  *   and let popup manage all the modes/values from then on.
32  *
33  *  OR use the following to simplify code for extern pup
34  *    when extern_menu is used, gets all text and mode, then
35  *    all the code would be the same for extern and native menu.
36  */
37 
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41 
42 #include "include/forms.h"
43 #include "flinternal.h"
44 #include "private/pmenu.h"
45 
46 #include <string.h>
47 #include <stdlib.h>
48 #include <ctype.h>
49 
50 
51 #define ISPUP( sp )   ( ( sp )->extern_menu >= 0 )
52 
53 
54 /***************************************
55  * Returns the index into the array of items from the items menu ID
56  ***************************************/
57 
58 static int
val_to_index(FL_OBJECT * ob,int val)59 val_to_index( FL_OBJECT * ob,
60               int         val )
61 {
62     int i;
63     FLI_MENU_SPEC *sp = ob->spec;
64 
65     if ( ISPUP( sp ) )
66         return val;
67 
68     for ( i = 1; i <= sp->numitems; i++ )
69         if ( val == sp->mval[ i ] )
70             return i;
71 
72     return -1;
73 }
74 
75 
76 /***************************************
77  * Creates the menu and shows it. Returns the item selected.
78  ***************************************/
79 
80 static int
do_menu_low_level(FL_OBJECT * ob)81 do_menu_low_level( FL_OBJECT * ob )
82 {
83     int popup_id,
84         i,
85         val,
86         k;
87     FLI_MENU_SPEC *sp = ob->spec;
88 
89     /* The number of items can be 0 only if the menu is an external popup */
90 
91     if ( sp->numitems == 0 && ! ISPUP( sp ) )
92         return 0;
93 
94     /* If it's an external popup let the xpopup code deal with everything */
95 
96     if ( ISPUP( sp ) )
97     {
98         if ( ob->label && *ob->label && ob->type != FL_PULLDOWN_MENU )
99             fl_setpup_title( sp->extern_menu, ob->label );
100 
101         if ( ( val = fl_dopup( sp->extern_menu ) ) > 0 )
102             sp->val = val;
103 
104         return val;
105     }
106 
107     /* Create a new popup */
108 
109     popup_id = fl_newpup( FL_ObjWin( ob ) );
110 
111     if ( ob->type != FL_PULLDOWN_MENU && ! sp->no_title )
112         fl_setpup_title( popup_id, ob->label );
113     else
114         fl_setpup_softedge( popup_id, 1 );
115 
116     for ( i = 1; i <= sp->numitems; i++ )
117     {
118         if ( sp->mval[ i ] == i && ! sp->cb[ i ] )
119             fl_addtopup( popup_id, sp->items[ i ] );
120         else
121         {
122             char *s = fl_malloc(   strlen( sp->items[ i ] )
123                                  + 6 + log10( INT_MAX ) );
124 
125             sprintf( s, "%s%%x%d%s", sp->items[ i ], sp->mval[ i ],
126                      sp->cb[ i ] ? "%f" : "" );
127 
128             if ( ! sp->cb[ i ] )
129                 fl_addtopup( popup_id, s );
130             else
131                 fl_addtopup( popup_id, s, sp->cb[ i ] );
132 
133             fl_free( s );
134         }
135 
136         if ( sp->modechange[ i ] || sp->mode[ i ] != FL_PUP_NONE )
137         {
138             fl_setpup_mode( popup_id, sp->mval[ i ], sp->mode[ i ] );
139             sp->modechange[ i ] = 0;
140         }
141 
142         fl_setpup_shortcut( popup_id, sp->mval[ i ], sp->shortcut[ i ] );
143     }
144 
145     /* Pulldown menus and those without a title appear directly
146        below the menu itself, the others more or less on top of
147        the menu */
148 
149     if ( ob->type == FL_PULLDOWN_MENU || sp->no_title )
150         fl_setpup_position( ob->form->x + ob->x + 1,
151                             ob->form->y + ob->y + ob->h + 1 );
152     else
153         fl_setpup_position( ob->form->x + ob->x + 5,
154                             ob->form->y + ob->y + 5 );
155 
156     /* Now do the user interaction */
157 
158     val = fl_dopup( popup_id );
159 
160     /* Deal with whatever is needed according to the return value */
161 
162     if ( val > 0 && ( k = val_to_index( ob, val ) ) > 0 )
163     {
164         /* If shown for the first time, need to get all mode right as the
165            menu item string may have embedded mode setting strings in it */
166 
167         if ( sp->shown == 0 )
168         {
169             for ( i = 1; i <= sp->numitems; i++ )
170             {
171                 int m = fl_getpup_mode( popup_id, sp->mval[ i ] );
172 
173                 sp->modechange[ i ] = sp->mode[ i ] != m;
174                 sp->mode[ i ] = m;
175                 sp->shown = 1;
176             }
177         }
178         else
179         {
180             sp->mode[ k ] = fl_getpup_mode( popup_id, val );
181             sp->modechange[ k ] = 1;
182 
183             /* Old val also might change mode if binary */
184 
185             if ( sp->val > 0 )
186             {
187                 int m = fl_getpup_mode( popup_id, sp->mval[ sp->val ] );
188 
189                 sp->modechange[ sp->val ] = sp->mode[ sp->val ] != m;
190                 sp->mode[ sp->val ] = m;
191             }
192         }
193 
194         sp->val = k;
195     }
196 
197     /* Get rid of the popup */
198 
199     fl_freepup( popup_id );
200 
201     return val;
202 }
203 
204 
205 /***************************************
206  ***************************************/
207 
208 static int
do_menu(FL_OBJECT * ob)209 do_menu( FL_OBJECT *ob )
210 {
211     int val;
212 
213     ob->pushed = 1;
214     fl_redraw_object( ob );
215 
216     val = do_menu_low_level( ob ) > 0;
217 
218     ob->pushed = 0;
219     fl_redraw_object( ob );
220 
221     return val > 0;
222 }
223 
224 
225 /***************************************
226  * Handles an event, return non-zero if an item has been selected.
227  ***************************************/
228 
229 static int
handle_menu(FL_OBJECT * ob,int event,FL_Coord mx FL_UNUSED_ARG,FL_Coord my FL_UNUSED_ARG,int key FL_UNUSED_ARG,void * ev FL_UNUSED_ARG)230 handle_menu( FL_OBJECT * ob,
231              int         event,
232              FL_Coord    mx   FL_UNUSED_ARG,
233              FL_Coord    my   FL_UNUSED_ARG,
234              int         key  FL_UNUSED_ARG,
235              void      * ev   FL_UNUSED_ARG )
236 {
237     FLI_MENU_SPEC *sp = ob->spec;
238     int val,
239         boxtype = ob->boxtype;
240     FL_COLOR col;
241     int ret = FL_RETURN_NONE;
242 
243 #if FL_DEBUG >= ML_DEBUG
244     M_info2( "handle_menu", fli_event_name( event ) );
245 #endif
246 
247     switch ( event )
248     {
249         case FL_ATTRIB :
250             ob->align = fl_to_inside_lalign( ob->align );
251             break;
252 
253         case FL_DRAW:
254             /* Draw the object */
255 
256             if ( ob->pushed )
257             {
258                 boxtype = FL_UP_BOX;
259                 col = ob->col2;
260             }
261             else
262                 col = ob->col1;
263 
264             fl_draw_box( boxtype, ob->x, ob->y, ob->w, ob->h, col, ob->bw );
265             fl_draw_text( ob->align, ob->x, ob->y, ob->w, ob->h,
266                           ob->lcol, ob->lstyle, ob->lsize, ob->label );
267 
268             if ( sp->showsymbol )
269             {
270                 int dm = 0.85 * FL_min( ob->w, ob->h );
271 
272                 fl_draw_text( 0, ob->x + ob->w - dm - 1, ob->y + 1,
273                               dm, dm, col, 0, 0, "@menu" );
274             }
275             break;
276 
277         case FL_ENTER:
278             if ( ob->type == FL_TOUCH_MENU && do_menu( ob ) > 0 )
279                 ret |= FL_RETURN_CHANGED;
280             break;
281 
282         case FL_PUSH:
283             /* Touch menus and push menus without a title don't do anything
284                on a button press */
285 
286             if (    key != FL_MBUTTON1
287                  || ( ob->type == FL_PUSH_MENU && sp->no_title ) )
288                 break;
289 
290             if ( ob->type == FL_TOUCH_MENU )
291             {
292                 ret |= FL_RETURN_END;
293                 break;
294             }
295 
296             if ( do_menu( ob ) > 0 )
297                 ret |= FL_RETURN_END | FL_RETURN_CHANGED;
298 
299             break;
300 
301         case FL_RELEASE :
302             /* Button release is only important for push menus without a
303                title, all others get started by a button press or by just
304                moving the mouse on top of it (and they also don't expect
305                a release - that gets eaten by the popup handler) */
306 
307             if (    key != FL_MBUTTON1
308                  || ! ( ob->type == FL_PUSH_MENU && sp->no_title )
309                  || mx < ob->x
310                  || mx > ob->x + ob->w
311                  || my < ob->y
312                  || my > ob->y + ob->h )
313                 break;
314 
315             if ( do_menu( ob ) > 0 )
316                 ret |= FL_RETURN_CHANGED | FL_RETURN_END;
317 
318             break;
319 
320         case FL_SHORTCUT:
321             /* Show menu as highlighted */
322 
323             ob->pushed = 1;
324             fl_redraw_object( ob );
325 
326             /* Do interaction and then redraw without highlighting */
327 
328             val = do_menu( ob );
329             ob->pushed = 0;
330             fl_redraw_object( ob );
331             if ( val > 0 )
332                 ret |= FL_RETURN_CHANGED | FL_RETURN_END;
333             break;
334 
335         case FL_FREEMEM:
336             fl_clear_menu( ob );
337             fl_free( ob->spec );
338             return 0;
339     }
340 
341     return ret;
342 }
343 
344 
345 /***************************************
346  * Creates a menu object
347  ***************************************/
348 
349 FL_OBJECT *
fl_create_menu(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)350 fl_create_menu( int          type,
351                 FL_Coord     x,
352                 FL_Coord     y,
353                 FL_Coord     w,
354                 FL_Coord     h,
355                 const char * label )
356 {
357     FL_OBJECT *obj;
358     FLI_MENU_SPEC *sp;
359 
360     obj = fl_make_object( FL_MENU, type, x, y, w, h, label, handle_menu );
361 
362     obj->boxtype = FL_FLAT_BOX;
363     obj->col1   = FL_MENU_COL1;
364     obj->col2   = FL_MENU_COL2;
365     obj->lcol   = FL_MENU_LCOL;
366     obj->lstyle = FL_NORMAL_STYLE;
367     obj->align  = FL_MENU_ALIGN;
368 
369     if ( type == FL_TOUCH_MENU )
370         fl_set_object_return( obj, FL_RETURN_CHANGED );
371     else
372         fl_set_object_return( obj, FL_RETURN_END_CHANGED );
373 
374     sp = obj->spec = fl_calloc( 1, sizeof *sp );
375     sp->extern_menu = -1;
376 
377     return obj;
378 }
379 
380 
381 /***************************************
382  * Adds a menu object
383  ***************************************/
384 
385 FL_OBJECT *
fl_add_menu(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)386 fl_add_menu( int          type,
387              FL_Coord     x,
388              FL_Coord     y,
389              FL_Coord     w,
390              FL_Coord     h,
391              const char * label )
392 {
393     FL_OBJECT *ob;
394 
395     ob = fl_create_menu( type, x, y, w, h, label );
396     fl_add_object( fl_current_form, ob );
397 
398     return ob;
399 }
400 
401 
402 /***************************************
403  * Clears the menu object
404  ***************************************/
405 
406 void
fl_clear_menu(FL_OBJECT * ob)407 fl_clear_menu( FL_OBJECT * ob )
408 {
409     int i;
410     FLI_MENU_SPEC *sp = ob->spec;
411 
412     if ( ISPUP( sp ) )
413     {
414         fl_freepup( sp->extern_menu );
415         sp->extern_menu = -1;
416         return;
417     }
418 
419     sp->val = 0;
420     sp->cur_val = 0;
421 
422     for ( i = 1; i <= sp->numitems; i++ )
423     {
424         fli_safe_free( sp->items[ i ] );
425         fli_safe_free( sp->shortcut[ i ] );
426         sp->mode[ i ] = FL_PUP_NONE;
427         sp->cb[ i ] = NULL;
428     }
429 
430     sp->numitems = 0;
431 }
432 
433 
434 /***************************************
435  * Adds a line to the menu item.
436  ***************************************/
437 
438 static void
addto_menu(FL_OBJECT * ob,const char * str,...)439 addto_menu( FL_OBJECT  * ob,
440             const char * str,
441             ... )
442 {
443     FLI_MENU_SPEC *sp = ob->spec;
444     int n;
445     char *p;
446 
447     if (    ISPUP( sp )
448          || sp->numitems >= FL_MENU_MAXITEMS
449          || sp->cur_val == INT_MAX )
450         return;
451 
452     n = ++sp->numitems;
453 
454     sp->items[ n ]    = fl_strdup( str );
455     sp->shortcut[ n ] = fl_strdup( "" );
456     sp->mode[ n ]     = FL_PUP_NONE;
457     sp->cb[ n ]       = NULL;
458 
459     /* Check if a callback function needs to be set */
460 
461     if ( ( p = strstr( sp->items[ n ], "%f" ) ) )
462     {
463         va_list ap;
464 
465         va_start( ap, str );
466         sp->cb[ n ] = va_arg( ap, FL_PUP_CB );
467         va_end( ap );
468         memmove( p, p + 2, strlen( p ) - 1 );
469     }
470 
471     /* Set the value for the menu (either the index or extract it from "%xn" */
472 
473     if ( ! ( p = strstr( sp->items[ n ], "%x" ) ) )
474         sp->mval[ n ] = ++sp->cur_val;
475     else
476     {
477         if ( ! isdigit( ( unsigned char ) p[ 2 ] ) )
478         {
479             M_err( "addto_menu", "Missing number after %%x" );
480             sp->mval[ n ] = ++sp->cur_val;
481         }
482         else
483         {
484             char *eptr;
485 
486             sp->mval[ n ] = strtol( p + 2, &eptr, 10 );
487             while ( *eptr && isspace( ( unsigned char ) *eptr ) )
488                 eptr++;
489             if ( *eptr )
490                 memmove( p, eptr, strlen( eptr ) + 1 );
491             else
492                 *p = '\0';
493         }
494     }
495 }
496 
497 
498 /***************************************
499  * Sets the menu to a particular menu string
500  ***************************************/
501 
502 void
fl_set_menu(FL_OBJECT * ob,const char * menustr,...)503 fl_set_menu( FL_OBJECT  * ob,
504              const char * menustr,
505              ... )
506 {
507     char *t,
508          *c;
509     va_list ap;
510     FLI_MENU_SPEC *sp = ob->spec;
511 
512 #if FL_DEBUG >= ML_ERR
513     if ( ! IsValidClass( ob, FL_MENU ) )
514     {
515         M_err( "fl_set_menu", "%s is not Menu class", ob ? ob->label : "" );
516         return;
517     }
518 #endif
519 
520     fl_clear_menu( ob );
521 
522     /* Split up menu string at '|' chars and create an entry for each part */
523 
524     va_start( ap, menustr );
525 
526     t = fl_strdup( menustr );
527 
528     for ( c = strtok( t, "|" );
529           c && sp->numitems < FL_CHOICE_MAXITEMS;
530           c = strtok( NULL, "|" ) )
531     {
532         FL_PUP_CB cb;
533 
534         if ( strstr( c, "%f" ) )
535         {
536             cb = va_arg( ap, FL_PUP_CB );
537             addto_menu( ob, c, cb );
538         }
539         else
540             addto_menu( ob, c );
541     }
542 
543     if ( t )
544         fl_free( t );
545 
546     va_end( ap );
547 }
548 
549 
550 /***************************************
551  * Adds a line to the menu item.
552  ***************************************/
553 
554 int
fl_addto_menu(FL_OBJECT * ob,const char * menustr,...)555 fl_addto_menu( FL_OBJECT  * ob,
556                const char * menustr,
557                ... )
558 {
559     FLI_MENU_SPEC *sp= ob->spec;
560     char *t,
561          *c;
562     va_list ap;
563 
564 #if FL_DEBUG >= ML_ERR
565     if ( ! IsValidClass( ob, FL_MENU ) )
566     {
567         M_err( "fl_addto_menu", "%s is not Menu class", ob ? ob->label : "" );
568         return 0;
569     }
570 #endif
571 
572     /* Split up menu string at '|' chars and create an entry for each part */
573 
574     va_start( ap, menustr );
575 
576     t = fl_strdup( menustr );
577 
578     for ( c = strtok( t, "|" );
579           c && sp->numitems < FL_CHOICE_MAXITEMS;
580           c = strtok( NULL, "|" ) )
581     {
582         FL_PUP_CB cb;
583 
584         if ( strstr( c, "%f" ) )
585         {
586             cb = va_arg( ap, FL_PUP_CB );
587             addto_menu( ob, c, cb );
588         }
589         else
590             addto_menu( ob, c );
591     }
592 
593     if ( t )
594         fl_free( t );
595 
596     va_end( ap );
597 
598     return sp->numitems;
599 }
600 
601 
602 /***************************************
603  * Replaces a line in the menu item.
604  ***************************************/
605 
606 void
fl_replace_menu_item(FL_OBJECT * ob,int numb,const char * str,...)607 fl_replace_menu_item( FL_OBJECT  * ob,
608                       int          numb,
609                       const char * str,
610                       ... )
611 {
612     FLI_MENU_SPEC *sp = ob->spec;
613     char *s,
614          *p,
615          *eptr;
616 
617     if ( ISPUP( sp ) )
618     {
619         fli_replacepup_text( sp->extern_menu, numb, str );
620         return;
621     }
622 
623     if ( ( numb = val_to_index( ob, numb ) ) <= 0 )
624         return;
625 
626     if ( sp->items[ numb ] )
627         fl_free( sp->items[ numb ] );
628     sp->cb[ numb ] = NULL;
629 
630     s = strdup( str );
631 
632     if ( ( p = strstr( s, "%f" ) ) )
633     {
634         va_list ap;
635 
636         va_start( ap, str );
637         sp->cb[ numb ] = va_arg( ap, FL_PUP_CB );
638         va_end( ap );
639         memmove( p, p + 2, strlen( p ) - 1 );
640     }
641 
642     if ( ( p = strstr( s, "%x" ) ) )
643     {
644         if ( isdigit( ( unsigned char ) p[ 2 ] ) )
645         {
646             sp->mval[ numb ] = strtol( p + 2, &eptr, 10 );
647             while ( *eptr && isspace( ( unsigned char ) *eptr ) )
648                 eptr++;
649             if ( *eptr )
650                 memmove( p, eptr, strlen( eptr ) + 1 );
651             else
652                 *p = '\0';
653         }
654         else
655         {
656             M_err( "fl_replace_menu_item", "Missing number after %%x" );
657             memmove( p, p + 2, strlen( p ) - 1 );
658         }
659     }
660 
661     sp->items[ numb ] = s;
662 }
663 
664 
665 /***************************************
666  * Removes a line from the menu item.
667  ***************************************/
668 
669 void
fl_delete_menu_item(FL_OBJECT * ob,int numb)670 fl_delete_menu_item( FL_OBJECT * ob,
671                      int         numb )
672 {
673     int i;
674     FLI_MENU_SPEC *sp = ob->spec;
675 
676     if ( ISPUP( sp ) || ( numb = val_to_index( ob, numb ) ) <= 0 )
677         return;
678 
679     fli_safe_free( sp->items[ numb ] );
680     fli_safe_free( sp->shortcut[ numb ] );
681 
682     for ( i = numb; i < sp->numitems; i++ )
683     {
684         sp->items[ i ]      = sp->items[ i + 1 ];
685         sp->mode[ i ]       = sp->mode[ i + 1 ];
686         sp->modechange[ i ] = sp->modechange[ i + 1 ];
687         sp->mval[ i ]       = sp->mval[ i + 1 ];
688         sp->shortcut[ i ]   = sp->shortcut[ i + 1 ];
689         sp->cb[ i ]         = sp->cb[ i + 1 ];
690     }
691 
692     if ( sp->val == numb )
693         sp->val = -1;
694 
695     sp->items[ sp->numitems ]      = NULL;
696     sp->shortcut[ sp->numitems ]   = NULL;
697     sp->mode[ sp->numitems ]       = FL_PUP_NONE;
698     sp->modechange[ sp->numitems ] = 0;
699     sp->mval[ sp->numitems ]       = 0;
700     sp->cb[ sp->numitems ]         = NULL;
701 
702     sp->numitems--;
703 }
704 
705 
706 /***************************************
707  * Sets a callback function for a menu item
708  ***************************************/
709 
710 FL_PUP_CB
fl_set_menu_item_callback(FL_OBJECT * ob,int numb,FL_PUP_CB cb)711 fl_set_menu_item_callback( FL_OBJECT * ob,
712                            int         numb,
713                            FL_PUP_CB   cb )
714 {
715     FLI_MENU_SPEC *sp = ob->spec;
716     FL_PUP_CB old_cb;
717 
718     if ( ISPUP( sp ) || ( numb = val_to_index( ob, numb ) ) <= 0 )
719         return NULL;
720 
721     old_cb = sp->cb[ numb ];
722     sp->cb[ numb ] = cb;
723     return old_cb;
724 }
725 
726 
727 /***************************************
728  * Sets a shortcut for a menu item
729  ***************************************/
730 
731 void
fl_set_menu_item_shortcut(FL_OBJECT * ob,int numb,const char * str)732 fl_set_menu_item_shortcut( FL_OBJECT  * ob,
733                            int          numb,
734                            const char * str )
735 {
736     FLI_MENU_SPEC *sp = ob->spec;
737 
738     if ( ISPUP( sp ) || ( numb = val_to_index( ob, numb ) ) <= 0 )
739         return;
740 
741     fli_safe_free( sp->shortcut[ numb ] );
742     sp->shortcut[ numb ] = fl_strdup( str ? str : "" );
743 }
744 
745 
746 /***************************************
747  * Sets the display mode for the menu item
748  ***************************************/
749 
750 void
fl_set_menu_item_mode(FL_OBJECT * ob,int numb,unsigned int mode)751 fl_set_menu_item_mode( FL_OBJECT    * ob,
752                        int            numb,
753                        unsigned int   mode )
754 {
755     FLI_MENU_SPEC *sp = ob->spec;
756 
757     if ( ISPUP( sp ) )
758         fl_setpup_mode( sp->extern_menu, numb, mode );
759     else
760     {
761         if ( ( numb = val_to_index( ob, numb ) ) <= 0 )
762             return;
763 
764         sp->mode[ numb ] = mode;
765         sp->modechange[ numb ] = 1;
766 
767         if ( mode & FL_PUP_CHECK )
768             sp->val = numb;
769     }
770 }
771 
772 
773 /***************************************
774  * Sets the display mode for the menu item
775  ***************************************/
776 
777 int
fl_set_menu_item_id(FL_OBJECT * ob,int index,int id)778 fl_set_menu_item_id( FL_OBJECT * ob,
779                      int         index,
780                      int         id )
781 {
782     FLI_MENU_SPEC *sp = ob->spec;
783     int old_id;
784 
785     if ( ISPUP( sp ) || id < 1 || index < 1 || index > sp->numitems )
786         return -1;
787 
788     old_id = sp->mval[ index ];
789     sp->mval[ index ] = id;
790     return old_id;
791 }
792 
793 
794 /***************************************
795  * Makes the menu symbol visible or not
796  ***************************************/
797 
798 void
fl_show_menu_symbol(FL_OBJECT * ob,int show)799 fl_show_menu_symbol( FL_OBJECT * ob,
800                      int         show )
801 {
802     FLI_MENU_SPEC *sp = ob->spec;
803 
804     if ( ISPUP( sp ) )
805          return;
806 
807     sp->showsymbol = show;
808     fl_redraw_object( ob );
809 }
810 
811 
812 /***************************************
813  * Returns the number of the menu item selected.
814  ***************************************/
815 
816 int
fl_get_menu(FL_OBJECT * ob)817 fl_get_menu( FL_OBJECT * ob )
818 {
819     FLI_MENU_SPEC *sp = ob->spec;
820 
821 #if FL_DEBUG >= ML_ERR
822     if ( ! IsValidClass( ob, FL_MENU ) )
823     {
824         M_err( "fl_get_menu", "%s is not Menu class", ob ? ob->label : "" );
825         return 0;
826     }
827 #endif
828 
829     if ( ISPUP( sp ) )
830         return sp->val;
831 
832     return sp->val > 0 && sp->val <= sp->numitems ? sp->mval[ sp->val ] : -1;
833 }
834 
835 
836 /***************************************
837  * Returns rhe number of items in a menu
838  ***************************************/
839 
840 int
fl_get_menu_maxitems(FL_OBJECT * ob)841 fl_get_menu_maxitems( FL_OBJECT * ob )
842 {
843     FLI_MENU_SPEC *sp = ob->spec;
844 
845 #if FL_DEBUG >= ML_ERR
846     if ( ! IsValidClass( ob, FL_MENU ) )
847     {
848         M_err( "fl_get_menu_maxitems", "%s is not Menu class",
849                ob ? ob->label : "" );
850         return 0;
851     }
852 #endif
853 
854     return ISPUP( sp ) ? fl_getpup_items( sp->extern_menu ) : sp->numitems;
855 }
856 
857 
858 /***************************************
859  * Returns the text of the menu item selected.
860  ***************************************/
861 
862 const char *
fl_get_menu_text(FL_OBJECT * ob)863 fl_get_menu_text( FL_OBJECT * ob )
864 {
865     FLI_MENU_SPEC *sp = ob->spec;
866 
867 #if FL_DEBUG >= ML_ERR
868     if ( ! IsValidClass( ob, FL_MENU ) )
869     {
870         M_err( "fl_get_menu_text", "%s is not Menu class",
871                ob ? ob->label : "" );
872         return NULL;
873     }
874 #endif
875 
876     if ( ISPUP( sp ) )
877         return fl_getpup_text( sp->extern_menu, sp->val );
878 
879     return ( sp->val < 1 || sp->val > sp->numitems ) ?
880             NULL : sp->items[ sp->val ];
881 }
882 
883 
884 /***************************************
885  * Returns a string with the menu items text
886  ***************************************/
887 
888 const char *
fl_get_menu_item_text(FL_OBJECT * ob,int numb)889 fl_get_menu_item_text( FL_OBJECT * ob,
890                        int         numb )
891 {
892     FLI_MENU_SPEC *sp = ob->spec;
893 
894 #if FL_DEBUG >= ML_ERR
895     if ( ! IsValidClass( ob, FL_MENU ) )
896     {
897         M_err( "fl_get_menu_item_text", "%s is not Menu class",
898                ob ? ob->label : "" );
899         return NULL;
900     }
901 #endif
902 
903     if ( ISPUP(sp ) )
904         return fl_getpup_text( sp->extern_menu, numb );
905 
906     numb = val_to_index( ob, numb );
907 
908     return numb <= 0 ? NULL : sp->items[ numb ];
909 }
910 
911 
912 /***************************************
913  * Returns the mode of a menu item
914  ***************************************/
915 
916 unsigned int
fl_get_menu_item_mode(FL_OBJECT * ob,int numb)917 fl_get_menu_item_mode( FL_OBJECT * ob,
918                        int         numb )
919 {
920     FLI_MENU_SPEC *sp = ob->spec;
921 
922 #if FL_DEBUG >= ML_ERR
923     if ( ! IsValidClass( ob, FL_MENU ) )
924     {
925         M_err( "fl_get_menu_item_mode", "%s is not Menu class",
926                ob ? ob->label : "" );
927         return 0;
928     }
929 #endif
930 
931     if ( ISPUP( sp ) )
932         return fl_getpup_mode( sp->extern_menu, numb );
933 
934     numb = val_to_index( ob, numb );
935 
936     return numb <= 0 ? 0 : sp->mode[ numb ];
937 }
938 
939 
940 /***************************************
941  * Makes an already existing popup a menu
942  ***************************************/
943 
944 void
fl_set_menu_popup(FL_OBJECT * ob,int pup)945 fl_set_menu_popup( FL_OBJECT * ob,
946                    int         pup )
947 {
948 #if FL_DEBUG >= ML_ERR
949     if ( ! IsValidClass( ob, FL_MENU ) )
950     {
951         M_err( "fl_set_menu_popup", "%s is not Menu class",
952                ob ? ob->label : "" );
953         return;
954     }
955 #endif
956 
957     ( ( FLI_MENU_SPEC * ) ob->spec )->extern_menu = pup;
958 
959     if ( ob->type == FL_PULLDOWN_MENU )
960         fl_setpup_shadow( pup, 0 );
961 }
962 
963 
964 /***************************************
965  * Creates a popup and makes that a menu
966  ***************************************/
967 
968 int
fl_set_menu_entries(FL_OBJECT * ob,FL_PUP_ENTRY * ent)969 fl_set_menu_entries( FL_OBJECT    * ob,
970                      FL_PUP_ENTRY * ent )
971 {
972     int n;
973 
974     fl_clear_menu( ob );
975 
976     n = fl_newpup( FL_ObjWin( ob ) );
977     fl_set_menu_popup( ob, fl_setpup_entries( n, ent ) );
978 
979     if ( ob->type == FL_PULLDOWN_MENU )
980     {
981         fl_setpup_bw( n, ob->bw );
982         fl_setpup_shadow( n, 0 );
983     }
984 
985     return n;
986 }
987 
988 
989 /***************************************
990  * If the menu is really a popup in disguise returns the popups number
991  ***************************************/
992 
993 int
fl_get_menu_popup(FL_OBJECT * ob)994 fl_get_menu_popup( FL_OBJECT * ob )
995 {
996     FLI_MENU_SPEC *sp = ob->spec;
997 
998     return ISPUP( sp ) ? sp->extern_menu : -1;
999 }
1000 
1001 
1002 /***************************************
1003  * Allows to change the no-title attribute of a menu
1004  ***************************************/
1005 
1006 int
fl_set_menu_notitle(FL_OBJECT * ob,int off)1007 fl_set_menu_notitle( FL_OBJECT * ob,
1008                      int         off )
1009 {
1010     FLI_MENU_SPEC *sp = ob->spec;
1011     int old = sp->no_title;
1012 
1013     sp->no_title = off;
1014     return old;
1015 }
1016 
1017 
1018 /*
1019  * Local variables:
1020  * tab-width: 4
1021  * indent-tabs-mode: nil
1022  * End:
1023  */
1024