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 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <string.h>
24 #include <ctype.h>
25
26 #include "fd_main.h"
27 #include "fd_spec.h"
28 #include "fd_iconinfo.h"
29
30
31 /* Pointer to object currently being edited */
32
33 static FL_OBJECT * curobj;
34
35 static void save_edited_object( FL_OBJECT * obj );
36 static void restore_edited_object( FL_OBJECT * obj );
37 static void attrib_init( FD_generic_attrib * ui );
38 static int validate_attributes( FL_OBJECT * obj );
39 static void readback_attributes( FL_OBJECT * obj );
40 static void copy_shortcut( FL_OBJECT * dest,
41 FL_OBJECT * src );
42 static void cleanup_saved_object( void );
43 static void show_attributes( const FL_OBJECT * obj );
44 static int valid_c_identifier( const char * s );
45 static void add_font_choice( const char * p );
46 static int validate_cvar_name( FL_OBJECT * obj,
47 const char * w );
48
49
50 /* Structuure for storing the initial state of the object */
51
52 static struct {
53 FL_OBJECT * obj;
54 char name[ MAX_VAR_LEN ];
55 char cbname[ MAX_VAR_LEN ];
56 char argname[ MAX_VAR_LEN ];
57 } saved_object;
58
59
60 /* Font sizes, need to do this because of symbolic names */
61
62 static FL_OBJECT *fnts;
63
64 typedef struct {
65 int size;
66 char * name,
67 * sc;
68 } Fsizes;
69
70 static Fsizes fsizes[ ] =
71 {
72 { FL_TINY_SIZE, "Tiny", "Tt#t" },
73 { FL_SMALL_SIZE, "Small", "Ss#s" },
74 { FL_NORMAL_SIZE, "Normal", "Nn#n" },
75 { FL_MEDIUM_SIZE, "Medium", "Mm#m" },
76 { FL_LARGE_SIZE, "Large", "Ll#l" },
77 { FL_HUGE_SIZE, "Huge", "Hh#h" },
78 { 11, "Variable", "" }
79 };
80
81 #define NFSIZE ( sizeof fsizes / sizeof *fsizes )
82
83 /* Character used for newline */
84
85 #define NL 0x0a
86
87
88
89 /***************************************
90 * Displays and do interaction with the form for changing object attributes.
91 * 'all' indicates whether label, name, etc. should also be changed and is
92 * only set when only a single object is to selected for changing.
93 ***************************************/
94
95 int
change_object(FL_OBJECT * obj,int all)96 change_object( FL_OBJECT * obj,
97 int all )
98 {
99 FL_OBJECT *retobj;
100 FD_generic_attrib *ui = fd_generic_attrib;
101 FL_FORM * spec_form = NULL;
102
103 attrib_init( ui );
104
105 /* Save current attributes for later restore */
106
107 curobj = obj;
108 save_edited_object( obj );
109
110 /* Show only required parts */
111
112 if ( all )
113 {
114 fl_show_object( ui->labelobj );
115 fl_show_object( ui->scobj );
116 fl_show_object( ui->nameobj );
117 fl_show_object( ui->cbnameobj );
118 fl_show_object( ui->argobj );
119
120 if ( ( spec_form = create_spec_form( curobj ) ) )
121 {
122 FL_OBJECT *t;
123
124 t = fl_addto_tabfolder( fd_attrib->attrib_folder,
125 "Spec", spec_form );
126 fl_set_object_shortcut( t, "#S", 1 );
127 }
128 }
129 else
130 {
131 fl_hide_object( ui->labelobj );
132 fl_hide_object( ui->scobj );
133 fl_hide_object( ui->nameobj );
134 fl_hide_object( ui->cbnameobj );
135 fl_hide_object( ui->argobj );
136 }
137
138 /* Show attributes of the current object */
139
140 show_attributes( obj );
141
142 /* Do interaction */
143
144 fl_deactivate_all_forms( );
145
146 /* Disable selection */
147
148 no_selection = 1;
149
150 fl_show_form( fd_attrib->attrib, FL_PLACE_GEOMETRY, FL_FULLBORDER,
151 "Attributes" );
152 fl_set_app_mainform( fd_attrib->attrib );
153
154 /* Both cancel and readyobj should have their own callbacks, so we don't
155 need to call fl_do_forms(), but since attribute editing can't be
156 invoked for more than one item at a time we need to block the
157 process_xevent. TODO */
158
159 do
160 {
161 XEvent xev;
162
163 retobj = fl_do_forms( );
164 if ( retobj == FL_EVENT )
165 fl_XNextEvent( &xev );
166 } while ( ! ( ( retobj == fd_attrib->readyobj
167 && validate_attributes( curobj ) )
168 || retobj == fd_attrib->cancelobj ) );
169
170 if ( retobj == fd_attrib->cancelobj )
171 {
172 restore_edited_object( obj );
173 redraw_the_form( 0 );
174 }
175 else
176 {
177 reread_spec_form( obj );
178 readback_attributes( obj );
179 spec_to_superspec( obj );
180 }
181
182 cleanup_saved_object( );
183
184 fl_set_app_mainform( fd_control->control );
185 fl_set_folder_bynumber( fd_attrib->attrib_folder, 1 );
186 if ( spec_form )
187 fl_delete_folder( fd_attrib->attrib_folder, spec_form );
188 fl_hide_form( fd_attrib->attrib );
189 fl_activate_all_forms( );
190
191 no_selection = 0;
192
193 return retobj == fd_attrib->readyobj;
194 }
195
196
197 /***************************************
198 * Called on switching between "Generic" and "Spec" folder
199 ***************************************/
200
201 void
folder_switch_cb(FL_OBJECT * obj,long data FL_UNUSED_ARG)202 folder_switch_cb( FL_OBJECT * obj,
203 long data FL_UNUSED_ARG )
204 {
205 int active = fl_get_active_folder_number(
206 ( ( FD_attrib * ) obj->form->fdui )->attrib_folder );
207
208 if ( active == 1 )
209 reread_spec_form( curobj );
210 else
211 {
212 readback_attributes( curobj );
213 prepare_spec_form( curobj );
214 }
215 }
216
217
218 /***************************************
219 * Callback for most of the objects for setting generic attributes
220 * (instead of having one for each of them) - evaluates the settings
221 * from all the objects in the generic attributes form and sets the
222 * object accordingly.
223 ***************************************/
224
225 void
apply_cb(FL_OBJECT * obj FL_UNUSED_ARG,long arg FL_UNUSED_ARG)226 apply_cb( FL_OBJECT * obj FL_UNUSED_ARG,
227 long arg FL_UNUSED_ARG )
228 {
229 readback_attributes( curobj );
230 show_attributes( curobj );
231 }
232
233
234 /***************************************
235 * Callback for the "Restore" button
236 ***************************************/
237
238 void
restore_cb(FL_OBJECT * ob FL_UNUSED_ARG,long data FL_UNUSED_ARG)239 restore_cb( FL_OBJECT * ob FL_UNUSED_ARG,
240 long data FL_UNUSED_ARG )
241 {
242 restore_edited_object( curobj );
243 show_attributes( curobj );
244 redraw_the_form( 0 );
245 }
246
247
248 /***************************************
249 * Stores all information about the initial settings of the object
250 * being edited (for restoring it)
251 ***************************************/
252
253 static void
save_edited_object(FL_OBJECT * obj)254 save_edited_object( FL_OBJECT * obj )
255 {
256 /* Get memory for the object to save and copy everything */
257
258 /* Now get memory for the saved object and store what it contains */
259
260 saved_object.obj = fl_malloc( sizeof *saved_object.obj );
261 *saved_object.obj = *obj;
262 saved_object.obj->spec = NULL;
263
264 /* Get the objects name, name of the callback function and
265 the argument string and store them */
266
267 get_object_name( obj, saved_object.name, saved_object.cbname,
268 saved_object.argname );
269
270 /* Now get memory for the saved object, store what it contains and
271 also save the label and the shortcut for real */
272
273 /* Make a copy of allocated memory in the obejct */
274
275 saved_object.obj->label = fl_strdup( obj->label );
276 copy_shortcut( saved_object.obj, obj );
277
278 saved_object.obj->u_vdata = saved_object.obj->c_vdata = NULL;
279
280 copy_superspec( saved_object.obj, obj );
281 copy_iconinfo( saved_object.obj, obj );
282 }
283
284
285 /***************************************
286 * Restores the object state to what it was when editing started
287 ***************************************/
288
289 static void
restore_edited_object(FL_OBJECT * obj)290 restore_edited_object( FL_OBJECT * obj )
291 {
292 void *sp = obj->spec;
293
294 fl_free( obj->label );
295 fl_free( obj->shortcut );
296
297 free_superspec( obj );
298 free_iconinfo( obj );
299
300 *obj = *saved_object.obj;
301 obj->spec = sp;
302
303 obj->label = fl_strdup( saved_object.obj->label );
304 copy_shortcut( obj, saved_object.obj );
305
306 obj->u_vdata = obj->c_vdata = NULL;
307
308 copy_superspec( obj, saved_object.obj );
309 superspec_to_spec( obj );
310
311 copy_iconinfo( obj, saved_object.obj );
312 restore_spec( obj );
313
314 set_object_name( obj, saved_object.name, saved_object.cbname,
315 saved_object.argname );
316
317 /* It the "Spec" folder is currently been shown set its content to
318 the restored object settings and redraw it */
319
320 if ( fl_get_active_folder_number( fd_attrib->attrib_folder ) == 2 )
321 {
322 prepare_spec_form( obj );
323 fl_redraw_object( fd_attrib->attrib_folder );
324 }
325 }
326
327
328 /***************************************
329 * Remove all data allocated in the structure for saving the objects
330 * initial state
331 ***************************************/
332
333 static void
cleanup_saved_object(void)334 cleanup_saved_object( void )
335 {
336 if ( ! saved_object.obj )
337 return;
338
339 fl_free( saved_object.obj->label );
340 fl_free( saved_object.obj->shortcut );
341 free_superspec( saved_object.obj );
342 free_iconinfo( saved_object.obj );
343 fli_safe_free( saved_object.obj );
344 }
345
346
347 /***************************************
348 * Initialize the form used for editing the objects attributes, needs to
349 * be run only once
350 ***************************************/
351
352 static void
attrib_init(FD_generic_attrib * ui)353 attrib_init( FD_generic_attrib * ui )
354 {
355 static int attrib_initialized;
356 int i;
357 VN_pair *vp;
358
359 if ( attrib_initialized )
360 return;
361
362 attrib_initialized = 1;
363
364 fl_clear_choice( ui->boxobj );
365 for ( i = 1, vp = vn_btype; vp->val >= 0; vp++, i++ )
366 {
367 fl_addto_choice( ui->boxobj, vp->shown );
368 fl_set_choice_item_shortcut( ui->boxobj, i, vp->hotkey );
369 }
370
371 fl_set_object_return( ui->nameobj, FL_RETURN_END );
372 fl_set_object_return( ui->cbnameobj, FL_RETURN_END );
373
374 /* Resize */
375
376 fl_set_choice_fontsize( ui->resize, fd_align_fontsize );
377 for ( vp = vn_resize; vp->val >= 0; vp++ )
378 fl_addto_choice( ui->resize, vp->name + 3 );
379
380 /* Gravity. Due to compatibility issues there are more than is needed
381 in vn_gravity */
382
383 for ( i = 0, vp = vn_gravity; vp->val >= 0 && i < 9; vp++, i++ )
384 {
385 fl_addto_choice( ui->nwgravity, vp->name + 3 );
386 fl_addto_choice( ui->segravity, vp->name + 3 );
387 }
388
389 /* Align (only show the first 9 elements of 'vn_align' the rest is
390 in there for backward compatibility reasons when reading in a file) */
391
392 fl_set_choice_fontsize( ui->align, fd_align_fontsize );
393 for ( vp = vn_align, i = 0; vp->val >= 0 && i < 9; vp++, i++ )
394 fl_addto_choice( ui->align, vp->name + 9 );
395 fl_addto_choice( ui->inside, "Inside|Outside" );
396
397 /* Font stuff */
398
399 fnts = ui->fontobj;
400 fl_enumerate_fonts( add_font_choice, 1 );
401 fl_addto_choice( ui->styleobj, "Normal|Shadow|Engraved|Embossed" );
402
403 /* Size */
404
405 for ( i = 0; i < ( int ) NFSIZE; i++ )
406 {
407 if ( fsizes[ i ].size == FL_NORMAL_SIZE )
408 {
409 fsizes[ i ].name = "Normal";
410 fsizes[ i ].sc = "Nn#n";
411 }
412
413 fl_addto_choice_f( ui->sizeobj,
414 "%2d %s%%r1", fsizes[ i ].size, fsizes[ i ].name );
415 fl_set_choice_item_shortcut( ui->sizeobj, i + 1, fsizes[ i ].sc );
416 }
417 }
418
419
420 /***************************************
421 * Sets up the "Generic" attributes form with the properties of the
422 * object currently being edited
423 ***************************************/
424
425 static void
show_attributes(const FL_OBJECT * obj)426 show_attributes( const FL_OBJECT * obj )
427 {
428 char objname[ MAX_VAR_LEN ],
429 cbname[ MAX_VAR_LEN ],
430 argname[ MAX_VAR_LEN ];
431 char *label;
432 int i,
433 lstyle,
434 spstyle,
435 oksize,
436 align = fl_to_outside_lalign( obj->align );
437 static char othersize[ 32 ];
438
439 fl_freeze_form( fd_generic_attrib->generic_attrib );
440
441 /* Fill in list of types */
442
443 fl_clear_choice( fd_generic_attrib->typeobj );
444 fl_set_choice_fontsize( fd_generic_attrib->typeobj, fd_type_fontsize );
445
446 if ( obj->objclass != FL_BOX )
447 {
448 for ( i = 0; i < find_class_maxtype( obj->objclass ); i++ )
449 fl_addto_choice_f( fd_generic_attrib->typeobj,
450 "%s%%r1", find_type_name( obj->objclass, i ) );
451
452 fl_set_choice( fd_generic_attrib->typeobj, obj->type + 1 );
453 }
454
455 /* Fill in settings */
456
457 /* a) boxtype */
458
459 fl_set_choice( fd_generic_attrib->boxobj, obj->boxtype + 1 );
460
461 /* b) label alignment */
462
463 fl_set_choice_text( fd_generic_attrib->align, align_name( align, 0 ) + 9 );
464 fl_set_choice( fd_generic_attrib->inside,
465 fl_is_outside_lalign( obj->align ) + 1 );
466
467 /* c) label font and style */
468
469 lstyle = obj->lstyle % FL_SHADOW_STYLE;
470 spstyle = obj->lstyle / FL_SHADOW_STYLE;
471
472 if ( spstyle >= 3 )
473 spstyle = 3;
474
475 fl_set_choice( fd_generic_attrib->fontobj, lstyle + 1 );
476 fl_set_choice( fd_generic_attrib->styleobj, spstyle + 1 );
477
478 /* d) label font size */
479
480 for ( oksize = i = 0; ! oksize && i < ( int ) NFSIZE; i++ )
481 if ( ( oksize = ( obj->lsize == fsizes[ i ].size ) ) )
482 fl_set_choice( fd_generic_attrib->sizeobj, i + 1 );
483
484 if ( ! oksize )
485 {
486 sprintf( othersize, "%d (Variable)", obj->lsize );
487 fsizes[ NFSIZE - 1 ].size = obj->lsize;
488 fsizes[ NFSIZE - 1 ].name = othersize;
489 fl_replace_choice( fd_generic_attrib->sizeobj, NFSIZE, othersize );
490 fl_set_choice( fd_generic_attrib->sizeobj, NFSIZE );
491 }
492
493 /* e) gravity settings */
494
495 fl_set_choice_text( fd_generic_attrib->nwgravity,
496 gravity_name( obj->nwgravity ) + 3 );
497 fl_set_choice_text( fd_generic_attrib->segravity,
498 gravity_name( obj->segravity ) + 3 );
499
500 /* f) resize behaviour */
501
502 fl_set_choice_text( fd_generic_attrib->resize,
503 resize_name( obj->resize ) + 3 );
504
505 /* g) Label string */
506
507 label = get_label( obj, 0 );
508 fl_set_input( fd_generic_attrib->labelobj, label );
509 fl_free( label );
510
511 /* h) name, callback function name and argument */
512
513 get_object_name( obj, objname, cbname, argname );
514
515 fl_set_input( fd_generic_attrib->nameobj, objname );
516 fl_set_input( fd_generic_attrib->cbnameobj, cbname );
517 fl_set_input( fd_generic_attrib->argobj, argname );
518
519 /* h) shortcut */
520
521 fl_set_input( fd_generic_attrib->scobj, get_shortcut_string( obj ) );
522
523 /* i) object and label colors */
524
525 fl_set_object_color( fd_generic_attrib->col1obj, obj->col1, obj->col1 );
526 fl_set_object_color( fd_generic_attrib->col2obj, obj->col2, obj->col2 );
527 fl_set_object_color( fd_generic_attrib->lcolobj, obj->lcol, obj->lcol );
528
529 fl_unfreeze_form( fd_generic_attrib->generic_attrib );
530 }
531
532
533 /***************************************
534 * Sets the objects attributes from the content of the "Generic" attributes
535 * form
536 ***************************************/
537
538 static void
readback_attributes(FL_OBJECT * obj)539 readback_attributes( FL_OBJECT * obj )
540 {
541 int v1, v2;
542 char * name,
543 * cbname;
544 char tmpbuf[ 128 ];
545
546 obj->boxtype = fl_get_choice( fd_generic_attrib->boxobj ) - 1;
547
548 /* Take care: for some objects the "Type" choice is empty! */
549
550 if ( ( v1 = fl_get_choice( fd_generic_attrib->typeobj ) - 1 ) >= 0
551 && v1 != obj->type )
552 spec_change_type( obj, v1 );
553
554 /* Label style consists of two parts */
555
556 v1 = fl_get_choice( fd_generic_attrib->fontobj ) - 1;
557 v2 = fl_get_choice( fd_generic_attrib->styleobj ) - 1;
558 v1 += v2 == 3 ? FL_EMBOSSED_STYLE : ( v2 * FL_SHADOW_STYLE );
559 fl_set_object_lstyle( obj, v1 );
560
561 fl_set_object_color( obj, fd_generic_attrib->col1obj->col1,
562 fd_generic_attrib->col2obj->col1 );
563
564 fl_set_object_lcol( obj, fd_generic_attrib->lcolobj->col1 );
565
566 sprintf( tmpbuf, "FL_ALIGN_%s",
567 fl_get_choice_text( fd_generic_attrib->align ) );
568 v1 = align_val( tmpbuf );
569
570 if ( fl_get_choice( fd_generic_attrib->inside ) == 1 )
571 v1 = fl_to_inside_lalign( v1 );
572 else
573 v1 = fl_to_outside_lalign( v1 );
574
575 fl_set_object_lalign( obj, v1 );
576
577 sprintf( tmpbuf, "FL_%s",
578 fl_get_choice_text( fd_generic_attrib->nwgravity ) );
579 v1 = gravity_val( tmpbuf );
580
581 sprintf( tmpbuf, "FL_%s",
582 fl_get_choice_text( fd_generic_attrib->segravity ) );
583 v2 = gravity_val( tmpbuf );
584
585 fl_set_object_gravity( obj, v1, v2 );
586
587 /* Set resize property after making sure it fits with the gravity
588 settings */
589
590 sprintf( tmpbuf, "FL_%s", fl_get_choice_text( fd_generic_attrib->resize ) );
591 fl_set_object_resize( obj, check_resize( resize_val( tmpbuf ),
592 obj->nwgravity, obj->segravity ) );
593
594 fl_set_object_lsize( obj, fsizes[ fl_get_choice(
595 fd_generic_attrib->sizeobj ) - 1 ].size );
596
597 set_label( obj, fl_get_input( fd_generic_attrib->labelobj ) );
598 set_shortcut( obj, fl_get_input( fd_generic_attrib->scobj ) );
599
600 name = fl_strdup( fl_get_input( fd_generic_attrib->nameobj ) );
601 cbname = fl_strdup( fl_get_input( fd_generic_attrib->cbnameobj ) );
602
603 if ( ! valid_c_identifier( name ) )
604 *name = '\0';
605
606 if ( ! valid_c_identifier( cbname ) )
607 *cbname = '\0';
608
609 set_object_name( obj, name, cbname,
610 fl_get_input( fd_generic_attrib->argobj ) );
611
612 fl_free( cbname );
613 fl_free( name );
614
615 redraw_the_form( 0 );
616 }
617
618
619 /***************************************
620 * Turns the string from the label input field into a string suitable for
621 * an object label (taking care of newlines and shortcut markers) and
622 * the sets the label of the object being edited.
623 ***************************************/
624
625 void
set_label(FL_OBJECT * obj,const char * str)626 set_label( FL_OBJECT * obj,
627 const char * str )
628 {
629 int i = 0,
630 j = 0;
631 char *tmpstr = fl_malloc( strlen( str ) + 1 );
632
633 *tmpstr = '\0';
634
635 do
636 {
637 if ( str[ i ] == '\\' && str[ i + 1 ] == 'n' )
638 {
639 tmpstr[ j++ ] = NL;
640 i++;
641 }
642 else if ( str[ i ] == '\\' && strncmp( str + i + 1, "010", 3 ) == 0 )
643 {
644 if ( ! obj->shortcut || ! *obj->shortcut )
645 tmpstr[ j++ ] = *fl_ul_magic_char;
646 i += 3;
647 }
648 else
649 tmpstr[ j++ ] = str[ i ];
650 } while ( str[ i++ ] );
651
652 fl_set_object_label( obj, tmpstr );
653 fl_free( tmpstr );
654 }
655
656
657 /***************************************
658 * Sets the shortcut of the object being edited.
659 ***************************************/
660
661 void
set_shortcut(FL_OBJECT * obj,const char * sc)662 set_shortcut( FL_OBJECT * obj,
663 const char * sc )
664 {
665 if ( obj->type != FL_RETURN_BUTTON
666 && obj->type != FL_HIDDEN_RET_BUTTON )
667 fl_set_object_shortcut( obj, sc, 1 );
668 }
669
670
671 /* if \ preceeds c, \ does not need quote */
672
673 #define Ok( c ) \
674 ( c== '"' || c== '\\' || c == 't' || c == 'n' \
675 || isdigit( ( unsigned char ) c ) )
676
677
678 /***************************************
679 * Decides if label need quotes ('\')
680 ***************************************/
681
682 static int
need_quote(const char * s,int i)683 need_quote( const char * s,
684 int i )
685 {
686 int c = s[ i ],
687 p = i ? s[ i - 1 ] : 0, /* prev char */
688 n = *s ? s[ i + 1 ] : 0; /* next char */
689
690 if ( c == '"' && p != '\\' )
691 return 1;
692 else if ( c == '\\' && p != '\\' )
693 return ! isdigit( ( unsigned char ) n ) && ! Ok( n );
694 else
695 return 0;
696 }
697
698
699 /***************************************
700 * Takes an objects label string and converts it into a string suitable
701 * for setting as the content of the label input field
702 ***************************************/
703
704 char *
get_label(const FL_OBJECT * obj,int c_source)705 get_label( const FL_OBJECT * obj,
706 int c_source )
707 {
708 int i = 0,
709 j = 0;
710 const char *label = obj->label;
711 int len = strlen( label );
712 int tlen = len + 1;
713 char *tmpstr = fl_malloc( tlen );
714
715 for ( i = 0; i < len; i++ )
716 {
717 if ( label[ i ] == NL )
718 {
719 tmpstr = fl_realloc( tmpstr, tlen += 1 );
720 tmpstr[ j++ ] = '\\';
721 tmpstr[ j++ ] = 'n';
722 }
723 else if ( label[ i ] == *fl_ul_magic_char )
724 {
725 if ( ! obj->shortcut || ! *obj->shortcut )
726 {
727 tmpstr = fl_realloc( tmpstr, tlen += 3 );
728 tmpstr[ j++ ] = '\\';
729 tmpstr[ j++ ] = '0';
730 tmpstr[ j++ ] = '1';
731 tmpstr[ j++ ] = '0';
732 }
733 }
734 else if ( c_source && need_quote( label, i ) )
735 {
736 tmpstr = fl_realloc( tmpstr, tlen += 1 );
737 tmpstr[ j++ ] = '\\';
738 tmpstr[ j++ ] = label[ i ];
739 }
740 else
741 tmpstr[ j++ ] = label[ i ];
742 }
743
744 tmpstr[ j ] = '\0';
745
746 return tmpstr;
747 }
748
749
750 /***************************************
751 * Convert shortcut into string representation.
752 * ESC -> ^[, F1 -> &1 etc.
753 ***************************************/
754
755 static int
special_key(int key,char * outbuf)756 special_key( int key,
757 char * outbuf )
758 {
759 char *start = outbuf;
760
761 if ( key >= XK_F1 && key <= XK_F30 )
762 {
763 int p = ( key - XK_F1 + 1 ) / 10,
764 q = ( key - XK_F1 + 1 ) % 10;
765
766 *outbuf++ = '&';
767 if ( p )
768 *outbuf++ = '0' + p;
769 *outbuf++ = '0' + q;
770 }
771 else if ( IsUp( key ) )
772 {
773 *outbuf++ = '&';
774 *outbuf++ = 'A';
775 }
776 else if ( IsDown( key ) )
777 {
778 *outbuf++ = '&';
779 *outbuf++ = 'B';
780 }
781 else if ( IsRight( key ) )
782 {
783 *outbuf++ = '&';
784 *outbuf++ = 'C';
785 }
786 else if ( IsLeft( key ) )
787 {
788 *outbuf++ = '&';
789 *outbuf++ = 'D';
790 }
791 else
792 *outbuf++ = key;
793
794 *outbuf = '\0';
795
796 return outbuf - start;
797 }
798
799
800 /***************************************
801 * Converts the objects shortcut string into a string suitable for
802 * setting as the content of the shortcut input object
803 ***************************************/
804
805 char *
get_shortcut_string(const FL_OBJECT * obj)806 get_shortcut_string( const FL_OBJECT * obj )
807 {
808 static char tmps[ 127 ];
809 char *p = tmps;
810 long *sc = obj->shortcut;
811 int n;
812
813 for ( *p = '\0'; sc && *sc; sc++ )
814 {
815 if ( *sc >= FL_ALT_MASK )
816 {
817 *p++ = '#';
818 n = special_key( *sc - FL_ALT_MASK, p );
819 p += n;
820 }
821 else if ( *sc == '#' || *sc == '&' || *sc == '^' ) /* prefixed w/ ^ */
822 {
823 *p++ = '^';
824 *p++ = *sc;
825 }
826 else if ( *sc < 30 )
827 {
828 *p++ = '^';
829 if ( *sc <= 'Z' )
830 *p++ = 'A' + *sc - 1;
831 else if ( *sc == 27 ) /* Escape */
832 *p++ = '[';
833 }
834 else if ( *sc > 255 )
835 {
836 n = special_key( *sc, p );
837 p += n;
838 }
839 else
840 *p++ = *sc;
841 }
842
843 *p = '\0';
844
845 return tmps;
846 }
847
848
849 /***************************************
850 * Callback for fl_enumerate_fonts() used in intializing the form
851 ***************************************/
852
853 static void
add_font_choice(const char * p)854 add_font_choice( const char * p )
855 {
856 fl_addto_choice( fnts, p );
857 }
858
859
860 /***************************************
861 * Callback routine for getting a color from the user
862 ***************************************/
863
864 void
setcolor_cb(FL_OBJECT * obj,long arg FL_UNUSED_ARG)865 setcolor_cb( FL_OBJECT * obj,
866 long arg FL_UNUSED_ARG )
867 {
868 int col1 = fl_show_colormap( obj->col1 );
869
870 fl_set_object_color( obj, col1, col1 );
871 readback_attributes( curobj );
872 }
873
874
875 /***************************************
876 * Validates the name of the object and the callback function
877 ***************************************/
878
879 static int
validate_attributes(FL_OBJECT * obj)880 validate_attributes( FL_OBJECT * obj )
881 {
882 FL_OBJECT *o;
883 const char *name,
884 *cn;
885
886 if ( ! validate_cvar_name( fd_generic_attrib->nameobj, "object name" )
887 || ! validate_cvar_name( fd_generic_attrib->cbnameobj, "callback" ) )
888 return 0;
889
890 name = fl_get_input( fd_generic_attrib->nameobj );
891
892 if ( ! name || ! *name )
893 return 1;
894
895 /* Make sure the name diesn't clash with its forms name */
896
897 if ( ( cn = get_form_name( obj->form ) ) && ! strcmp( name, cn ) )
898 {
899 fl_show_alert( "Error", "Invalid C identifier:",
900 "Object has same name as the form it belongs to!", 0 );
901 fl_set_focus_object( fd_generic_attrib->nameobj->form,
902 fd_generic_attrib->nameobj );
903 return 0;
904 }
905
906 /* Make sure the name doesn clash with the name of another object in
907 the form it belongs to */
908
909 for ( o = obj->form->first; o; o = o->next )
910 if ( o != obj
911 && ( cn = get_object_c_name( o ) )
912 && ! strcmp( name, cn ) )
913 {
914 fl_show_alert( "Error", "Invalid C identifier:",
915 "Object has sam name as another one!", 0 );
916 fl_set_focus_object( fd_generic_attrib->nameobj->form,
917 fd_generic_attrib->nameobj );
918 return 0;
919 }
920
921 return 1;
922 }
923
924
925 /***************************************
926 ***************************************/
927
928 void
validate_cvar_name_cb(FL_OBJECT * obj,long data)929 validate_cvar_name_cb( FL_OBJECT * obj,
930 long data )
931 {
932 validate_cvar_name( obj, data == 0 ? "object name" : "callback" );
933 }
934
935
936 /***************************************
937 * Checks if the string of an input field is a valid C indentifier
938 ***************************************/
939
940 static int
validate_cvar_name(FL_OBJECT * obj,const char * w)941 validate_cvar_name( FL_OBJECT * obj,
942 const char * w )
943 {
944 const char *s = fl_get_input( obj );
945
946 if ( valid_c_identifier( s ) )
947 return 1;
948
949 /* If something's wrong switch to the form with the generic attributs,
950 since there's were the input fields with the name and the callback
951 function are */
952
953 fl_set_folder_bynumber( fd_attrib->attrib_folder, 1 );
954
955 if ( ! w || ! *w )
956 fl_show_alert_f( 0, "Error\fInvalid C identifier:\n'%s'", s );
957 else
958 fl_show_alert_f( 0, "Error\fInvalid C identifier\nfor %s: '%s'", w, s );
959
960 fl_set_focus_object( obj->form, obj );
961 return 0;
962 }
963
964
965 /* Check for obvious errors */
966
967 #define OK_letter( c ) ( *c == '_' \
968 || *c == '[' \
969 || *c == ']' \
970 || * c== '.' \
971 || ( *c == ':' && *++c == ':' ) \
972 || ( *c == '-' && *++c == '>' ) )
973
974
975 /***************************************
976 ***************************************/
977
978 static int
valid_c_identifier(const char * s)979 valid_c_identifier( const char * s )
980 {
981 if ( fdopt.lax )
982 return 1;
983
984 /* Empty is considered to be valid */
985
986 if ( ! s || ! *s || ( *s == ' ' && *( s + 1 ) == '\0' ) )
987 return 1;
988
989 if ( ! isalpha( ( unsigned char ) *s ) && *s != '_' )
990 return 0;
991
992 for ( s++; *s; s++ )
993 if ( ! isalnum( ( unsigned char ) *s ) && ! OK_letter( s ) )
994 return 0;
995
996 return 1;
997 }
998
999
1000 /***************************************
1001 ***************************************/
1002
1003 static void
copy_shortcut(FL_OBJECT * dest,FL_OBJECT * src)1004 copy_shortcut( FL_OBJECT * dest,
1005 FL_OBJECT * src )
1006 {
1007 if ( src->shortcut )
1008 {
1009 size_t i = 0;
1010
1011 while ( src->shortcut[ i++ ] )
1012 /* empty */ ;
1013
1014 if ( i )
1015 {
1016 dest->shortcut = malloc( i * sizeof *dest->shortcut );
1017 memcpy( dest->shortcut, src->shortcut, i * sizeof *dest->shortcut );
1018 }
1019 }
1020 else
1021 dest->shortcut = NULL;
1022 }
1023
1024
1025 /*
1026 * Local variables:
1027 * tab-width: 4
1028 * indent-tabs-mode: nil
1029 * End:
1030 */
1031