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 formbrowser.c
21  *
22  *  This file is part of the XForms library package.
23  *
24  *  Copyright (c) 1997  By T.C. Zhao and Mark Overmars
25  *  Copyright (c) 1998  By Steve Lamont of the National Center for
26  *                      Microscopy and Imaging Research
27  *  Copyright (c) 1999-2002  by T.C. Zhao and Steve Lamont
28  *  All rights reserved.
29  *
30  * form browser.
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "include/forms.h"
38 #include "flinternal.h"
39 #include "private/pformbrowser.h"
40 
41 
42 static void check_scrollbar( FL_OBJECT * ob );
43 static int canvas_cleanup( FL_OBJECT * ob );
44 static int canvas_handler( FL_OBJECT * ob,
45                            Window      win,
46                            int         w,
47                            int         h,
48                            XEvent    * ev,
49                            void      * data );
50 static void delete_form( FLI_FORMBROWSER_SPEC * sp,
51                      int                    f );
52 static void display_forms( FLI_FORMBROWSER_SPEC * sp );
53 static void form_cb( FL_OBJECT * ob,
54                      void      * data );
55 static int handle_formbrowser( FL_OBJECT * ob,
56                                int         event,
57                                FL_Coord    mx,
58                                FL_Coord    my,
59                                int         key,
60                                void      * ev );
61 static void hcb( FL_OBJECT * ob,
62                  long        data );
63 static void parentize_form( FL_FORM   * form,
64                             FL_OBJECT * ob );
65 static void set_form_position( FL_FORM * form,
66                                int       x,
67                                int       y );
68 static void vcb( FL_OBJECT * ob,
69                  long        data );
70 static void set_formbrowser_return( FL_OBJECT    * obj,
71                                     unsigned int   when );
72 
73 
74 /***************************************
75  ***************************************/
76 
77 FL_OBJECT *
fl_create_formbrowser(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)78 fl_create_formbrowser( int          type,
79                        FL_Coord     x,
80                        FL_Coord     y,
81                        FL_Coord     w,
82                        FL_Coord     h,
83                        const char * label )
84 {
85     FL_OBJECT *ob;
86     FLI_FORMBROWSER_SPEC *sp;
87     int absbw, oldu = fl_get_coordunit( );
88     int D;
89 
90     ob = fl_make_object( FL_FORMBROWSER, type, x, y, w, h, label,
91                          handle_formbrowser );
92     fl_set_coordunit( FL_COORD_PIXEL );
93     ob->boxtype    = FL_FORMBROWSER_BOXTYPE;
94     ob->align      = FL_FORMBROWSER_ALIGN;
95     ob->col1       = FL_FORMBROWSER_COL1;
96     ob->col2       = FL_BLACK;
97     ob->set_return = set_formbrowser_return;
98     ob->spec       = sp = fl_calloc( 1, sizeof *sp );
99 
100     absbw = FL_abs( ob->bw );
101 
102     sp->form   = NULL;
103     sp->parent = ob;
104     sp->scroll = FL_SMOOTH_SCROLL;
105     sp->vw_def = sp->hh_def = D = fli_get_default_scrollbarsize( ob );
106     sp->canvas = fl_create_canvas( FL_CANVAS,
107                                    ob->x + absbw, ob->y + absbw,
108                                    ob->w - 2 * absbw - sp->vw_def,
109                                    ob->h - 2 * absbw - sp->hh_def,
110                                    label );
111 
112     sp->canvas->u_vdata = sp;
113 
114     fl_modify_canvas_prop( sp->canvas, NULL, NULL, canvas_cleanup );
115 
116     fl_set_object_color( sp->canvas, ob->col1, ob->col2 );
117     fl_set_object_bw( sp->canvas, ob->bw );
118 
119     fl_set_object_boxtype( sp->canvas,
120                            fli_boxtype2frametype( ob->boxtype ) );
121     fl_add_canvas_handler( sp->canvas, Expose, canvas_handler, NULL );
122 
123     sp->v_pref = sp->h_pref = FL_AUTO;
124 
125     sp->hsl = fl_create_scrollbar( FL_HOR_THIN_SCROLLBAR, ob->x,
126                                    y + h - D, w - D, D, "" );
127     fl_set_scrollbar_value( sp->hsl, sp->old_hval = 0.0 );
128     fl_set_object_boxtype( sp->hsl, ob->boxtype );
129     sp->hsl->visible = sp->h_pref == FL_ON;
130     sp->hsl->resize = FL_RESIZE_X;
131     fl_set_object_callback( sp->hsl, hcb, 0 );
132 
133     sp->vsl = fl_create_scrollbar( FL_VERT_THIN_SCROLLBAR,
134                                    x + w - D, y, D, h - D, "" );
135     fl_set_object_boxtype( sp->vsl, ob->boxtype );
136     sp->vsl->visible = sp->v_pref == FL_ON;
137     fl_set_scrollbar_value( sp->vsl, sp->old_hval = 0.0 );
138     sp->vsl->resize = FL_RESIZE_Y;
139     fl_set_object_callback( sp->vsl, vcb, 0 );
140 
141     fl_add_child( ob, sp->canvas );
142     fl_add_child( ob, sp->hsl );
143     fl_add_child( ob, sp->vsl );
144 
145     fl_set_coordunit( oldu );
146 
147     /* Set default return policy for the object */
148 
149     fl_set_object_return( ob, FL_RETURN_NONE );
150 
151     return ob;
152 }
153 
154 
155 /***************************************
156  ***************************************/
157 
158 FL_OBJECT *
fl_add_formbrowser(int type,FL_Coord x,FL_Coord y,FL_Coord w,FL_Coord h,const char * label)159 fl_add_formbrowser( int          type,
160                     FL_Coord     x,
161                     FL_Coord     y,
162                     FL_Coord     w,
163                     FL_Coord     h,
164                     const char * label )
165 {
166 
167     FL_OBJECT *obj = fl_create_formbrowser( type, x, y, w, h, label );
168 
169     fl_add_object( fl_current_form, obj );
170 
171     return obj;
172 }
173 
174 
175 /***************************************
176  ***************************************/
177 
178 FL_FORM *
fl_get_formbrowser_topform(FL_OBJECT * ob)179 fl_get_formbrowser_topform( FL_OBJECT * ob )
180 {
181     int topline;
182     FLI_FORMBROWSER_SPEC *sp;
183 
184     if ( ! IsFormBrowserClass( ob ) )
185     {
186         M_err( "fl_get_formbrowser_topform", "%s not a formbrowser",
187                ob ? ob->label : "null" );
188         return NULL;
189     }
190 
191     sp = ob->spec;
192     topline = sp->top_form + 1;
193 
194     return topline ? sp->form[ topline - 1 ] : NULL;
195 }
196 
197 
198 /***************************************
199  ***************************************/
200 
201 int
fl_set_formbrowser_topform(FL_OBJECT * ob,FL_FORM * form)202 fl_set_formbrowser_topform( FL_OBJECT * ob,
203                             FL_FORM   * form )
204 {
205     int n = fl_find_formbrowser_form_number( ob, form );
206 
207     if ( n > 0 )
208         fl_set_formbrowser_topform_bynumber( ob, n );
209 
210     return n;
211 }
212 
213 
214 /***************************************
215  ***************************************/
216 
217 FL_FORM *
fl_set_formbrowser_topform_bynumber(FL_OBJECT * ob,int n)218 fl_set_formbrowser_topform_bynumber( FL_OBJECT * ob,
219                                      int         n )
220 {
221     FLI_FORMBROWSER_SPEC *sp = ob->spec;
222     FL_FORM *form = NULL;
223 
224     if ( n > 0 && n <= sp->nforms )
225     {
226         int h,
227             f;
228 
229         sp->top_form = n - 1;
230         sp->top_edge = 0;
231         form = sp->form[ sp->top_form ];
232         display_forms( sp );
233 
234         for ( h = f = 0; f < sp->top_form; f++ )
235             h += sp->form[ f ]->h;
236 
237         sp->old_vval = ( double ) h / ( sp->max_height - sp->canvas->h );
238         fl_set_scrollbar_value( sp->vsl, sp->old_vval );
239     }
240 
241     return form;
242 }
243 
244 
245 /***************************************
246  ***************************************/
247 
248 int
fl_addto_formbrowser(FL_OBJECT * ob,FL_FORM * form)249 fl_addto_formbrowser( FL_OBJECT * ob,
250                       FL_FORM   * form )
251 {
252     FLI_FORMBROWSER_SPEC *sp;
253 
254     if ( ! IsFormBrowserClass( ob ) )
255     {
256         M_err( "fl_addto_formbrowser", "%s not a formbrowser",
257                ob ? ob->label : "null" );
258         return 0;
259     }
260 
261     if ( ! form )
262     {
263         M_err( "fl_addto_formbrowser", "Invalid argument" );
264         return 0;
265     }
266 
267     if ( form->attached )
268     {
269         M_err( "fl_addto_formbrowser", "Already attached ?" );
270         return 0;
271     }
272 
273     sp = ob->spec;
274 
275     if ( form->visible == FL_VISIBLE )
276         fl_hide_form( form );
277 
278     if ( ! form->form_callback )
279         fl_set_form_callback( form, form_cb, NULL );
280 
281     parentize_form( form, ob );
282     sp->form = fl_realloc( sp->form, ( sp->nforms + 1 ) * sizeof *sp->form );
283     sp->form[ sp->nforms++ ] = form;
284     form->attached = 1;
285 
286     if ( form->pre_attach )
287         form->pre_attach( form );
288 
289     if ( sp->max_width < form->w )
290         sp->max_width = form->w;
291 
292     sp->max_height += form->h;
293     display_forms( sp );
294 
295     return sp->nforms;
296 }
297 
298 
299 /***************************************
300  ***************************************/
301 
302 int
fl_find_formbrowser_form_number(FL_OBJECT * ob,FL_FORM * form)303 fl_find_formbrowser_form_number( FL_OBJECT * ob,
304                                  FL_FORM   * form )
305 {
306     FLI_FORMBROWSER_SPEC *sp;
307     int num;
308 
309     if ( ! IsFormBrowserClass( ob ) )
310     {
311         M_err( "fl_find_formbrowser_form_number", "%s not a formbrowser",
312                ob ? ob->label : "null" );
313         return 0;
314     }
315 
316     if ( ! form )
317     {
318         M_err( "fl_find_formbrowser_form_number", "Invalid argument" );
319         return 0;
320     }
321 
322     sp = ob->spec;
323 
324     for ( num = 0; num < sp->nforms; num++ )
325         if ( sp->form[ num ] == form )
326             break;
327 
328     return num == sp->nforms ? 0 : num + 1;
329 }
330 
331 
332 /***************************************
333  ***************************************/
334 
335 int
fl_delete_formbrowser(FL_OBJECT * ob,FL_FORM * form)336 fl_delete_formbrowser( FL_OBJECT * ob,
337                        FL_FORM   * form )
338 {
339     FLI_FORMBROWSER_SPEC *sp;
340     int f;
341 
342     if ( ! IsFormBrowserClass( ob ) )
343     {
344         M_err( "fl_delete_formbrowser", "%s not a formbrowser",
345                ob ? ob->label : "null" );
346         return -1;
347     }
348 
349     if ( ! form )
350     {
351         M_err( "fl_delete_formbrowser", "Invalid argument" );
352         return -1;
353     }
354 
355     sp = ob->spec;
356     f = fl_find_formbrowser_form_number( ob, form );
357 
358     if ( f )
359         delete_form( sp, f - 1 );
360 
361     return f ? sp->nforms : -1;
362 }
363 
364 
365 /***************************************
366  ***************************************/
367 
368 #if 0
369 
370 FL_FORM *
371 fl_get_formbrowser_parent_form( FL_OBJECT * ob )
372 {
373     return ob->form->parent;
374 }
375 
376 #endif
377 
378 
379 /***************************************
380  ***************************************/
381 
382 FL_FORM *
fl_delete_formbrowser_bynumber(FL_OBJECT * ob,int num)383 fl_delete_formbrowser_bynumber( FL_OBJECT * ob,
384                                 int         num )
385 {
386     FL_FORM *form;
387     FLI_FORMBROWSER_SPEC *sp;
388 
389     if ( ! IsFormBrowserClass( ob ) )
390     {
391         M_err( "fl_delete_formbrowser_bynumber", "%s not a formbrowser",
392                ob ? ob->label : "null" );
393         return NULL;
394     }
395 
396     sp = ob->spec;
397 
398     if ( num <= 0 || num > sp->nforms )
399     {
400         M_err( "fl_delete_formbrowser_bynumber",
401                "Invalid argument -- %d not between 1 and %d",
402                num, sp->nforms );
403         return NULL;
404     }
405 
406     form = sp->form[ --num ];
407     delete_form( sp, num );
408 
409     return form;
410 }
411 
412 
413 /***************************************
414  ***************************************/
415 
416 FL_FORM *
fl_replace_formbrowser(FL_OBJECT * ob,int num,FL_FORM * form)417 fl_replace_formbrowser( FL_OBJECT * ob,
418                         int         num,
419                         FL_FORM   * form )
420 {
421     FL_FORM *old_form;
422     FLI_FORMBROWSER_SPEC *sp;
423 
424     if ( ! IsFormBrowserClass( ob ) )
425     {
426         M_err( "fl_replace_formbrowser", "%s not a formbrowser",
427                ob ? ob->label : "null" );
428         return NULL;
429     }
430 
431     sp = ob->spec;
432 
433     if ( num <= 0 || num > sp->nforms )
434     {
435         M_err( "fl_replace_formbrowser",
436                "Invalid argument -- %d not between 1 and %d",
437                num, sp->nforms );
438         return NULL;
439     }
440 
441 
442     old_form = sp->form[ --num ];
443     fl_hide_form( old_form );
444     sp->form[ num ] = form;
445     display_forms( sp );
446 
447     return old_form;
448 }
449 
450 
451 /***************************************
452  ***************************************/
453 
454 int
fl_get_formbrowser_area(FL_OBJECT * ob,int * x,int * y,int * w,int * h)455 fl_get_formbrowser_area( FL_OBJECT * ob,
456                          int       * x,
457                          int       * y,
458                          int       * w,
459                          int       * h )
460 {
461     FLI_FORMBROWSER_SPEC *sp;
462 
463     if ( ! IsFormBrowserClass( ob ) )
464     {
465         M_err( "fl_get_formbrowser_area", "%s not a formbrowser",
466                ob ? ob->label : "null" );
467         return 0;
468     }
469 
470     sp = ob->spec;
471 
472     *x = sp->canvas->x;
473     *y = sp->canvas->y;
474     *w = sp->canvas->w;
475     *h = sp->canvas->h;
476 
477     return 1;
478 }
479 
480 
481 /***************************************
482  ***************************************/
483 
484 int
fl_insert_formbrowser(FL_OBJECT * ob,int line,FL_FORM * new_form)485 fl_insert_formbrowser( FL_OBJECT * ob,
486                        int         line,
487                        FL_FORM   * new_form )
488 {
489     FLI_FORMBROWSER_SPEC *sp;
490     int nforms;
491     FL_FORM **form;
492     int n = line - 1;
493 
494     if ( ! IsFormBrowserClass( ob ) )
495     {
496         M_err( "fl_insert_formbrowser", "%s not a formbrowser",
497                ob ? ob->label : "null" );
498         return -1;
499     }
500 
501     sp = ob->spec;
502     nforms = sp->nforms;
503 
504     if ( line <= 0 || line > nforms )
505     {
506         M_err( "fl_insert_formbrowser", "Invalid argument" );
507         return -1;
508     }
509 
510     form = fl_realloc( sp->form, ( nforms + 1 ) * sizeof *form );
511 
512     if ( ! form )
513     {
514         M_err( "fl_insert_formbrowser", "Running out of memory" );
515         return -1;
516     }
517 
518     parentize_form( new_form, ob );
519 
520     if ( n != nforms )
521         memmove( form + n + 1, form + n, sizeof *form * ( nforms - n ) );
522     form[ n ] = new_form;
523     sp->form = form;
524     sp->nforms++;
525     display_forms( sp );
526 
527     return sp->nforms;
528 }
529 
530 
531 /***************************************
532  ***************************************/
533 
534 void
fl_set_formbrowser_hscrollbar(FL_OBJECT * ob,int how)535 fl_set_formbrowser_hscrollbar( FL_OBJECT * ob,
536                                int         how )
537 {
538     FLI_FORMBROWSER_SPEC *sp = ob->spec;
539 
540     if ( sp->h_pref != how )
541     {
542         sp->h_pref = how;
543         fl_redraw_object( ob );
544     }
545 }
546 
547 
548 /***************************************
549  ***************************************/
550 
551 void
fl_set_formbrowser_vscrollbar(FL_OBJECT * ob,int how)552 fl_set_formbrowser_vscrollbar( FL_OBJECT * ob,
553                                int         how )
554 {
555     FLI_FORMBROWSER_SPEC *sp = ob->spec;
556 
557     if ( sp->v_pref != how )
558     {
559         sp->v_pref = how;
560         fl_redraw_object( ob );
561     }
562 }
563 
564 
565 /***************************************
566  ***************************************/
567 
568 void
fl_set_formbrowser_scroll(FL_OBJECT * ob,int how)569 fl_set_formbrowser_scroll( FL_OBJECT * ob,
570                            int         how )
571 {
572     FLI_FORMBROWSER_SPEC *sp = ob->spec;
573 
574     if ( sp->scroll != how )
575     {
576         if ( ( sp->scroll = how ) == FL_JUMP_SCROLL )
577             sp->top_edge = 0;
578         fl_redraw_object( ob );
579     }
580 }
581 
582 
583 /***************************************
584  ***************************************/
585 
586 int
fl_set_formbrowser_xoffset(FL_OBJECT * ob,int offset)587 fl_set_formbrowser_xoffset( FL_OBJECT * ob,
588                             int         offset )
589 {
590     FLI_FORMBROWSER_SPEC *sp;
591     int current;
592 
593     if ( ! IsFormBrowserClass( ob ) )
594     {
595         M_err( "fl_set_formbrowser_xoffset", "%s not a formbrowser",
596                ob ? ob->label : "null" );
597         return 0;
598     }
599 
600     sp = ob->spec;
601     current = sp->left_edge;
602 
603     if ( sp->max_width < sp->canvas->w )
604         offset = 0;
605     if ( offset < 0 )
606         offset = 0;
607     if ( offset > sp->max_width - sp->canvas->w )
608         offset = sp->max_width - sp->canvas->w;
609 
610     sp->left_edge = offset;
611     sp->old_hval = ( double ) sp->left_edge / ( sp->max_width - sp->canvas->w );
612     fl_set_scrollbar_value( sp->hsl, sp->old_hval );
613 
614     return current;
615 }
616 
617 
618 /***************************************
619  ***************************************/
620 
621 int
fl_get_formbrowser_xoffset(FL_OBJECT * ob)622 fl_get_formbrowser_xoffset( FL_OBJECT * ob )
623 {
624     if ( ! IsFormBrowserClass( ob ) )
625     {
626         M_err( "fl_get_formbrowser_xoffset", "%s not a formbrowser",
627                ob ? ob->label : "null" );
628         return 0;
629     }
630 
631     return ( ( FLI_FORMBROWSER_SPEC * ) ob->spec )->left_edge;
632 }
633 
634 
635 /***************************************
636  ***************************************/
637 
638 int
fl_set_formbrowser_yoffset(FL_OBJECT * ob,int offset)639 fl_set_formbrowser_yoffset( FL_OBJECT * ob,
640                             int         offset )
641 {
642     FLI_FORMBROWSER_SPEC *sp;
643     int current;
644     int h,
645         f;
646 
647     if ( ! IsFormBrowserClass( ob ) )
648     {
649         M_err( "fl_set_formbrowser_yoffset", "%s not a formbrowser",
650                ob ? ob->label : "null" );
651         return 0;
652     }
653 
654     sp = ob->spec;
655     current = fl_get_formbrowser_yoffset( ob );
656 
657     if ( sp->max_height < sp->canvas->h )
658         offset = 0;
659     if ( offset < 0 )
660         offset = 0;
661     if ( offset > sp->max_height - sp->canvas->h )
662         offset = sp->max_height - sp->canvas->h;
663 
664     h = sp->max_height;
665     for ( f = sp->nforms - 1; f >= 0 && offset < h; f-- )
666         h -= sp->form[ f ]->h;
667 
668     sp->top_form = ++f;
669     sp->top_edge = offset - h;
670 
671     sp->old_vval = ( double ) offset / ( sp->max_height - sp->canvas->h );
672     fl_set_scrollbar_value( sp->vsl, sp->old_vval );
673 
674     return current;
675 }
676 
677 
678 /***************************************
679  ***************************************/
680 
681 int
fl_get_formbrowser_yoffset(FL_OBJECT * ob)682 fl_get_formbrowser_yoffset( FL_OBJECT * ob )
683 {
684     FLI_FORMBROWSER_SPEC *sp;
685     int h,
686         f;
687 
688     if ( ! IsFormBrowserClass( ob ) )
689     {
690         M_err( "fl_get_formbrowser_yoffset", "%s not a formbrowser",
691                ob ? ob->label : "null" );
692         return 0;
693     }
694 
695     sp = ob->spec;
696     for ( h = f = 0; f < sp->top_form; f++ )
697         h += sp->form[ f ]->h;
698 
699     return h + sp->top_edge;
700 }
701 
702 
703 /***************************************
704  ***************************************/
705 
706 int
fl_get_formbrowser_numforms(FL_OBJECT * ob)707 fl_get_formbrowser_numforms( FL_OBJECT * ob )
708 {
709     if ( ! IsFormBrowserClass( ob ) )
710     {
711         M_err( "fl_get_formbrowser_numforms", "%s not a formbrowser",
712                ob ? ob->label : "null" );
713         return -1;
714     }
715 
716     return ( ( FLI_FORMBROWSER_SPEC * ) ob->spec )->nforms;
717 }
718 
719 
720 /***************************************
721  ***************************************/
722 
723 FL_FORM *
fl_get_formbrowser_form(FL_OBJECT * ob,int n)724 fl_get_formbrowser_form( FL_OBJECT * ob,
725                          int         n )
726 {
727     FL_FORM *form = NULL;
728     FLI_FORMBROWSER_SPEC *sp;
729 
730     if ( ! IsFormBrowserClass( ob ) )
731     {
732         M_err( "fl_get_formbrowser_form", "%s not a formbrowser",
733                ob ? ob->label : "null" );
734         return NULL;
735     }
736 
737     sp = ob->spec;
738 
739     if ( n >= 1 && n <= sp->nforms )
740         form = sp->form[ n - 1 ];
741     else
742         M_err( "fl_get_formbrowser_form",
743                "%d is not an allowable form number", n );
744 
745     return form;
746 }
747 
748 
749 /* Internals */
750 
751 /***************************************
752  ***************************************/
753 
754 static void
display_forms(FLI_FORMBROWSER_SPEC * sp)755 display_forms( FLI_FORMBROWSER_SPEC * sp )
756 {
757     int f;
758     int y_pos;
759     FL_OBJECT *canvas = sp->canvas;
760     FL_FORM **form    = sp->form;
761     int nforms        = sp->nforms;
762     int top_form      = sp->top_form;
763     int left_edge     = - sp->left_edge;
764     int height        = canvas->h;           /* - (2 * absbw); */
765 
766     if ( ! FL_ObjWin( sp->canvas ) )
767         return;
768 
769     fli_inherit_attributes( sp->parent, sp->canvas );
770 
771     for ( f = 0; f < top_form; f++ )
772         if ( form[ f ]->visible )
773             fl_hide_form( form[ f ] );
774 
775     fli_inherit_attributes( sp->parent, sp->vsl );
776     fli_inherit_attributes( sp->parent, sp->hsl );
777 
778     /* I prefer to keep scrollbar unresizable */
779 
780     sp->vsl->resize = sp->hsl->resize = FL_RESIZE_NONE;
781 
782     y_pos = sp->scroll == FL_JUMP_SCROLL ? 0 : -sp->top_edge;
783 
784     for ( f = top_form; y_pos < height && f < nforms; f++ )
785     {
786         if ( form[ f ]->visible )
787             set_form_position( form[ f ], left_edge, y_pos );
788         else
789         {
790             fl_prepare_form_window( form[ f ], 0, FL_NOBORDER, "Formbrowser" );
791             form[ f ]->parent_obj = sp->parent;
792             XReparentWindow( fl_get_display( ),
793                              form[ f ]->window,
794                              FL_ObjWin( sp->canvas ),
795                              left_edge, y_pos );
796             fl_show_form_window( form[ f ] );
797         }
798 
799         y_pos += form[ f ]->h;
800     }
801 
802     for ( ; f < nforms; f++ )
803         if ( form[ f ]->visible )
804             fl_hide_form( form[ f ] );
805 }
806 
807 
808 /***************************************
809  ***************************************/
810 
811 static int
handle_formbrowser(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)812 handle_formbrowser( FL_OBJECT * ob,
813                     int         event,
814                     FL_Coord    mx   FL_UNUSED_ARG,
815                     FL_Coord    my   FL_UNUSED_ARG,
816                     int         key  FL_UNUSED_ARG,
817                     void      * ev   FL_UNUSED_ARG )
818 {
819     FLI_FORMBROWSER_SPEC *sp = ob->spec;
820 
821     switch ( event )
822     {
823         case FL_RESIZED :
824             fl_redraw_object( ob );
825             break;
826 
827         case FL_DRAW :
828             fl_set_object_boxtype( sp->canvas,
829                                    fli_boxtype2frametype( ob->boxtype ) );
830             sp->processing_destroy = 0;
831             check_scrollbar( ob );
832             if ( ! sp->in_draw && FL_ObjWin( sp->canvas ) )
833             {
834                 sp->in_draw = 1;
835                 display_forms( sp );
836                 sp->in_draw = 0;
837             }
838             break;
839 
840         case FL_FREEMEM :
841             fl_free( sp );
842             break;
843     }
844 
845     return FL_RETURN_NONE;
846 }
847 
848 
849 /***************************************
850  * Canvas expose handler.
851  ***************************************/
852 
853 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)854 canvas_handler( FL_OBJECT * ob,
855                 Window      win   FL_UNUSED_ARG,
856                 int         w     FL_UNUSED_ARG,
857                 int         h     FL_UNUSED_ARG,
858                 XEvent    * ev    FL_UNUSED_ARG,
859                 void      * data  FL_UNUSED_ARG )
860 {
861     display_forms( ( FLI_FORMBROWSER_SPEC * ) ob->u_vdata );
862     return 0;
863 }
864 
865 
866 /***************************************
867  * Before canvas is destroyed, this routine will be called.
868  * we need to close the form that is attached to this canvas
869  ***************************************/
870 
871 static int
canvas_cleanup(FL_OBJECT * ob)872 canvas_cleanup( FL_OBJECT * ob )
873 {
874 
875     FLI_FORMBROWSER_SPEC *sp = ob->u_vdata;
876     int i;
877 
878     sp->processing_destroy = 1;
879 
880     sp->h_on = FL_OFF;
881     sp->v_on = FL_OFF;
882 
883     for ( i = 0; i < sp->nforms; i++ )
884     if ( sp->form[ i ]->visible )
885         fl_hide_form( sp->form[ i ] );
886 
887     return 0;
888 }
889 
890 
891 /***************************************
892  * Dummy
893  ***************************************/
894 
895 static void
form_cb(FL_OBJECT * ob FL_UNUSED_ARG,void * data FL_UNUSED_ARG)896 form_cb( FL_OBJECT * ob    FL_UNUSED_ARG,
897          void      * data  FL_UNUSED_ARG )
898 {
899 }
900 
901 
902 /***************************************
903  ***************************************/
904 
905 static void
hcb(FL_OBJECT * obj,long data FL_UNUSED_ARG)906 hcb( FL_OBJECT * obj,
907      long        data  FL_UNUSED_ARG )
908 {
909     FLI_FORMBROWSER_SPEC *sp = obj->parent->spec;
910     double nval = fl_get_scrollbar_value( sp->hsl );
911     int old_left_edge = sp->left_edge;
912 
913     sp->left_edge = ( sp->max_width - sp->canvas->w ) * nval;
914     if ( old_left_edge != sp->left_edge )
915     {
916         fl_freeze_form( obj->form );
917         display_forms( sp );
918         fl_unfreeze_form( obj->form );
919     }
920 
921     if ( obj->returned & FL_RETURN_END )
922         obj->parent->returned |= FL_RETURN_END;
923 
924     if ( nval != sp->old_hval )
925         obj->parent->returned |= FL_RETURN_CHANGED;
926 
927     if (    obj->parent->how_return & FL_RETURN_END_CHANGED
928          && ! (    obj->parent->returned & FL_RETURN_CHANGED
929                 && obj->parent->returned & FL_RETURN_END ) )
930             obj->parent->returned = FL_RETURN_NONE;
931 
932     if ( obj->parent->returned & FL_RETURN_END )
933         sp->old_hval = nval;
934 }
935 
936 
937 /***************************************
938  ***************************************/
939 
940 static void
vcb(FL_OBJECT * obj,long data FL_UNUSED_ARG)941 vcb( FL_OBJECT * obj,
942      long        data  FL_UNUSED_ARG )
943 {
944     FLI_FORMBROWSER_SPEC *sp = obj->parent->spec;
945     double nval = fl_get_scrollbar_value( sp->vsl );
946 
947     if ( sp->scroll == FL_JUMP_SCROLL )
948         sp->top_form = ( sp->nforms - 1 ) * nval;
949     else
950     {
951         /* do pixel based scrolling */
952 
953         int pos = ( sp->max_height - sp->canvas->h ) * nval;
954         int h = 0,
955             f;
956 
957         for ( f = 0; h <= pos && f < sp->nforms; f++ )
958             h += sp->form[ f ]->h;
959 
960         sp->top_form = f ? ( f - 1 ) : f;
961         sp->top_edge = sp->form[ sp->top_form ]->h - h + pos;
962     }
963 
964     fl_freeze_form( obj->form );
965     display_forms( sp );
966     fl_unfreeze_form( obj->form );
967 
968     if ( obj->returned & FL_RETURN_END )
969         obj->parent->returned |= FL_RETURN_END;
970 
971     if ( nval != sp->old_vval )
972         obj->parent->returned |= FL_RETURN_CHANGED;
973 
974     if (    obj->parent->how_return & FL_RETURN_END_CHANGED
975          && ! (    obj->parent->returned & FL_RETURN_CHANGED
976                 && obj->parent->returned & FL_RETURN_END ) )
977             obj->parent->returned = FL_RETURN_NONE;
978 
979     if ( obj->parent->returned & FL_RETURN_END )
980         sp->old_vval = nval;
981 }
982 
983 
984 /***************************************
985  ***************************************/
986 
987 static void
set_form_position(FL_FORM * form,int x,int y)988 set_form_position( FL_FORM * form,
989                    int       x,
990                    int       y )
991 {
992     XMoveWindow( fl_get_display( ), form->window, x, y );
993 }
994 
995 
996 /***************************************
997  ***************************************/
998 
999 static void
delete_form(FLI_FORMBROWSER_SPEC * sp,int f)1000 delete_form( FLI_FORMBROWSER_SPEC * sp,
1001              int                    f )
1002 {
1003     fl_hide_form( sp->form[ f ] );
1004     sp->form[ f ]->attached = 0;
1005     sp->nforms--;
1006     sp->max_height -= sp->form[ f ]->h;
1007     for ( ; f < sp->nforms; f++ )
1008         sp->form[ f ] = sp->form[ f + 1 ];
1009     sp->form = fl_realloc( sp->form, sizeof *sp->form * sp->nforms );
1010     display_forms( sp );
1011 }
1012 
1013 
1014 /***************************************
1015  ***************************************/
1016 
1017 static void
parentize_form(FL_FORM * form,FL_OBJECT * ob)1018 parentize_form( FL_FORM   * form,
1019                 FL_OBJECT * ob )
1020 {
1021     form->parent = ob->form;    /* This is probably the wrong way to do it. */
1022 }
1023 
1024 
1025 /***************************************
1026  ***************************************/
1027 
1028 static void
check_scrollbar(FL_OBJECT * ob)1029 check_scrollbar( FL_OBJECT * ob )
1030 {
1031     FLI_FORMBROWSER_SPEC *sp = ob->spec;
1032     int absbw = FL_abs( ob->bw );
1033     int h_on = sp->h_on,
1034         v_on = sp->v_on;
1035 
1036     /* Inherit the boxtype of the parent */
1037 
1038     sp->hsl->boxtype = ob->boxtype;
1039     sp->vsl->boxtype = ob->boxtype;
1040 
1041     /* Gravity/resize may screw up the ratios. Recompute */
1042 
1043     sp->canvas->x = ob->x + absbw;
1044     sp->canvas->y = ob->y + absbw;
1045     sp->canvas->w = ob->w - 2 * absbw;
1046     sp->canvas->h = ob->h - 2 * absbw;
1047 
1048     sp->h_on =    sp->canvas->w - 2 * absbw - sp->vw_def > 0
1049                && sp->canvas->h - 2 * absbw - sp->hh_def > 0
1050                && (    sp->h_pref == FL_ON
1051                     || (    sp->h_pref != FL_OFF
1052                          && sp->canvas->w < sp->max_width ) );
1053 
1054     sp->v_on =    sp->canvas->w - 2 * absbw - sp->vw_def > 0
1055                && sp->canvas->h - 2 * absbw - sp->hh_def > 0
1056                && (    sp->v_pref == FL_ON
1057                     || (    sp->v_pref != FL_OFF
1058                          && sp->canvas->h < sp->max_height ) );
1059 
1060     if ( sp->h_on && ! sp->v_on )
1061         sp->v_on =    sp->canvas->w - 2 * absbw - sp->vw_def > 0
1062                    && sp->canvas->h - 2 * absbw - sp->hh_def > 0
1063                    && sp->v_pref != FL_OFF
1064                    && sp->canvas->h < sp->max_height + sp->hh_def;
1065     else if ( ! sp->h_on && sp->v_on )
1066         sp->h_on =    sp->canvas->w - 2 * absbw - sp->vw_def > 0
1067                    && sp->canvas->h - 2 * absbw - sp->hh_def > 0
1068                    && sp->h_pref != FL_OFF
1069                    && sp->canvas->w < sp->max_width + sp->vw_def;
1070 
1071     if ( sp->v_on )
1072     {
1073         sp->vw = sp->vw_def;
1074         sp->vsl->x = ob->x + ob->w - sp->vw;
1075         sp->vsl->y = ob->y;
1076         sp->vsl->w = sp->vw;
1077         fli_set_object_visibility( sp->vsl, FL_VISIBLE );
1078         fli_notify_object( sp->vsl, FL_RESIZED );
1079     }
1080     else
1081     {
1082         fli_set_object_visibility( sp->vsl, FL_HIDDEN );
1083         sp->vw = 0;
1084     }
1085 
1086     if ( sp->h_on )
1087     {
1088         sp->hh = sp->hh_def;
1089         sp->hsl->x = ob->x;
1090         sp->hsl->y = ob->y + ob->h - sp->hh;
1091         sp->hsl->h = sp->hh;
1092         fli_set_object_visibility( sp->hsl, FL_VISIBLE );
1093         fli_notify_object( sp->hsl, FL_RESIZED );
1094     }
1095     else
1096     {
1097         fli_set_object_visibility( sp->hsl, FL_HIDDEN );
1098         sp->hh = 0;
1099     }
1100 
1101     /* Recheck vertical */
1102 
1103     if (    ! sp->v_on
1104          && sp->canvas->w - 2 * absbw - sp->vw_def > 0
1105          && sp->canvas->h - 2 * absbw - sp->hh_def > 0
1106          && sp->v_pref != FL_OFF
1107          && sp->canvas->h < sp->max_height )
1108     {
1109         sp->v_on = 1;
1110         sp->vw = sp->vw_def;
1111         sp->vsl->x = ob->x + ob->w - sp->vw;
1112         sp->vsl->y = ob->y;
1113         sp->canvas->w = ob->w - 2 * absbw - sp->vw;
1114     }
1115 
1116     sp->canvas->w =    ob->w - 2 * absbw
1117                     - ( sp->v_on ? 2 * absbw + sp->vw_def : 0 );
1118     sp->canvas->h =    ob->h - 2 * absbw
1119                      - ( sp->h_on ? 2 * absbw + sp->hh_def : 0 );
1120 
1121     sp->hsl->w = sp->canvas->w + 2 * absbw;
1122     sp->vsl->h = sp->canvas->h + 2 * absbw;
1123 
1124     /* If scrollbars get turned off adjust the offsets. */
1125 
1126     if ( ! sp->v_on && v_on && sp->canvas->h >= sp->max_height )
1127     {
1128         sp->top_edge = 0;
1129         sp->top_form = 0;
1130         fl_set_scrollbar_value( sp->vsl, sp->old_vval = 0.0 );
1131     }
1132 
1133     if ( ! sp->h_on && h_on && sp->canvas->w >= sp->max_width )
1134     {
1135         sp->left_edge = 0;
1136         fl_set_scrollbar_value( sp->hsl, sp->old_hval = 0.0 );
1137     }
1138 
1139     if ( sp->h_on )
1140     {
1141         fl_set_scrollbar_size( sp->hsl,
1142                                ( double ) sp->canvas->w / sp->max_width );
1143         fl_set_formbrowser_xoffset( ob, fl_get_formbrowser_xoffset( ob ) );
1144     }
1145 
1146     if ( sp->v_on )
1147     {
1148         fl_set_scrollbar_size( sp->vsl,
1149                                ( double ) sp->canvas->h / sp->max_height );
1150         fl_set_formbrowser_yoffset( ob, fl_get_formbrowser_yoffset( ob ) );
1151     }
1152 
1153     if ( sp->canvas->w > 0 && sp->canvas->h > 0 )
1154         fl_winresize( FL_ObjWin( sp->canvas ), sp->canvas->w, sp->canvas->h );
1155 }
1156 
1157 
1158 /***************************************
1159  * Sets under which conditions the object is to be returned to the
1160  * application. This function is for interal use only, the user
1161  * must call fl_set_object_return() (which then will call this
1162  * function).
1163  ***************************************/
1164 
1165 static void
set_formbrowser_return(FL_OBJECT * obj,unsigned int when)1166 set_formbrowser_return( FL_OBJECT    * obj,
1167                         unsigned int   when )
1168 {
1169     FLI_FORMBROWSER_SPEC *sp = obj->spec;
1170 
1171     if ( when & FL_RETURN_END_CHANGED )
1172         when &= ~ ( FL_RETURN_NONE | FL_RETURN_CHANGED );
1173 
1174     obj->how_return = when;
1175 
1176     if ( when == FL_RETURN_NONE || when == FL_RETURN_CHANGED )
1177     {
1178         fl_set_scrollbar_return( sp->vsl, FL_RETURN_CHANGED );
1179         fl_set_scrollbar_return( sp->hsl, FL_RETURN_CHANGED );
1180     }
1181     else
1182     {
1183         fl_set_scrollbar_return( sp->vsl, FL_RETURN_ALWAYS );
1184         fl_set_scrollbar_return( sp->hsl, FL_RETURN_ALWAYS );
1185     }
1186 }
1187 
1188 
1189 /*
1190  * Local variables:
1191  * tab-width: 4
1192  * indent-tabs-mode: nil
1193  * End:
1194  */
1195