1 /*
2  * This file is part of XForms.
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 sp_menu.c
21  *
22  *  This file is part of XForms package
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  * Setting menu class specific attributes.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <ctype.h>
34 
35 #include "fd_main.h"
36 #include "fd_spec.h"
37 #include "sp_menu.h"
38 #include "private/pmenu.h"
39 #include "spec/menu_spec.h"
40 
41 static FD_menuattrib *menu_attrib;
42 static FL_OBJECT *curobj;
43 
44 static const char * int_out( FL_OBJECT * ob,
45                              double      val,
46                              int         prec );
47 static char * get_pupentry_name( FL_OBJECT * obj );
48 
49 
50 /***************************************
51  ***************************************/
52 
53 FL_FORM *
menu_create_spec_form(void)54 menu_create_spec_form( void )
55 {
56     if ( menu_attrib )
57         return menu_attrib->menuattrib;
58 
59     menu_attrib = create_form_menuattrib( );
60     fl_addto_choice( menu_attrib->mode, get_pupmode_string( ) );
61     fl_addto_choice( menu_attrib->scope, "local|global" );
62     fl_set_choice_item_shortcut( menu_attrib->mode, 1, "Nn#N" );
63     fl_set_choice_item_shortcut( menu_attrib->mode, 1, "Gg#G" );
64     fl_set_choice_item_shortcut( menu_attrib->mode, 1, "Bb#B" );
65     fl_set_choice_item_shortcut( menu_attrib->mode, 1, "Cc#C" );
66     fl_set_choice_item_shortcut( menu_attrib->mode, 1, "Rr#R" );
67     fl_set_browser_dblclick_callback( menu_attrib->content_br,
68                                           change_menu_item_cb, 0 );
69 
70     return menu_attrib->menuattrib;
71 }
72 
73 
74 /***************************************
75  ***************************************/
76 
77 void
menu_fill_in_spec_form(FL_OBJECT * obj)78 menu_fill_in_spec_form( FL_OBJECT * obj )
79 {
80     FLI_MENU_SPEC *sp = obj->spec;
81     SuperSPEC *ssp = get_superspec( obj );
82     int i;
83     int mval = sp->numitems + 1;
84 
85     curobj = obj;
86 
87     fl_freeze_form( menu_attrib->content_br->form );
88 
89     fl_set_button( menu_attrib->new_menuapi, ssp->new_menuapi );
90     fl_clear_browser( menu_attrib->content_br );
91 
92     for ( i = 1; i <= sp->numitems; i++ )
93     {
94         fl_add_browser_line( menu_attrib->content_br, sp->items[ i ] );
95         if ( sp->mval[ i ] >= mval )
96             mval = sp->mval[ i ] + 1;
97     }
98 
99     fl_set_choice( menu_attrib->scope, ssp->global_scope + 1 );
100 
101     if ( ssp->new_menuapi )
102         fl_hide_object( menu_attrib->id );
103     else
104         fl_show_object( menu_attrib->id );
105 
106     fl_set_counter_filter( menu_attrib->id, int_out );
107     fl_set_counter_value( menu_attrib->id, sp->numitems + 1 );
108 
109     fl_unfreeze_form( menu_attrib->content_br->form );
110 }
111 
112 
113 /***************************************
114  ***************************************/
115 
116 void
menu_emit_spec_fd_code(FILE * fp,FL_OBJECT * obj)117 menu_emit_spec_fd_code( FILE      * fp,
118                         FL_OBJECT * obj )
119 {
120     FL_OBJECT *defobj = fl_create_menu( obj->type, 0, 0, 0, 0, "" );
121     FLI_MENU_SPEC *sp    = obj->spec,
122                   *defsp = defobj->spec;
123     SuperSPEC *ssp    = get_superspec( obj ),
124               *defssp = get_superspec( defobj );
125     int i;
126 
127     if ( ssp->new_menuapi != defssp->new_menuapi )
128         fprintf( fp, "    struct: %d\n", ssp->new_menuapi );
129 
130     if ( ssp->global_scope != defssp->global_scope )
131         fprintf( fp, "    global: %d\n", ssp->global_scope );
132 
133     for ( i = 1; i <= sp->numitems; i++ )
134     {
135         if ( sp->items[ i ] )
136             fprintf( fp, "    content: %s\n", sp->items[ i ] );
137         fprintf( fp, "    id: %d\n", sp->mval[ i ] );
138 
139         if ( sp->mode[ i ] != defsp->mode[ i ] )
140             fprintf( fp, "    mode: %s\n", get_pupmode_name(sp->mode[ i ] ) );
141 
142         if ( sp->shortcut[ i ] && *sp->shortcut[ i ] )
143             fprintf( fp, "    shortcut: %s\n", sp->shortcut[ i ] );
144 
145         if ( ssp->callback && ssp->callback[ i ] )
146             fprintf( fp, "    callback: %s\n", ssp->callback[ i ] );
147     }
148 
149     free_superspec( defobj );
150     fl_free_object( defobj );
151 }
152 
153 
154 /***************************************
155  ***************************************/
156 
157 void
menu_emit_spec_c_code(FILE * fp,FL_OBJECT * obj)158 menu_emit_spec_c_code( FILE      * fp,
159                        FL_OBJECT * obj )
160 {
161     FL_OBJECT *defobj;
162     FLI_MENU_SPEC *sp = obj->spec,
163                   *defsp;
164     SuperSPEC *ssp;
165 
166     if ( sp->numitems == 0 )
167         return;
168 
169     /* Create a default object */
170 
171     defobj = fl_create_menu( obj->type, 0, 0, 0, 0, "" );
172     defsp = defobj->spec;
173 
174     ssp = get_superspec( obj );
175 
176     if ( ssp->new_menuapi )
177         fprintf( fp, "    fl_set_menu_entries( obj, %s );\n", ssp->misc_char );
178     else
179     {
180         int i;
181 
182         for ( i = 1; i <= sp->numitems; i++ )
183         {
184             fprintf( fp, "    fl_addto_menu( obj, \"%s\" );\n",
185                      sp->items[ i ] );
186 
187             if ( sp->mode[ i ] != defsp->mode[ i ] )
188                 fprintf(fp, "    fl_set_menu_item_mode( obj, %d, %s );\n",
189                         i, get_pupmode_name( sp->mode[ i ] ) );
190 
191             if ( sp->shortcut[ i ] && *sp->shortcut[ i ] )
192                 fprintf( fp,
193                          "    fl_set_menu_item_shortcut( obj, %d, \"%s\" );\n",
194                          i, sp->shortcut[ i ] );
195 
196             if ( ssp->callback[ i ] && *ssp->callback[ i ] )
197                 fprintf( fp, "    fl_set_menu_item_callback( obj, %d, %s );\n",
198                          i, ssp->callback[ i ] );
199 
200             if ( sp->mval[ i ] != i )
201                 fprintf( fp, "    fl_set_menu_item_id( obj, %d, %d );\n",
202                          i, sp->mval[ i ] );
203         }
204     }
205 
206     fl_free_object( defobj );
207 }
208 
209 
210 /***************************************
211  * emit things that are needed before code emission (file scope)
212  ***************************************/
213 
214 void
menu_emit_spec_header(FILE * fp,FL_OBJECT * obj)215 menu_emit_spec_header( FILE      * fp,
216                        FL_OBJECT * obj )
217 {
218     FLI_MENU_SPEC *sp = obj->spec;
219     SuperSPEC *ssp = get_superspec( obj );
220     int i;
221 
222     if ( ! ssp->new_menuapi || sp->numitems <= 0 )
223         return;
224 
225     get_pupentry_name( obj );
226 
227     fprintf( fp, "\n%sFL_PUP_ENTRY %s[ ] = {\n",
228              ssp->global_scope ? "" : "static ", ssp->misc_char );
229     fprintf( fp, "    /*  itemtext callback  shortcut   mode */\n" );
230 
231     for ( i = 1; i <= sp->numitems; i++ )
232         fprintf( fp, "    { \"%s\", %s, \"%s\", %s, { 0, 0 } },\n",
233                  sp->items[ i ],
234                  ( ssp->callback[ i ] && *ssp->callback[ i ] ) ?
235                  ( char * ) ssp->callback[ i ] : "NULL",
236                  sp->shortcut[ i ] ? sp->shortcut[ i ] : "",
237                  get_pupmode_name( sp->mode[ i ] ) );
238 
239     /* sentinel */
240 
241     fprintf( fp, "    { NULL, 0, NULL, 0, { 0, 0 } }\n};\n\n");
242 }
243 
244 
245 /***************************************
246  * emit header info that is global in nature
247  ***************************************/
248 
249 void
menu_emit_spec_global_header(FILE * fp,FL_OBJECT * obj)250 menu_emit_spec_global_header( FILE      * fp,
251                               FL_OBJECT * obj )
252 {
253     FLI_MENU_SPEC *sp = obj->spec;
254     SuperSPEC *ssp = get_superspec( obj );
255 
256     if ( ! ssp->new_menuapi || sp->numitems <= 0 || ! ssp->global_scope )
257         return;
258 
259     get_pupentry_name( obj );
260 
261     fprintf( fp, "extern FL_PUP_ENTRY %s[ ];\n", ssp->misc_char );
262 }
263 
264 
265 /***************************************
266  * Emit menu item callback prototypes or function definitions
267  ***************************************/
268 
269 void
menu_emit_item_callback_headers(FILE * fn,FL_OBJECT * obj,int code)270 menu_emit_item_callback_headers( FILE      * fn,
271                                  FL_OBJECT * obj,
272                                  int         code )
273 {
274     FLI_MENU_SPEC *sp = obj->spec;
275     SuperSPEC *ssp = get_superspec( obj );
276     int i;
277 
278     if ( ssp->new_menuapi || sp->numitems <= 0 )
279         return;
280 
281     for ( i = 1; i <= sp->numitems; i++ )
282     {
283         if ( ! ssp->callback[ i ] )
284             continue;
285 
286         if ( ! code )
287             fprintf( fn, "int %s( int );\n", ssp->callback[ i ] );
288         else
289         {
290             fprintf( fn, "/***************************************\n"
291                      " ***************************************/\n\n" );
292             fprintf( fn, "int %s( int menu_item_ID )\n{\n",
293                      ssp->callback[ i ] );
294             fprintf( fn, "    /* fill-in code for menu item callback */\n\n"
295                      "    return menu_item_ID;\n}\n\n\n" );
296         }
297     }
298 }
299 
300 
301 /***************************************
302  ***************************************/
303 
304 static const char *
int_out(FL_OBJECT * ob FL_UNUSED_ARG,double val,int prec FL_UNUSED_ARG)305 int_out( FL_OBJECT * ob    FL_UNUSED_ARG,
306          double      val,
307          int         prec  FL_UNUSED_ARG )
308 {
309     static char buf[ 20 ];
310 
311     sprintf( buf, "%d", FL_nint( val ) );
312     return buf;
313 }
314 
315 
316 /***************************************
317  * create a name for the [menu|choice]_entry API and hang it off
318  * sp->misc_char
319  ***************************************/
320 
321 static char *
get_pupentry_name(FL_OBJECT * obj)322 get_pupentry_name( FL_OBJECT * obj )
323 {
324     static int n = 0;
325     char pupname[ 128 ],
326          *p;
327     char objname[ 128 ],
328          cbname[ 128 ],
329          argname[ 128 ];
330     FLI_MENU_SPEC *sp = obj->spec;
331     SuperSPEC *ssp = get_superspec( obj );
332     int i;
333 
334     if ( ! ssp->new_menuapi || sp->numitems <= 0 )
335         return "";
336 
337     if ( ssp->misc_char && *ssp->misc_char )
338         return ssp->misc_char;
339 
340     get_object_name( obj, objname, cbname, argname );
341 
342     if ( *objname )
343         sprintf( pupname, "fdmenu_%s_%d", objname, n );
344     else if ( *obj->label )
345         sprintf( pupname, "fdmenu_%s_%d", obj->label, n );
346     else
347         sprintf( pupname, "fdmenu_%d", n );
348 
349     n++;
350 
351     /* Get rid of illegal chars */
352 
353     for ( i = 0, p = pupname; *p; p++ )
354         if ( isalnum( ( unsigned char ) *p ) || *p == '_' )
355             pupname[ i++ ] = *p;
356 
357     pupname[ i++ ] = '\0';
358     fli_safe_free ( ssp->misc_char );
359     ssp->misc_char = fl_strdup( pupname );
360 
361     return ssp->misc_char;
362 }
363 
364 
365 /*
366  * attributes callbacks
367  */
368 
369 /***************************************
370  * callbacks and freeobj handles for form choiceattrib
371  ***************************************/
372 
373 void
add_menu_item_cb(FL_OBJECT * obj FL_UNUSED_ARG,long data FL_UNUSED_ARG)374 add_menu_item_cb( FL_OBJECT * obj   FL_UNUSED_ARG,
375                   long        data  FL_UNUSED_ARG )
376 {
377         FLI_MENU_SPEC *sp = curobj->spec;
378         int i,
379             k;
380 
381     const char *s = fl_get_input( menu_attrib->input );
382     const char *sc = fl_get_input( menu_attrib->shortcut );
383     const char *mode = fl_get_choice_text( menu_attrib->mode );
384     const char *item_cb = fl_get_input( menu_attrib->item_cb );
385     int mval = fl_get_counter_value( menu_attrib->id );
386 
387     if ( ! s || ! *s )
388         return;
389 
390     fl_addto_browser( menu_attrib->content_br, s );
391 
392     i = fl_addto_menu( curobj, s );
393 
394     k = sp->mval[ i ];
395     fl_set_menu_item_shortcut( curobj, k, sc );
396 
397     fl_set_menu_item_mode( curobj, k, get_pupmode_value( mode ) );
398 
399     fli_safe_free( sp->cb[ i ] );
400 
401     if ( item_cb && *item_cb )
402         fl_set_menu_item_callback( curobj, k,
403                                    ( FL_PUP_CB ) fl_strdup( item_cb ) );
404     if ( k != mval )
405         fl_set_menu_item_id( curobj, i, mval );
406 
407     if ( fl_get_button( menu_attrib->auto_clear ) )
408         clear_menu_field_cb( menu_attrib->auto_clear, 0 );
409 
410     redraw_the_form( 0 );
411 }
412 
413 
414 /***************************************
415  ***************************************/
416 
417 void
replace_menu_item_cb(FL_OBJECT * obj FL_UNUSED_ARG,long data FL_UNUSED_ARG)418 replace_menu_item_cb( FL_OBJECT * obj   FL_UNUSED_ARG,
419                       long        data  FL_UNUSED_ARG )
420 {
421     FLI_MENU_SPEC *sp = curobj->spec;
422     int i = fl_get_browser( menu_attrib->content_br );
423     const char *s = fl_get_input( menu_attrib->input );
424     const char *sc = fl_get_input( menu_attrib->shortcut );
425     const char *mode = fl_get_choice_text( menu_attrib->mode );
426     const char *item_cb = fl_get_input( menu_attrib->item_cb );
427     int mval = fl_get_counter_value( menu_attrib->id );
428     int k;
429 
430     if ( ! *s || i <= 0 )
431         return;
432 
433     fl_replace_browser_line( menu_attrib->content_br, i, s );
434 
435     k = sp->mval[ i ];
436 
437     fl_replace_menu_item( curobj, k, s );
438 
439     fl_set_menu_item_shortcut( menu_attrib->vdata, k, sc );
440 
441     fl_set_menu_item_mode( curobj, k, get_pupmode_value( mode ) );
442 
443     fli_safe_free( sp->cb[ i ] );
444 
445     if ( item_cb && *item_cb )
446         fl_set_menu_item_callback( curobj, k,
447                                    ( FL_PUP_CB ) fl_strdup( item_cb ) );
448     if ( k != mval )
449         fl_set_menu_item_id( curobj, i, mval );
450 
451     if ( fl_get_button( menu_attrib->auto_clear ) )
452         clear_menu_field_cb( menu_attrib->auto_clear, 0 );
453 
454     redraw_the_form( 0 );
455 }
456 
457 
458 /***************************************
459  ***************************************/
460 
461 void
delete_menu_item_cb(FL_OBJECT * obj FL_UNUSED_ARG,long data FL_UNUSED_ARG)462 delete_menu_item_cb( FL_OBJECT * obj   FL_UNUSED_ARG,
463                      long        data  FL_UNUSED_ARG )
464 {
465         FLI_MENU_SPEC *sp = curobj->spec;
466     int i = fl_get_browser( menu_attrib->content_br );
467 
468     if ( i <= 0 )
469         return;
470 
471     fl_delete_browser_line( menu_attrib->content_br, i );
472     fli_safe_free( sp->cb[ i ] );
473     fl_delete_menu_item( curobj, sp->mval[ i ] );
474     redraw_the_form( 0 );
475 }
476 
477 
478 /***************************************
479  ***************************************/
480 
481 void
change_menu_item_cb(FL_OBJECT * obj FL_UNUSED_ARG,long data FL_UNUSED_ARG)482 change_menu_item_cb( FL_OBJECT * obj   FL_UNUSED_ARG,
483                      long        data  FL_UNUSED_ARG )
484 {
485     int i = fl_get_browser( menu_attrib->content_br );
486     FLI_MENU_SPEC *sp = curobj->spec;
487 
488     if ( i <= 0 )
489         return;
490 
491     fl_set_input( menu_attrib->input,
492                   fl_get_browser_line( menu_attrib->content_br, i ) );
493 
494     if ( sp->shortcut[ i ] )
495         fl_set_input( menu_attrib->shortcut, sp->shortcut[ i ] );
496 
497     fl_set_choice_text( menu_attrib->mode,
498                         get_pupmode_name( sp->mode[ i ] ) + 3 );
499 
500     if ( sp->cb[ i ] )
501         fl_set_input( menu_attrib->item_cb, ( char * ) sp->cb[ i ] );
502     else
503         fl_set_input( menu_attrib->item_cb, "" );
504 
505     fl_set_counter_value( menu_attrib->id, sp->mval[ i ] );
506 }
507 
508 
509 /***************************************
510  ***************************************/
511 
512 void
clear_menu_field_cb(FL_OBJECT * obj FL_UNUSED_ARG,long data FL_UNUSED_ARG)513 clear_menu_field_cb( FL_OBJECT * obj   FL_UNUSED_ARG,
514                      long        data  FL_UNUSED_ARG )
515 {
516     int i;
517     FLI_MENU_SPEC *sp = curobj->spec;
518     int mval = sp->numitems + 1;
519 
520     fl_set_input( menu_attrib->input, "" );
521     fl_set_input( menu_attrib->shortcut, "" );
522     fl_set_choice( menu_attrib->mode, 1 );
523     fl_set_input( menu_attrib->item_cb, "" );
524 
525     for ( i = 1; i <= sp->numitems; i++ )
526         if ( sp->mval[ i ] >= mval )
527             mval = sp->mval[ i ] + 1;
528 
529     fl_set_counter_value( menu_attrib->id, mval );
530 }
531 
532 
533 /***************************************
534  ***************************************/
535 
536 void
new_menuapi_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)537 new_menuapi_cb( FL_OBJECT * obj,
538                 long        data  FL_UNUSED_ARG )
539 {
540     SuperSPEC * ssp = curobj->u_vdata;
541 
542     ssp->new_menuapi = fl_get_button( obj );
543 
544     if ( ssp->new_menuapi )
545         fl_hide_object( menu_attrib->id );
546     else
547         fl_show_object( menu_attrib->id );
548 }
549 
550 
551 /***************************************
552  ***************************************/
553 
554 void
menuentry_scope_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)555 menuentry_scope_cb( FL_OBJECT * obj,
556                     long        data  FL_UNUSED_ARG )
557 {
558     ( ( SuperSPEC * ) curobj->u_vdata )->global_scope =
559                                           ( fl_get_choice( obj ) - 1 ) > 0;
560 }
561 
562 
563 #include "spec/menu_spec.c"
564 
565 
566 /*
567  * Local variables:
568  * tab-width: 4
569  * indent-tabs-mode: nil
570  * End:
571  */
572