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 tabfolder.c
21  *
22  *  This file is part of the XForms library package.
23  *  Copyright (c) 1997-2002  By T.C. Zhao
24  *  All rights reserved.
25  *
26  * tabbed folder
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "include/forms.h"
34 #include "flinternal.h"
35 #include "private/flvasprintf.h"
36 
37 typedef struct {
38     FL_OBJECT  * canvas;
39     FL_OBJECT  * parent;            /* the tabfolder object         */
40     FL_FORM   ** forms;             /* the folders                  */
41     FL_OBJECT ** title;             /* the associted tab            */
42     int          nforms;            /* number of folders            */
43     int          active_folder;     /* current active folder        */
44     int          last_active;       /* the previous active folder   */
45     int          x,
46                  y;
47     int          max_h;
48     int          h_pad,
49                  v_pad;
50     int          processing_destroy;
51     int          auto_fit;
52     int          offset;
53     int          num_visible;
54 } FLI_TABFOLDER_SPEC;
55 
56 
57 static void compute_position( FL_OBJECT * );
58 static void switch_folder( FL_OBJECT *,
59                            long );
60 static void program_switch( FL_OBJECT *,
61                             int );
62 static void get_tabsize( FL_OBJECT *,
63                          const char *,
64                          int *,
65                          int *,
66                          int );
67 static void shift_tabs( FL_OBJECT *,
68                         int left );
69 
70 #define IsFolderClass( ob ) ( ( ob ) && ( ob )->objclass == FL_TABFOLDER )
71 
72 
73 /***************************************
74  ***************************************/
75 
76 static int
handle_tabfolder(FL_OBJECT * ob,int event,FL_Coord mx FL_UNUSED_ARG,FL_Coord my FL_UNUSED_ARG,int key FL_UNUSED_ARG,void * ev)77 handle_tabfolder( FL_OBJECT * ob,
78                   int         event,
79                   FL_Coord    mx   FL_UNUSED_ARG,
80                   FL_Coord    my   FL_UNUSED_ARG,
81                   int         key  FL_UNUSED_ARG,
82                   void      * ev )
83 {
84     FL_FORM *folder;
85     FLI_TABFOLDER_SPEC *sp = ob->spec;
86 
87     switch ( event )
88     {
89         case FL_RESIZED:
90             if (    ( folder = fl_get_active_folder( ob ) )
91                  && sp->auto_fit != FL_NO )
92             {
93                 if ( sp->auto_fit == FL_FIT )
94                     fl_set_form_size( folder, sp->canvas->w, sp->canvas->h );
95                 else if (    folder->w < sp->canvas->w
96                           || folder->h < sp->canvas->h )
97                     fl_set_form_size( folder, sp->canvas->w, sp->canvas->h );
98             }
99             break;
100 
101         case FL_MOVEORIGIN:
102             if ( ( folder = fl_get_active_folder( ob ) ) )
103             {
104                 fl_get_winorigin( folder->window, &folder->x, &folder->y );
105 
106                 /* Don't forget nested folders */
107 
108                 fli_handle_form( folder, FL_MOVEORIGIN, 0, ev );
109             }
110             break;
111 
112         case FL_DRAW:
113             fl_set_object_boxtype( sp->canvas,
114                                    fli_boxtype2frametype( ob->boxtype ) );
115             sp->processing_destroy = 0;
116             compute_position( ob );
117             break;
118 
119         case FL_FREEMEM:
120             fli_safe_free( sp->forms );
121             fli_safe_free( sp->title );
122             fl_free( sp );
123             break;
124     }
125 
126     return 0;
127 }
128 
129 
130 /***************************************
131  * Canvas expose handler.
132  ***************************************/
133 
134 static int
canvas_handler(FL_OBJECT * ob,Window win FL_UNUSED_ARG,int w FL_UNUSED_ARG,int h FL_UNUSED_ARG,XEvent * ev FL_UNUSED_ARG,void * data FL_UNUSED_ARG)135 canvas_handler( FL_OBJECT * ob,
136                 Window      win   FL_UNUSED_ARG,
137                 int         w     FL_UNUSED_ARG,
138                 int         h     FL_UNUSED_ARG,
139                 XEvent    * ev    FL_UNUSED_ARG,
140                 void      * data  FL_UNUSED_ARG )
141 {
142     FLI_TABFOLDER_SPEC *sp = ob->u_vdata;
143 
144     /* sp->nforms can be zero */
145 
146     if ( sp->nforms == 0 || sp->active_folder >= sp->nforms )
147         return 0;
148 
149     if ( sp->active_folder >= 0 )   /* regular exposure, not first time */
150         program_switch( sp->title[ sp->active_folder ], sp->active_folder );
151     else if ( sp->last_active >= 0 && sp->last_active < sp->nforms )
152         program_switch( sp->title[ sp->last_active ], sp->last_active );
153 
154     return 0;
155 }
156 
157 
158 /***************************************
159  * Before canvas is destroyed this routine will be called where
160  * we need to close the form that is attached to this canvas
161  ***************************************/
162 
163 static int
canvas_cleanup(FL_OBJECT * ob)164 canvas_cleanup( FL_OBJECT * ob )
165 {
166     FLI_TABFOLDER_SPEC *sp = ob->u_vdata;
167 
168     if ( sp->active_folder >= 0 && sp->active_folder < sp->nforms )
169     {
170         sp->processing_destroy = 1;
171         if ( sp->forms[ sp->active_folder ]->visible == FL_VISIBLE )
172             fl_hide_form( sp->forms[ sp->active_folder ] );
173 
174         sp->last_active = sp->active_folder;
175 
176         if ( sp->active_folder >= 0 )
177             fl_set_object_boxtype( sp->title[ sp->active_folder ],
178                                    ob->parent->type != FL_BOTTOM_TABFOLDER ?
179                                    FL_TOPTAB_UPBOX : FL_BOTTOMTAB_UPBOX );
180         sp->active_folder = -1;
181     }
182 
183     return 0;
184 }
185 
186 
187 /***************************************
188  * For all the folders set a dummy form callback to prevent
189  * the contained objects from leaking thru to fl_do_forms
190  ***************************************/
191 
192 static void
form_cb(FL_OBJECT * ob FL_UNUSED_ARG,void * data FL_UNUSED_ARG)193 form_cb( FL_OBJECT * ob    FL_UNUSED_ARG,
194          void      * data  FL_UNUSED_ARG )
195 {
196 }
197 
198 
199 /***************************************
200  ***************************************/
201 
202 FL_OBJECT *
fl_create_tabfolder(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)203 fl_create_tabfolder( int          type,
204                      FL_Coord     x,
205                      FL_Coord     y,
206                      FL_Coord     w,
207                      FL_Coord     h,
208                      const char * label )
209 {
210     FL_OBJECT *ob;
211     FLI_TABFOLDER_SPEC *sp;
212     int absbw,
213         oldu = fl_get_coordunit( );;
214 
215     ob = fl_make_object( FL_TABFOLDER, type, x, y, w, h, label,
216                          handle_tabfolder );
217     fl_set_coordunit( FL_COORD_PIXEL );
218 
219     ob->boxtype = FL_UP_BOX;
220     ob->spec    = sp  = fl_calloc( 1, sizeof *sp );
221 
222     absbw = FL_abs( ob->bw );
223 
224     sp->parent = ob;
225     sp->forms = NULL;
226     sp->title = NULL;
227     sp->x = ob->x + absbw;
228     sp->y = ob->y + absbw;
229     sp->h_pad = 12;
230     sp->v_pad = 5;
231     sp->auto_fit = FL_NO;
232 
233     sp->canvas = fl_create_canvas( FL_SCROLLED_CANVAS, sp->x, sp->y,
234                                    ob->w - 2 * absbw,
235                                    ob->h - 2 * absbw, label ? label : "tab" );
236 
237     sp->canvas->u_vdata = sp;
238     fl_modify_canvas_prop( sp->canvas, 0, 0, canvas_cleanup );
239     fl_set_object_boxtype( sp->canvas,
240                            fli_boxtype2frametype( ob->boxtype ) );
241     fl_add_canvas_handler( sp->canvas, Expose, canvas_handler, 0 );
242 
243     fl_set_object_color( sp->canvas, ob->col1, ob->col2 );
244     fl_set_object_bw( sp->canvas, ob->bw );
245     fl_set_object_gravity( sp->canvas, ob->nwgravity, ob->segravity );
246     fl_set_coordunit( oldu );
247 
248     fl_add_child( ob, sp->canvas );
249 
250     fl_set_object_return( ob, FL_RETURN_END_CHANGED );
251 
252     return ob;
253 }
254 
255 
256 /***************************************
257  ***************************************/
258 
259 FL_OBJECT *
fl_add_tabfolder(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * l)260 fl_add_tabfolder( int          type,
261                   FL_Coord     x,
262                   FL_Coord     y,
263                   FL_Coord     w,
264                   FL_Coord     h,
265                   const char * l )
266 {
267     FL_OBJECT *obj = fl_create_tabfolder( type, x, y, w, h, l );
268 
269     /* Set the default return policy for the object */
270 
271     fl_add_object( fl_current_form, obj );
272     return obj;
273 }
274 
275 
276 /***************************************
277  ***************************************/
278 
279 void
fli_detach_form(FL_FORM * form)280 fli_detach_form( FL_FORM * form )
281 {
282     form->attached = 0;
283     if ( form->parent && form->parent->child == form )
284         form->parent->child = 0;
285     form->parent = NULL;
286 }
287 
288 
289 /***************************************
290  ***************************************/
291 
292 int
fl_get_tabfolder_numfolders(FL_OBJECT * ob)293 fl_get_tabfolder_numfolders( FL_OBJECT * ob )
294 {
295     return ( ( FLI_TABFOLDER_SPEC * ) ob->spec )->nforms;
296 }
297 
298 
299 /***************************************
300  * Tab is switched by the application, no need to invoke the callback
301  * or report back to the user
302  ***************************************/
303 
304 static void
program_switch(FL_OBJECT * obj,int folder)305 program_switch( FL_OBJECT * obj,
306                 int         folder )
307 {
308     FLI_TABFOLDER_SPEC *sp;
309 
310     if ( folder >= 0 )
311     {
312         sp = obj->u_vdata;
313         switch_folder( obj, folder );
314         obj->parent->returned = FL_RETURN_NONE;
315 
316         /* This handles set_folder while hidden */
317 
318         if ( ! obj->visible || ! obj->form->visible == FL_VISIBLE )
319             sp->last_active = folder;
320     }
321 }
322 
323 
324 /***************************************
325  ***************************************/
326 
327 static void
switch_folder(FL_OBJECT * ob,long data)328 switch_folder( FL_OBJECT * ob,
329                long        data )
330 {
331     FLI_TABFOLDER_SPEC *sp = ob->u_vdata;
332     FL_FORM *form;
333     Window win;
334     FL_OBJECT *bkob;
335 
336     if ( data < 0 || data >= sp->nforms )
337     {
338         M_err( "switch_folder", "Invalid index");
339         return;
340     }
341 
342     form = sp->forms[ data ];
343 
344     if (    data == sp->active_folder
345          && sp->active_folder >= 0
346          && ! sp->processing_destroy
347          && (    ob->parent->how_return == FL_RETURN_ALWAYS
348               || ob->parent->how_return == FL_RETURN_END ) )
349     {
350         ob->parent->returned |= FL_RETURN_END;
351 
352 #if USE_BWC_BS_HACK
353         if ( ! ob->parent->object_callback )
354             ob->parent->returned &= ~ FL_RETURN_END;
355 #endif
356     }
357 
358     if ( data == sp->active_folder || sp->processing_destroy )
359     {
360         sp->processing_destroy = 0;
361         return;
362     }
363 
364     if ( ! ob->form->window || ! FL_ObjWin( sp->canvas ) )
365         return;
366 
367     if ( sp->auto_fit != FL_NO )
368     {
369         if ( sp->auto_fit == FL_FIT )
370             fl_set_form_size( form, sp->canvas->w, sp->canvas->h );
371         else if ( form->w < sp->canvas->w || form->h < sp->canvas->h )
372             fl_set_form_size( form, sp->canvas->w, sp->canvas->h );
373     }
374 
375     /* We may have more tabs than can be shown */
376 
377     if ( sp->num_visible < sp->nforms - 1 || sp->offset )
378     {
379         if ( ( data && data == sp->offset ) || data > sp->num_visible )
380         {
381             int last;
382 
383             shift_tabs( ob, data == sp->offset ? -1 : 1 );
384             sp->title[ data ]->boxtype &= ~ FLI_BROKEN_BOX;
385             sp->title[ data ]->align = FL_ALIGN_CENTER;
386             last = sp->num_visible + sp->offset + 1;
387             last = FL_clamp( last, 0, sp->nforms - 1 );
388             sp->title[ last ]->boxtype |= FLI_BROKEN_BOX;
389             sp->title[ last ]->align = fl_to_inside_lalign( FL_ALIGN_LEFT );
390             fl_redraw_form( ob->form );
391         }
392     }
393 
394     win = fl_prepare_form_window( form, 0, FL_NOBORDER, "Folder" );
395 
396     /* win reparent eats the reparent event */
397 
398     fl_winreparent( win, FL_ObjWin( sp->canvas ) );
399     form->parent_obj = ob;
400     fl_show_form_window( form );
401 
402     /* Need to redraw the last selected folder tab */
403 
404     if (    sp->active_folder >= 0
405          && sp->forms[ sp->active_folder ]->visible == FL_VISIBLE )
406     {
407         FL_OBJECT *actobj;
408 
409         actobj = sp->title[ sp->active_folder ];
410         actobj->col1 = sp->parent->col1;
411 
412         fl_set_object_boxtype( actobj,
413                                ob->parent->type != FL_BOTTOM_TABFOLDER ?
414                                FL_TOPTAB_UPBOX : FL_BOTTOMTAB_UPBOX );
415 
416         fl_draw_frame( FL_UP_FRAME, sp->canvas->x, sp->canvas->y, sp->canvas->w,
417                        sp->canvas->h, sp->canvas->col1, sp->canvas->bw );
418         fl_hide_form( sp->forms[ sp->active_folder ] );
419         sp->forms[ sp->active_folder ]->parent_obj = NULL;
420         sp->last_active = sp->active_folder;
421     }
422 
423     form->parent = ob->form;
424     ob->form->child = form;
425 
426     /* Find out the color of the new form */
427 
428     if ( ( bkob = form->first ) && bkob->type == FL_NO_BOX )
429         bkob = bkob->next;
430 
431     if ( bkob )
432         fl_set_object_color( ob, bkob->col1, ob->col2 );
433 
434     fl_set_object_boxtype( ob, ob->parent->type != FL_BOTTOM_TABFOLDER ?
435                            FL_SELECTED_TOPTAB_UPBOX :
436                            FL_SELECTED_BOTTOMTAB_UPBOX );
437 
438     if (    sp->active_folder >= 0 )
439     {
440         ob->parent->returned = FL_RETURN_END | FL_RETURN_CHANGED;
441 
442 #if USE_BWC_BS_HACK
443         if ( ! ob->parent->object_callback )
444             ob->parent->returned &= ~ ( FL_RETURN_END | FL_RETURN_CHANGED );
445 #endif
446     }
447 
448     sp->active_folder = data;
449 }
450 
451 
452 /***************************************
453  * Add a new folder to the bunch
454  ***************************************/
455 
456 FL_OBJECT *
fl_addto_tabfolder(FL_OBJECT * ob,const char * title,FL_FORM * form)457 fl_addto_tabfolder( FL_OBJECT  * ob,
458                     const char * title,
459                     FL_FORM    * form )
460 {
461     FLI_TABFOLDER_SPEC *sp = ob->spec;
462     FL_OBJECT *tab;
463 
464     if ( ! IsFolderClass( ob ) )
465     {
466         M_err( "fl_addto_tabfolder", "%s not a folder class",
467                ob ? ob->label : "null" );
468         return 0;
469     }
470 
471     if ( ! form || ! title )
472     {
473         M_err( "fl_addto_tabfolder", "Invalid argument(s)" );
474         return 0;
475     }
476 
477     if ( form->attached )
478     {
479         M_err( "fl_addto_tabfolder",
480                "Seems as if the form is already attached" );
481         return 0;
482     }
483 
484     if ( form->visible == FL_VISIBLE )
485         fl_hide_form( form );
486 
487     sp->forms = fl_realloc( sp->forms, ( sp->nforms + 1 ) * sizeof *sp->forms );
488     sp->title = fl_realloc( sp->title, ( sp->nforms + 1 ) * sizeof *sp->title );
489 
490     /* Plug the possible object leakage thru fl_do_forms */
491 
492     if ( ! form->form_callback )
493         fl_set_form_callback( form, form_cb, NULL );
494 
495     sp->forms[ sp->nforms ] = form;
496     form->attached = 1;
497 
498     if ( form->pre_attach )
499         form->pre_attach( form );
500 
501     tab = sp->title[ sp->nforms ] = fl_create_button( FL_NORMAL_BUTTON,
502                                                       0, 0, 10, 10, title );
503 
504     fli_inherit_attributes( ob, tab );
505     fl_set_object_boxtype( tab, ob->type != FL_BOTTOM_TABFOLDER ?
506                            FL_TOPTAB_UPBOX : FL_BOTTOMTAB_UPBOX );
507 
508     tab->u_vdata = sp;
509     fl_set_object_callback( tab, switch_folder, sp->nforms );
510 
511     sp->nforms++;
512     compute_position( ob );
513 
514     fl_add_child( ob, tab );
515 
516     tab->how_return = FL_RETURN_CHANGED;
517 
518     if ( sp->nforms == 1 )
519     {
520         sp->last_active = 0;
521         sp->active_folder = -1;
522         program_switch( sp->title[ sp->last_active ], sp->last_active );
523     }
524 
525     /* If first time and the canvas is visible, refresh */
526 
527     if ( sp->nforms == 1 && ob->visible )
528         fl_redraw_form( ob->form );
529 
530     return tab;
531 }
532 
533 
534 /***************************************
535  ***************************************/
536 
537 static void
get_tabsize(FL_OBJECT * ob,const char * label,int * ww,int * hh,int fudge)538 get_tabsize( FL_OBJECT  * ob,
539              const char * label,
540              int        * ww,
541              int        * hh,
542              int          fudge )
543 {
544     int w,
545         h,
546         absbw = FL_abs( ob->bw );
547     FLI_TABFOLDER_SPEC *sp = ob->spec;
548 
549     fl_get_string_dimension( ob->lstyle, ob->lsize, label, strlen( label ),
550                              &w, &h );
551     w += sp->h_pad + 2 * absbw;
552     h += sp->v_pad + 2 * absbw;
553 
554     *hh = h + fudge * absbw;
555     *ww = w;
556 
557     return;
558 }
559 
560 
561 /***************************************
562  ***************************************/
563 
564 void
fl_delete_folder_byname(FL_OBJECT * ob,const char * name)565 fl_delete_folder_byname( FL_OBJECT  * ob,
566                          const char * name )
567 {
568     FLI_TABFOLDER_SPEC *sp = ob->spec;
569     int i,
570         done;
571 
572     for ( done = i = 0; ! done && i < sp->nforms; i++ )
573         if ( ! strcmp( sp->title[ i ]->label, name ) )
574             done = i + 1;
575 
576     if ( done )
577         fl_delete_folder_bynumber( ob, done );
578 
579 }
580 
581 
582 /***************************************
583  ***************************************/
584 
585 void
fl_delete_folder_byname_f(FL_OBJECT * ob,const char * fmt,...)586 fl_delete_folder_byname_f( FL_OBJECT  * ob,
587                            const char * fmt,
588                            ... )
589 {
590     char *buf;
591 
592     EXPAND_FORMAT_STRING( buf, fmt );
593     fl_delete_folder_byname( ob, buf );
594     fl_free( buf );
595 }
596 
597 
598 /***************************************
599  ***************************************/
600 
601 void
fl_delete_folder_bynumber(FL_OBJECT * ob,int num)602 fl_delete_folder_bynumber( FL_OBJECT * ob,
603                            int         num )
604 {
605     int i = num - 1;
606     FLI_TABFOLDER_SPEC *sp = ob->spec;
607     FL_OBJECT *deleted = NULL;
608     FL_FORM *theform = NULL;
609 
610     if ( i >= 0 && i < sp->nforms )
611     {
612         int j;
613 
614         deleted = sp->title[ i ];
615         fli_detach_form( theform = sp->forms[ i ] );
616 
617         for ( j = i + 1; j < sp->nforms; j++ )
618         {
619             sp->title[ j - 1 ]           = sp->title[ j ];
620             sp->title[ j - 1 ]->argument = j - 1;
621             sp->forms[ j - 1 ]           = sp->forms[ j ];
622         }
623 
624         sp->nforms--;
625         sp->forms = fl_realloc( sp->forms, sp->nforms * sizeof *sp->forms );
626         sp->title = fl_realloc( sp->title, sp->nforms * sizeof *sp->title );
627     }
628 
629     if ( deleted )
630     {
631         fli_set_object_visibility( deleted, FL_INVISIBLE );
632 
633         if ( theform->form_callback == form_cb )
634             theform->form_callback = NULL;
635 
636         if ( theform->visible == FL_VISIBLE )
637             fl_hide_form( theform );
638 
639         /* Change active folder if need to */
640 
641         sp->last_active = -1;
642 
643         if ( i < sp->active_folder )
644             sp->active_folder--;
645         else if ( i == sp->active_folder )
646         {
647             sp->active_folder = -1;
648             fl_set_folder_bynumber( ob, i );
649         }
650 
651         fl_free_object( deleted );
652 
653         fl_redraw_form( ob->form );
654     }
655 }
656 
657 
658 /***************************************
659  ***************************************/
660 
661 FL_FORM *
fl_get_tabfolder_folder_bynumber(FL_OBJECT * ob,int num)662 fl_get_tabfolder_folder_bynumber( FL_OBJECT * ob,
663                                   int         num )
664 {
665     FLI_TABFOLDER_SPEC *sp = ob->spec;
666     int i = num - 1;
667 
668     return ( i >= 0 && i < sp->nforms ) ? sp->forms[ i ] : NULL;
669 }
670 
671 
672 /***************************************
673  ***************************************/
674 
675 FL_FORM *
fl_get_tabfolder_folder_byname(FL_OBJECT * ob,const char * name)676 fl_get_tabfolder_folder_byname( FL_OBJECT  * ob,
677                                 const char * name )
678 {
679     int i;
680     FLI_TABFOLDER_SPEC *sp = ob->spec;
681 
682     for ( i = 0; i < sp->nforms; i++ )
683         if ( strcmp( sp->title[ i ]->label, name ) == 0 )
684             return fl_get_tabfolder_folder_bynumber( ob, i + 1 );
685 
686     return NULL;
687 }
688 
689 
690 /***************************************
691  ***************************************/
692 
693 FL_FORM *
fl_get_tabfolder_folder_byname_f(FL_OBJECT * ob,const char * fmt,...)694 fl_get_tabfolder_folder_byname_f( FL_OBJECT  * ob,
695                                   const char * fmt,
696                                   ...)
697 {
698     FL_FORM *f;
699     char *buf;
700 
701     EXPAND_FORMAT_STRING( buf, fmt );
702     f = fl_get_tabfolder_folder_byname( ob, buf );
703     fl_free( buf );
704     return f;
705 }
706 
707 
708 /***************************************
709  ***************************************/
710 
711 void
fl_delete_folder(FL_OBJECT * ob,FL_FORM * form)712 fl_delete_folder( FL_OBJECT * ob,
713                   FL_FORM   * form )
714 {
715     int i, done;
716     FLI_TABFOLDER_SPEC *sp = ob->spec;
717 
718     for ( done = i = 0; ! done && i < sp->nforms; i++ )
719         if ( form == sp->forms[ i ] )
720             done = i + 1;
721 
722     if ( done )
723         fl_delete_folder_bynumber( ob, done );
724 }
725 
726 
727 /***************************************
728  ***************************************/
729 
730 void
fl_set_folder(FL_OBJECT * ob,FL_FORM * form)731 fl_set_folder( FL_OBJECT * ob,
732                FL_FORM   * form )
733 {
734     FLI_TABFOLDER_SPEC *sp;
735     int i,
736         done;
737 
738     if ( ! IsFolderClass( ob ) )
739     {
740         M_err( "fl_set_folder", "%s is not tabfolder",
741                ob ? ob->label : "null" );
742         return;
743     }
744 
745     sp = ob->spec;
746     for ( done = i = 0; ! done && i < sp->nforms; i++ )
747         if ( sp->forms[ i ] == form )
748         {
749             program_switch( sp->title[ i ], i );
750             done = 1;
751         }
752 }
753 
754 
755 /***************************************
756  ***************************************/
757 
758 void
fl_set_folder_byname(FL_OBJECT * ob,const char * name)759 fl_set_folder_byname( FL_OBJECT  * ob,
760                       const char * name )
761 {
762     FLI_TABFOLDER_SPEC *sp;
763     int i,
764         done;
765 
766     if ( ! IsFolderClass( ob ) )
767     {
768         M_err( "fl_set_folder_byname", "%s is not tabfolder",
769                ob ? ob->label : "null" );
770         return;
771     }
772 
773     sp = ob->spec;
774     for ( done = i = 0; ! done && i < sp->nforms; i++ )
775         if ( strcmp( sp->title[ i ]->label, name ) == 0 )
776         {
777             program_switch( sp->title[ i ], i );
778             done = 1;
779         }
780 }
781 
782 
783 /***************************************
784  ***************************************/
785 
786 void
fl_set_folder_byname_f(FL_OBJECT * ob,const char * fmt,...)787 fl_set_folder_byname_f( FL_OBJECT  * ob,
788                         const char * fmt,
789                         ... )
790 {
791     char *buf;
792 
793     EXPAND_FORMAT_STRING( buf, fmt );
794     fl_set_folder_byname( ob, buf );
795     fl_free( buf );
796 }
797 
798 
799 /***************************************
800  ***************************************/
801 
802 void
fl_set_folder_bynumber(FL_OBJECT * ob,int num)803 fl_set_folder_bynumber( FL_OBJECT * ob,
804                         int         num )
805 {
806     FLI_TABFOLDER_SPEC *sp;
807     int i = num - 1;
808 
809     if ( ! IsFolderClass( ob ) )
810     {
811         M_err( "fl_set_folder_bynumber", "%s is not tabfolder",
812                ob ? ob->label : "null" );
813         return;
814     }
815 
816     sp = ob->spec;
817     if ( i >= 0 && i < sp->nforms )
818         program_switch( sp->title[ i ], i );
819 }
820 
821 
822 /***************************************
823  * Keep tab but replace the folder content
824  ***************************************/
825 
826 void
fl_replace_folder_bynumber(FL_OBJECT * ob,int num,FL_FORM * form)827 fl_replace_folder_bynumber( FL_OBJECT * ob,
828                             int         num,
829                             FL_FORM   * form )
830 {
831     FLI_TABFOLDER_SPEC *sp = ob->spec;
832     int i = num - 1;
833 
834     if ( i >= 0 && i < sp->nforms && sp->forms[ i ] != form )
835     {
836         sp->forms[ i ] = form;
837 
838         if ( i == sp->active_folder )
839         {
840             sp->active_folder = -1;
841             program_switch( sp->title[ i ], i );
842         }
843     }
844 }
845 
846 
847 /***************************************
848  ***************************************/
849 
850 int
fl_get_folder_number(FL_OBJECT * ob)851 fl_get_folder_number( FL_OBJECT * ob )
852 {
853     if ( ! IsFolderClass( ob ) )
854     {
855         M_err( "fl_get_folder_number", "%s is not tabfolder",
856                ob ? ob->label : "null" );
857         return 0;
858     }
859 
860     return ( ( FLI_TABFOLDER_SPEC * ) ob->spec )->last_active + 1;
861 }
862 
863 
864 /***************************************
865  ***************************************/
866 
867 int
fl_get_active_folder_number(FL_OBJECT * ob)868 fl_get_active_folder_number( FL_OBJECT * ob )
869 {
870     if ( ! IsFolderClass( ob ) )
871     {
872         M_err( "fl_get_active_folder_number", "%s is not tabfolder",
873                ob ? ob->label : "null" );
874         return 0;
875     }
876 
877     return ( ( FLI_TABFOLDER_SPEC * ) ob->spec )->active_folder + 1;
878 }
879 
880 
881 /***************************************
882  ***************************************/
883 
884 FL_FORM *
fl_get_folder(FL_OBJECT * ob)885 fl_get_folder( FL_OBJECT * ob )
886 {
887     FLI_TABFOLDER_SPEC *sp;
888 
889     if ( ! IsFolderClass( ob ) )
890     {
891         M_err( "fl_get_folder", "%s is not tabfolder",
892                ob ? ob->label : "null" );
893         return NULL;
894     }
895 
896     sp = ob->spec;
897     return sp->last_active >= 0 ? sp->forms[ sp->last_active ] : NULL;
898 }
899 
900 
901 /***************************************
902  ***************************************/
903 
904 const char *
fl_get_folder_name(FL_OBJECT * ob)905 fl_get_folder_name( FL_OBJECT * ob )
906 {
907     FLI_TABFOLDER_SPEC *sp;
908 
909     if ( ! IsFolderClass( ob ) )
910     {
911         M_err( "fl_get_folder_name", "%s is not tabfolder",
912                ob ? ob->label : "null" );
913         return NULL;
914     }
915 
916     sp = ob->spec;
917     return sp->last_active >= 0 ? sp->title[ sp->last_active ]->label : NULL;
918 }
919 
920 
921 /***************************************
922  ***************************************/
923 
924 FL_FORM *
fl_get_active_folder(FL_OBJECT * ob)925 fl_get_active_folder( FL_OBJECT * ob )
926 {
927     FLI_TABFOLDER_SPEC *sp;
928 
929     if ( ! IsFolderClass( ob ) )
930     {
931         M_err( "fl_get_active_folder", "%s is not tabfolder",
932                ob ? ob->label : "null" );
933         return NULL;
934     }
935 
936     sp = ob->spec;
937 
938     return ( sp->forms && sp->active_folder >= 0 ) ?
939            sp->forms[ sp->active_folder ] : NULL;
940 }
941 
942 
943 /***************************************
944  ***************************************/
945 
946 const char *
fl_get_active_folder_name(FL_OBJECT * ob)947 fl_get_active_folder_name( FL_OBJECT * ob )
948 {
949     FLI_TABFOLDER_SPEC *sp;
950 
951     if ( ! IsFolderClass( ob ) )
952     {
953         M_err( "fl_get_active_folder_name", "%s is not tabfolder",
954               ob ? ob->label : "null" );
955         return NULL;
956     }
957 
958     sp = ob->spec;
959     return sp->active_folder >= 0 ?
960            sp->title[ sp->active_folder ]->label : NULL;
961 }
962 
963 
964 /***************************************
965  ***************************************/
966 
967 void
fl_get_folder_area(FL_OBJECT * ob,FL_Coord * x,FL_Coord * y,FL_Coord * w,FL_Coord * h)968 fl_get_folder_area( FL_OBJECT * ob,
969                     FL_Coord  * x,
970                     FL_Coord  * y,
971                     FL_Coord  * w,
972                     FL_Coord  * h )
973 {
974     FLI_TABFOLDER_SPEC *sp = ob->spec;
975 
976     compute_position( ob );
977     *x = sp->canvas->x;
978     *y = sp->canvas->y;
979     *w = sp->canvas->w;
980     *h = sp->canvas->h;
981 }
982 
983 
984 /***************************************
985  ***************************************/
986 
987 int
fl_get_tabfolder_offset(FL_OBJECT * obj)988 fl_get_tabfolder_offset( FL_OBJECT * obj )
989 {
990     return ( ( FLI_TABFOLDER_SPEC * ) obj->spec )->offset;
991 }
992 
993 
994 /***************************************
995  ***************************************/
996 
997 int
fl_set_tabfolder_offset(FL_OBJECT * obj,int offset)998 fl_set_tabfolder_offset( FL_OBJECT * obj,
999                          int         offset )
1000 {
1001     FLI_TABFOLDER_SPEC *sp = obj->spec;
1002     int old = sp->offset;
1003 
1004     if ( offset < 0 )
1005         offset = 0;
1006     else if ( offset + sp->num_visible + 1 > sp->nforms - 1 )
1007         offset = sp->nforms - sp->num_visible;
1008 
1009     if ( offset != sp->offset )
1010     {
1011         shift_tabs( obj, offset - sp->offset );
1012         fl_redraw_form( obj->form );
1013     }
1014 
1015     return old;
1016 }
1017 
1018 
1019 /***************************************
1020  * Compute the position and propagate the parent attributes
1021  ***************************************/
1022 
1023 static void
compute_top_position(FL_OBJECT * ob)1024 compute_top_position( FL_OBJECT * ob )
1025 {
1026     FLI_TABFOLDER_SPEC *sp ;
1027     FL_OBJECT *tab;
1028     int i,
1029         max_h = 4;
1030 
1031     sp = ob->objclass == FL_TABFOLDER ? ob->spec : ob->u_vdata;
1032 
1033     sp->y = ob->y + 1;
1034     sp->x = sp->canvas->x - FL_abs( sp->canvas->bw );
1035 
1036     for ( i = 0; i < sp->offset; i++ )
1037         sp->title[ i ]->x = 2000;
1038 
1039     /* This gets the fl_get_folder_area() right (single line tab) - even if
1040        empty folder */
1041 
1042     if ( sp->nforms == 0 )
1043     {
1044         int junk;
1045         get_tabsize( ob, "AjbY", &junk, &max_h, 1 );
1046     }
1047 
1048     for ( i = sp->offset; i < sp->nforms; i++ )
1049     {
1050         tab = sp->title[ i ];
1051         get_tabsize( ob, tab->label, &tab->w, &tab->h, 1 );
1052         if ( tab->h > max_h )
1053             max_h = tab->h;
1054         tab->x = sp->x;
1055         tab->y = sp->y;
1056         sp->x += tab->w + ( ob->bw > 0 );
1057         if ( sp->x < sp->canvas->x + sp->canvas->w - 2 )
1058         {
1059             sp->num_visible = i;
1060             tab->boxtype &= ~ FLI_BROKEN_BOX;
1061             tab->align = FL_ALIGN_CENTER;
1062             tab->visible = 1;
1063         }
1064         else if ( ( tab->w -= sp->x - sp->canvas->x - sp->canvas->w ) > 0 )
1065         {
1066             tab->boxtype |= FLI_BROKEN_BOX;
1067             tab->align = fl_to_inside_lalign( FL_ALIGN_LEFT );
1068             tab->visible = 1;
1069         }
1070         else
1071         {
1072             tab->w = 20;
1073             tab->visible = 0;
1074         }
1075     }
1076 
1077     for ( i = 0; i < sp->nforms; i++ )
1078         sp->title[ i ]->h = max_h;
1079 
1080     /* This will be the canvas location */
1081 
1082     if ( ob->objclass == FL_TABFOLDER )
1083     {
1084         if ( ob->type != FL_BOTTOM_TABFOLDER )
1085             sp->canvas->y = sp->y + max_h - ( ob->bw < 0 );
1086     }
1087     else
1088     {
1089         if ( sp->parent->type != FL_BOTTOM_TABFOLDER )
1090             sp->canvas->y = sp->y + max_h - ( ob->bw < 0 );
1091     }
1092 
1093     sp->canvas->h = ob->h - max_h - FL_abs( ob->bw ) - 1;
1094     sp->max_h = max_h;
1095     fl_set_object_color( sp->canvas, ob->col1, ob->col2 );
1096 }
1097 
1098 
1099 /***************************************
1100  ***************************************/
1101 
1102 static void
compute_bottom_position(FL_OBJECT * ob)1103 compute_bottom_position( FL_OBJECT * ob )
1104 {
1105     FLI_TABFOLDER_SPEC *sp;
1106     FL_OBJECT *tab;
1107     int i,
1108         max_h = 4,
1109         absbw = FL_abs( ob->bw );
1110 
1111     sp = ob->objclass == FL_TABFOLDER ? ob->spec:ob->u_vdata;
1112     sp->x = ob->x;
1113 
1114     if ( sp->nforms == 0 )
1115     {
1116         int junk;
1117         get_tabsize( ob, "AjbY", &junk, &max_h, -1 );
1118     }
1119 
1120     for ( i = 0; i < sp->nforms; i++ )
1121     {
1122         tab = sp->title[ i ];
1123         get_tabsize( ob, tab->label, &tab->w, &tab->h, -1 );
1124         if ( tab->h > max_h )
1125             max_h = tab->h;
1126         tab->x = sp->x;
1127         sp->x += tab->w + ( ob->bw > 0 );
1128     }
1129 
1130     sp->canvas->h = ob->h - 2 * absbw - max_h - 1;
1131     sp->y = sp->canvas->y + sp->canvas->h + absbw - ( ob->bw < 0 );
1132 
1133     for ( i = 0; i < sp->nforms; i++ )
1134     {
1135         sp->title[ i ]->h = max_h;
1136         sp->title[ i ]->y = sp->y;
1137     }
1138 
1139     sp->max_h = max_h;
1140     fl_set_object_color( sp->canvas, ob->col1, ob->col2 );
1141 }
1142 
1143 
1144 /***************************************
1145  ***************************************/
1146 
1147 static void
compute_position(FL_OBJECT * ob)1148 compute_position( FL_OBJECT * ob )
1149 {
1150     if ( ob->type == FL_BOTTOM_TABFOLDER )
1151         compute_bottom_position( ob );
1152     else
1153         compute_top_position( ob );
1154 }
1155 
1156 
1157 /***************************************
1158  ***************************************/
1159 
1160 int
fl_set_tabfolder_autofit(FL_OBJECT * ob,int y)1161 fl_set_tabfolder_autofit( FL_OBJECT * ob,
1162                           int         y )
1163 {
1164     FLI_TABFOLDER_SPEC *sp = ob->spec;
1165     int old = sp->auto_fit;
1166 
1167     sp->auto_fit = y;
1168     return old;
1169 }
1170 
1171 
1172 /***************************************
1173  ***************************************/
1174 
1175 static void
shift_tabs(FL_OBJECT * ob,int left)1176 shift_tabs( FL_OBJECT * ob,
1177             int         left )
1178 {
1179     FLI_TABFOLDER_SPEC *sp = ob->u_vdata;
1180     int newp = sp->offset + left;
1181 
1182     if ( newp < 0 )
1183         newp = 0;
1184 
1185     if ( newp == sp->offset )
1186         return;
1187 
1188     sp->offset = newp;
1189 
1190     compute_position( ob );
1191 }
1192 
1193 
1194 /***************************************
1195  ***************************************/
1196 
1197 void
fli_set_tab_color(FL_OBJECT * obj,FL_COLOR col1,FL_COLOR col2)1198 fli_set_tab_color( FL_OBJECT * obj,
1199                      FL_COLOR    col1,
1200                      FL_COLOR    col2 )
1201 {
1202     FLI_TABFOLDER_SPEC *sp = obj->spec;
1203     int i;
1204 
1205     for ( i = 0; i < sp->nforms; i++ )
1206         fl_set_object_color( sp->title[ i ], col1, col2 );
1207 }
1208 
1209 
1210 /***************************************
1211  ***************************************/
1212 
1213 void
fli_set_tab_lcolor(FL_OBJECT * obj,FL_COLOR lcol)1214 fli_set_tab_lcolor( FL_OBJECT * obj,
1215                     FL_COLOR    lcol )
1216 {
1217     FLI_TABFOLDER_SPEC *sp = obj->spec;
1218     int i;
1219 
1220     for ( i = 0; i < sp->nforms; i++ )
1221         fl_set_object_lcolor( sp->title[ i ], lcol );
1222 }
1223 
1224 
1225 /***************************************
1226  ***************************************/
1227 
1228 void
fli_set_tab_lsize(FL_OBJECT * obj,int lsize)1229 fli_set_tab_lsize( FL_OBJECT * obj,
1230                    int         lsize )
1231 {
1232     FLI_TABFOLDER_SPEC *sp = obj->spec;
1233     int i;
1234 
1235     for ( i = 0; i < sp->nforms; i++ )
1236         fl_set_object_lsize( sp->title[ i ], lsize );
1237 }
1238 
1239 
1240 /***************************************
1241  ***************************************/
1242 
1243 void
fli_set_tab_lstyle(FL_OBJECT * obj,int lstyle)1244 fli_set_tab_lstyle( FL_OBJECT * obj,
1245                     int         lstyle )
1246 {
1247     FLI_TABFOLDER_SPEC *sp = obj->spec;
1248     int i;
1249 
1250     for ( i = 0; i < sp->nforms; i++ )
1251         fl_set_object_lstyle( sp->title[ i ], lstyle );
1252 }
1253 
1254 
1255 /***************************************
1256  ***************************************/
1257 
1258 void
fli_set_tab_lalign(FL_OBJECT * obj,int align)1259 fli_set_tab_lalign( FL_OBJECT * obj,
1260                     int         align )
1261 {
1262     FLI_TABFOLDER_SPEC *sp = obj->spec;
1263     int i;
1264 
1265     for ( i = 0; i < sp->nforms; i++ )
1266         fl_set_object_lalign( sp->title[ i ], align );
1267 }
1268 
1269 
1270 /***************************************
1271  ***************************************/
1272 
1273 void
fli_set_tab_bw(FL_OBJECT * obj,int bw)1274 fli_set_tab_bw( FL_OBJECT * obj,
1275                 int         bw )
1276 {
1277     FLI_TABFOLDER_SPEC *sp = obj->spec;
1278     int i;
1279 
1280     for ( i = 0; i < sp->nforms; i++ )
1281         fl_set_object_bw( sp->title[ i ], bw );
1282 }
1283 
1284 
1285 /*
1286  * Local variables:
1287  * tab-width: 4
1288  * indent-tabs-mode: nil
1289  * End:
1290  */
1291