1 /*
2  * This file is part of XForms.
3  *
4  *  XForms is free software; you can redistribute it and/or modify it
5  *  under the terms of the GNU Lesser General Public License as
6  *  published by the Free Software Foundation; either version 2.1, or
7  *  (at your option) any later version.
8  *
9  *  XForms is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with XForms.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 
19 /**
20  * \file fd_select.c
21  *
22  *  This file is part of XForms package
23  *  Copyright (c) 1996-2002  T.C. Zhao and Mark Overmars
24  *  All rights reserved.
25  *
26  * Part of the Form Designer.
27  *
28  * This file contains all routines and data types to maintain the current
29  * selection and manipulate (move, scale) and draw it.
30  */
31 
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <ctype.h>
38 #include <float.h>
39 
40 #include "fd_main.h"
41 #include "fd_spec.h"
42 #include "fd_iconinfo.h"
43 
44 #define MAXSEL  2048
45 
46 #define BackOBJ( )    cur_form->first->next
47 
48 static FL_OBJECT *selobj[ MAXSEL ]; /* list of selected objects */
49 static int selnumb = 0;             /* and their number */
50 static int backf = FL_FALSE;        /* whether the selection is the backface */
51 
52 
53 static FL_OBJECT * copy_object( FL_OBJECT * obj,
54                                 int         exact );
55 static void set_attribs( FL_OBJECT * obj,
56                          FL_OBJECT * src );
57 
58 
59 /***************************************
60  * Returns the index of a particular object. -1 if it is not selected
61  ***************************************/
62 
63 static int
find_selobject(FL_OBJECT * obj)64 find_selobject( FL_OBJECT * obj )
65 {
66     int i;
67 
68     for ( i = 0; i < selnumb; i++ )
69         if ( selobj[ i ] == obj )
70             return i;
71 
72     return -1;
73 }
74 
75 
76 /***************************************
77  * Make a new, properly ordered list of selected objects, removing
78  * duplicates and objects set to NULL
79  ***************************************/
80 
81 static void
cleanup_selection_list(void)82 cleanup_selection_list( void )
83 {
84     FL_OBJECT **tmpobj = fl_malloc( selnumb * sizeof *tmpobj ),
85               *obj;
86     int tmpnumb = 0;
87 
88     for ( obj = cur_form->first; obj != NULL; obj = obj->next )
89         if ( find_selobject( obj ) != -1 )
90             tmpobj[ tmpnumb++ ] = obj;
91 
92     memcpy( selobj, tmpobj, tmpnumb * sizeof *tmpobj );
93     fl_free( tmpobj );
94     selnumb = tmpnumb;
95 }
96 
97 
98 /***************************************
99  * Cleans up the selection, ordering the objects and creating
100  * groups if all elements are in there
101  ***************************************/
102 
103 static void
cleanup_selection(void)104 cleanup_selection( void )
105 {
106     FL_OBJECT *obj,
107               *begobj = NULL;
108     int tt,
109         sel = -1;
110 
111     if ( cur_form == NULL )
112     {
113         selnumb = 0;
114         backf = FL_FALSE;
115         return;
116     }
117 
118     /* Figure out whether whole groups are selected */
119 
120     for ( obj = cur_form->first; obj != NULL; obj = obj->next )
121     {
122         if ( obj->objclass == FL_BEGIN_GROUP )
123         {
124             sel = 1;
125             begobj = obj;
126         }
127         else if ( obj->objclass == FL_END_GROUP )
128         {
129             if ( sel )
130             {
131                 selobj[ selnumb++ ] = begobj;
132                 selobj[ selnumb++ ] = obj;
133                 sel = 0;
134             }
135             else
136             {
137                 if ( ( tt = find_selobject( begobj ) ) != -1 )
138                     selobj[ tt ] = NULL;
139                 if ( ( tt = find_selobject( obj ) ) != -1 )
140                     selobj[ tt ] = NULL;
141             }
142         }
143         else if ( ! obj->parent && find_selobject( obj ) == -1 )
144             sel = 0;
145     }
146 
147     cleanup_selection_list( );
148     fillin_groups( );
149 }
150 
151 
152 /***************************************
153  * Returns whether object is selected
154  ***************************************/
155 
156 int
is_selected(FL_OBJECT * obj)157 is_selected( FL_OBJECT * obj )
158 {
159     return find_selobject( obj ) != -1;
160 }
161 
162 
163 /***************************************
164  * Adds an object to the current selection
165  ***************************************/
166 
167 void
addto_selection(FL_OBJECT * obj)168 addto_selection( FL_OBJECT * obj )
169 {
170     /* Find the real parent */
171 
172     while ( obj->parent )
173         obj = obj->parent;
174 
175     /* Don't add objects with backface */
176 
177     if ( backf )
178         clear_selection( );
179 
180     if ( selnumb >= MAXSEL )
181     {
182         fprintf( stderr, "Exceeding selection limits\n" );
183         return;
184     }
185 
186     selobj[ selnumb++ ] = obj;
187     cleanup_selection( );
188 }
189 
190 
191 /***************************************
192  * Adds a group to the current selection
193  ***************************************/
194 
195 void
addgroupto_selection(FL_OBJECT * obj)196 addgroupto_selection( FL_OBJECT * obj )
197 {
198     FL_OBJECT *ob;
199 
200     if ( obj->objclass != FL_BEGIN_GROUP )
201         return;
202 
203     /* If the currently selected object is the backface then deselect it */
204 
205     if ( backf )
206         clear_selection( );
207 
208     for ( ob = obj; ob && ob->objclass != FL_END_GROUP; ob = ob->next )
209     {
210         if ( ob->parent )
211             continue;
212 
213         if ( selnumb >= MAXSEL - 1 )
214         {
215             fprintf( stderr, "Exceeding selection limits\n" );
216             while ( selobj[ --selnumb ]->objclass != FL_BEGIN_GROUP )
217                 /* empty */ ;
218             return;
219         }
220 
221         selobj[ selnumb++ ] = ob;
222     }
223 
224     if ( ob != NULL )
225         selobj[ selnumb++ ] = ob;
226 
227     cleanup_selection( );
228 }
229 
230 
231 /***************************************
232  * Removes an object from the selection (if present)
233  ***************************************/
234 
235 void
deletefrom_selection(FL_OBJECT * obj)236 deletefrom_selection( FL_OBJECT * obj )
237 {
238     int ind = find_selobject( obj );
239 
240     if ( ind != -1 )
241         selobj[ ind ] = NULL;
242     cleanup_selection( );
243 }
244 
245 
246 /***************************************
247  * Removes a group to the current selection
248  ***************************************/
249 
250 void
deletegroupfrom_selection(FL_OBJECT * obj)251 deletegroupfrom_selection( FL_OBJECT * obj )
252 {
253     FL_OBJECT *ob;
254     int ind;
255 
256     if ( backf )
257         return;         /* Don't remove objects with backface */
258 
259     if ( obj->objclass != FL_BEGIN_GROUP )
260         return;
261 
262     for ( ob = obj; ob != NULL && ob->objclass != FL_END_GROUP; ob = ob->next )
263         if ( ( ind = find_selobject( ob ) ) != -1 )
264             selobj[ ind ] = NULL;
265 
266     cleanup_selection( );
267 }
268 
269 
270 /***************************************
271  * Clears the complete selection
272  ***************************************/
273 
274 void
clear_selection(void)275 clear_selection( void )
276 {
277     backf = FL_FALSE;
278     selnumb = 0;
279     cleanup_selection( );
280 }
281 
282 
283 /****
284   Helper procedures
285 ****/
286 
287 /***************************************
288  * Compute the bounding box of the selection
289  ***************************************/
290 
291 static void
compute_selbox(double * x,double * y,double * w,double * h)292 compute_selbox( double * x,
293                 double * y,
294                 double * w,
295                 double * h )
296 {
297     int i;
298     double x1 =   DBL_MAX,
299            y1 =   DBL_MAX,
300            x2 = - DBL_MAX,
301            y2 = - DBL_MAX;
302 
303     for ( i = 0; i < selnumb; i++ )
304         if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
305              && selobj[ i ]->objclass != FL_END_GROUP )
306         {
307             if ( selobj[ i ]->fl1 < x1 )
308                 x1 = selobj[ i ]->fl1;
309             if ( selobj[ i ]->ft1 < y1 )
310                 y1 = selobj[ i ]->ft1;
311             if ( selobj[ i ]->fl2 > x2 )
312                 x2 = selobj[ i ]->fl2;
313             if ( selobj[ i ]->ft2 > y2 )
314                 y2 = selobj[ i ]->ft2;
315         }
316 
317     *x = x1;
318     *y = y1;
319     *w = x2 - x1;
320     *h = y2 - y1;
321 }
322 
323 
324 /***************************************
325  * Find position of the mouse mouse
326  ***************************************/
327 
328 static void
find_mousepos(double * mx,double * my)329 find_mousepos( double * mx,
330                double * my )
331 {
332     if ( cur_form == NULL )
333         return;
334 
335     fl_winset( main_window );
336     get_mouse_pos( mx, my );
337 }
338 
339 
340 /***************************************
341  * Returns the object under the mouse.
342  ***************************************/
343 
344 static FL_OBJECT *
find_mouseobj(void)345 find_mouseobj( void )
346 {
347     double xx,
348            yy;
349 
350     if ( cur_form == NULL )
351         return NULL;
352 
353     find_mousepos( &xx, &yy );
354 
355     return fli_find_last( cur_form, FLI_FIND_MOUSE, xx, yy );
356 }
357 
358 
359 /****
360   Drawing routines
361 ****/
362 
363 #define HS  8
364 
365 int hidden = FL_FALSE;
366 
367 
368 /***************************************
369  * Draw the selection box
370  ***************************************/
371 
372 void
draw_selbox(void)373 draw_selbox( void )
374 {
375     double x,
376            y,
377            w,
378            h;
379     int i;
380     FL_OBJECT *ob;
381 
382     if ( selnumb == 0 )
383         return;
384 
385     /* Draw object boxes */
386 
387     color( fd_red );
388     for ( i = 0; i < selnumb; i++ )
389     {
390         ob = selobj[ i ];
391         if ( ob->objclass != FL_BEGIN_GROUP && ob->objclass != FL_END_GROUP )
392             rect( ob->x, ob->y, ob->x + ob->w - 1.0, ob->y + ob->h - 1.0 );
393     }
394 
395     if ( hidden )
396         return;
397 
398     /* Draw the total box */
399 
400     compute_selbox( &x, &y, &w, &h );
401 
402     show_geometry( x, y, w, h );
403 
404     if ( ! backf )
405     {
406         x -= 1.0;
407         y -= 1.0;
408         w += 2.0;
409         h += 2.0;
410     }
411     color( fd_red );
412 
413     rect(  x,          y,          x + w  - 1.0, y + h  - 1.0 );
414     rectf( x,          y,          x + HS - 1.0, y + HS - 1.0 );
415     rectf( x + w - HS, y,          x + w  - 1.0, y + HS - 1.0 );
416     rectf( x + w - HS, y + h - HS, x + w  - 1.0, y + h  - 1.0 );
417     rectf( x,          y + h - HS, x + HS - 1.0, y + h  - 1.0 );
418 
419     show_selmessage( selobj, selnumb );
420 }
421 
422 
423 /****
424   Interaction handling
425 ****/
426 
427 /***************************************
428  * Handles the moving of the selection (by mouse)
429  ***************************************/
430 
431 int
within_selection(double mx,double my)432 within_selection( double mx,
433                   double my )
434 {
435     double x,
436            y,
437            w = 0.0,
438            h = 0.0;
439 
440     if ( ! selnumb || ! cur_form || ! cur_form->first )
441         return 0;
442 
443     compute_selbox( &x, &y, &w, &h );
444 
445     /* If backface, only within scale knob is considered within */
446 
447     if ( selobj[ selnumb - 1 ] == BackOBJ( ) )
448         return    mx >= x + w - HS
449                && mx <  x + w
450                && my >= y + h - HS
451                && my <  y + h;
452 
453     return mx > x && mx < x + w && my > y && my < y + h;
454 }
455 
456 
457 /***************************************
458  ***************************************/
459 
460 void
handle_move(const XEvent * xev)461 handle_move( const XEvent * xev )
462 {
463     double mx,
464            my;
465     double x,
466            y,
467            w,
468            h;
469     int s;
470 
471     if ( cur_form == NULL || backf )
472         return;
473 
474     fl_winset( main_window );
475 
476     s = ShiftIsDown( xev->xbutton.state );
477 
478     find_mousepos( &mx, &my );
479     compute_selbox( &x, &y, &w, &h );
480 
481     if ( mx < x || mx > x + w || my < y || my > y + h )
482         return;         /* not in box */
483 
484     hidden = FL_TRUE;
485     redraw_the_form( 0 );
486 
487     if ( s )
488     {
489         copy_selection( );
490         paste_selection( );
491     }
492     else
493     {
494         int i;
495         double ox = x;
496         double oy = y;
497         double ow = w;
498         double oh = h;
499 
500         /* Show the rubberband box */
501 
502         if ( mx <= x + HS && my <= y + HS )
503         {
504             x += w;
505             y += h;
506             w = -w;
507             h = -h;
508             scale_box( &x, &y, &w, &h );
509         }
510         else if ( mx <= x + HS && my >= y + h - HS )
511         {
512             x += w;
513             w = -w;
514             scale_box( &x, &y, &w, &h );
515         }
516         else if ( mx >= x + w - HS && my <= y + HS )
517         {
518             y += h;
519             h = -h;
520             scale_box( &x, &y, &w, &h );
521         }
522         else if ( mx >= x + w - HS && my >= y + h - HS )
523             scale_box( &x, &y, &w, &h );
524         else
525             move_box( &x, &y, &w, &h, FL_TRUE );
526 
527         /* Recompute object sizes */
528 
529         for ( i = 0; i < selnumb; i++ )
530         {
531             if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
532                  && selobj[ i ]->objclass != FL_END_GROUP )
533             {
534                 selobj[ i ]->fl1 -= ox;
535                 selobj[ i ]->fl2 -= ox;
536                 selobj[ i ]->fr1 += ox;
537                 selobj[ i ]->fr2 += ox;
538 
539                 selobj[ i ]->ft1 -= oy;
540                 selobj[ i ]->ft2 -= oy;
541                 selobj[ i ]->fb1 += oy;
542                 selobj[ i ]->fb2 += oy;
543 
544                 fli_scale_object( selobj[ i ], w / ow, h / oh);
545 
546                 selobj[ i ]->x = selobj[ i ]->fl1 += x;
547                 selobj[ i ]->fl2 += x;
548                 selobj[ i ]->fr1 -= x;
549                 selobj[ i ]->fr2 -= x;
550 
551                 selobj[ i ]->y = selobj[ i ]->ft1 += y;
552                 selobj[ i ]->ft2 += y;
553                 selobj[ i ]->fb1 -= y;
554                 selobj[ i ]->fb2 -= y;
555 
556                 fli_notify_object( selobj[ i ], FL_RESIZED );
557             }
558         }
559     }
560 
561     fli_recalc_intersections( cur_form );
562 
563     hidden = FL_FALSE;
564     redraw_the_form( backf );
565     changed = FL_TRUE;
566 }
567 
568 
569 /***************************************
570  * We know how many pixels to move
571  ***************************************/
572 
573 void
move_selection(FL_Coord dx,FL_Coord dy)574 move_selection( FL_Coord dx,
575                 FL_Coord dy )
576 {
577     int i;
578     double x,
579            y,
580            w,
581            h;
582     double ox,
583            oy;
584     FL_OBJECT *ob;
585 
586     if ( ! cur_form || backf || selnumb == 0 )
587         return;
588 
589     compute_selbox( &x, &y, &w, &h );
590 
591     ox = x;
592     oy = y;
593 
594     if ( ( x += dx ) < 0 )
595         x = 0.0;
596     else if ( x + w > winw )
597         x = winw - w;
598 
599     if ( ( y += dy ) < 0 )
600         y = 0.0;
601     else if ( y + h > winh )
602         y = winh - h;
603 
604     if ( ( dx = x - ox ) == 0 && ( dy = y - oy ) == 0 )
605         return;
606 
607     for ( i = 0; i < selnumb; i++ )
608     {
609         ob = selobj[ i ];
610         if ( ob->objclass != FL_BEGIN_GROUP && ob->objclass != FL_END_GROUP )
611         {
612             ob->x   += dx;
613             ob->fl1 += dx;
614             ob->fl2 += dx;
615             ob->fr1 -= dx;
616             ob->fr2 -= dx;
617 
618             ob->y   += dy;
619             ob->ft1 += dy;
620             ob->ft2 += dy;
621             ob->fb1 -= dy;
622             ob->fb2 -= dy;
623 
624             fli_notify_object( ob, FL_RESIZED );
625         }
626     }
627 
628     redraw_the_form( 1 );
629     changed = FL_TRUE;
630 }
631 
632 
633 /***************************************
634  * Change the selection size
635  ***************************************/
636 
637 #define MINSIZE 5
638 #define DELTA 0.2
639 
640 void
resize_selection(FL_Coord dx,FL_Coord dy)641 resize_selection( FL_Coord dx,
642                   FL_Coord dy )
643 {
644     double x,
645            y,
646            w,
647            h,
648            ox,
649            oy,
650            ow,
651            oh;
652     double yscale,
653            xscale;
654     int i;
655 
656     if ( ! cur_form || selnumb == 0 )
657         return;
658 
659     compute_selbox( &x, &y, &w, &h );
660 
661     ox = x;
662     oy = y;
663     ow = w;
664     oh = h;
665 
666     if ( backf )
667     {
668         winw = fl_scrw;
669         winh = fl_scrh;
670     }
671 
672     if ( ( w += dx ) > winw)
673         w = winw;
674     else if ( w < MINSIZE )
675         w = MINSIZE;
676 
677     if ( ( h += dy ) > winh )
678         h = winh;
679     else if ( h < MINSIZE )
680         h = MINSIZE;
681 
682     if ( w == ow && oh == h )
683         return;
684 
685     xscale = w / ow;
686     yscale = h / oh;
687 
688     /* Recompute object sizes */
689 
690     for ( i = 0; i < selnumb; i++ )
691         if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
692              && selobj[ i ]->objclass != FL_END_GROUP )
693         {
694             selobj[ i ]->fl1 -= ox;
695             selobj[ i ]->fl2 -= ox;
696             selobj[ i ]->fr1 += ox;
697             selobj[ i ]->fr2 += ox;
698 
699             selobj[ i ]->ft1 -= oy;
700             selobj[ i ]->ft2 -= oy;
701             selobj[ i ]->fb1 += oy;
702             selobj[ i ]->fb2 += oy;
703 
704             fli_scale_object( selobj[ i ], xscale, yscale );
705 
706             selobj[ i ]->x = selobj[ i ]->fl1 += x;
707             selobj[ i ]->fl2 += x;
708             selobj[ i ]->fr1 -= x;
709             selobj[ i ]->fr2 -= x;
710 
711             selobj[ i ]->y = selobj[ i ]->ft1 += y;
712             selobj[ i ]->ft2 += y;
713             selobj[ i ]->fb1 -= y;
714             selobj[ i ]->fb2 -= y;
715 
716             fli_notify_object( selobj[ i ], FL_RESIZED );
717         }
718 
719     fli_recalc_intersections( cur_form );
720 
721     if ( backf )
722     {
723         cur_form->w_hr = cur_form->w = selobj[ 0 ]->w;
724         cur_form->h_hr = cur_form->h = selobj[ 0 ]->h;
725         fl_winresize( main_window, cur_form->w, cur_form->h );
726     }
727 
728     redraw_the_form( 1 );
729     changed = FL_TRUE;
730 }
731 
732 
733 /***************************************
734  * Handles the selection of objects
735  ***************************************/
736 
737 void
handle_select(const XEvent * xev)738 handle_select( const XEvent * xev )
739 {
740     int s;
741     FL_OBJECT * obj,
742               * mouseobj;
743     double x,
744            y,
745            w,
746            h;
747     double stepsize;
748 
749     if ( ! ( mouseobj = find_mouseobj( ) ) )
750         return;
751 
752     if ( ( s = ShiftIsDown( xev->xbutton.state ) ) )      /* Shift Push */
753     {
754         if ( ! cur_form->first )
755         {
756             fprintf( stderr, "something is wrong, form has No objects\n" );
757             return;
758         }
759 
760         if ( mouseobj == BackOBJ( ) )
761             return;
762 
763         if ( find_selobject( mouseobj ) == -1 )
764             addto_selection( mouseobj );
765         else
766             deletefrom_selection( mouseobj );
767 
768         return;
769     }
770 
771     clear_selection( );
772 
773     find_mousepos( &x, &y );
774     w = 0.0;
775     h = 0.0;
776 
777     stepsize = get_step_size( );
778     set_step_size( 0.0 );
779     if ( xev->type != ButtonRelease )
780         scale_box( &x, &y, &w, &h );
781     set_step_size( stepsize );
782     obj = BackOBJ( )->next;
783 
784     while ( obj != NULL )
785     {
786         if (    obj->objclass != FL_BEGIN_GROUP
787              && obj->objclass != FL_END_GROUP
788               && obj->x >= x
789               && obj->y >= y
790               && obj->x + obj->w <= x + w
791               && obj->y + obj->h <= y + h )
792             addto_selection( obj );
793 
794         obj = obj->next;
795     }
796 
797     if ( selnumb == 0 )
798     {
799         if ( mouseobj == NULL )
800             return;
801         else if ( mouseobj == BackOBJ( ) )
802         {
803             addto_selection( mouseobj );
804             backf = FL_TRUE;
805         }
806         else
807             addto_selection( mouseobj );
808     }
809 }
810 
811 
812 /***************************************
813  * Selects all objects in the form.
814  ***************************************/
815 
816 void
select_all(void)817 select_all( void )
818 {
819     FL_OBJECT *obj;
820 
821     if ( ! cur_form )
822         return;
823 
824     clear_selection( );
825 
826     for ( obj = BackOBJ( )->next; obj != NULL; obj = obj->next )
827         if ( ! obj->parent )
828             selobj[ selnumb++ ] = obj;
829 
830     cleanup_selection( );
831 }
832 
833 
834 /****
835   Operations on the selection
836 ****/
837 
838 /***************************************
839  * Clone curobj's attributes to the currently selected objects
840  ***************************************/
841 
842 static void
change_selected_objects(FL_OBJECT * curobj)843 change_selected_objects( FL_OBJECT * curobj )
844 {
845     int i;
846     FL_OBJECT *ob;
847 
848     for ( i = 0; i < selnumb; i++ )
849     {
850         ob = selobj[ i ];
851 
852         if ( ob == curobj )
853             continue;
854 
855         if ( ob->objclass != FL_BEGIN_GROUP && ob->objclass != FL_END_GROUP )
856         {
857             spec_change_type( ob, curobj->type );
858             set_attribs( ob, curobj );
859         }
860     }
861 }
862 
863 
864 /***************************************
865  * Interactively change the attributes of the selection
866  ***************************************/
867 
868 void
change_selection(void)869 change_selection( void )
870 {
871     FL_OBJECT *firstobj = NULL;
872     int objclass = -1,
873         i;
874     FL_OBJECT *ob;
875 
876     if ( ! cur_form )
877         return;
878 
879     if ( selnumb == 0 )
880     {
881         fl_show_alert( "", "Please select object to edit",
882                            "by single-clicking on it", 0 );
883         return;
884     }
885 
886     if ( selnumb == 1 )
887     {
888         if ( change_object( selobj[ 0 ], FL_TRUE ) )
889             changed = 1;
890         return;
891     }
892 
893     for ( i = 0; i < selnumb; i++ )
894     {
895         ob = selobj[ i ];
896         if (    ob->objclass != FL_BEGIN_GROUP
897              && ob->objclass != FL_END_GROUP )
898         {
899             if ( firstobj == NULL )
900             {
901                 firstobj = ob;
902                 objclass = ob->objclass;
903             }
904             else if ( objclass != ob->objclass )
905             {
906                 fl_show_messages( "Selected objects have different "
907                                   "classes" );
908                 return;
909             }
910         }
911     }
912 
913     if ( firstobj == NULL )
914         return;
915 
916     if ( ! change_object( firstobj, FL_FALSE ) )
917         return;
918 
919     change_selected_objects( firstobj );
920     changed = 1;
921 }
922 
923 
924 /***************************************
925  * Aligns the objects in the selection
926  ***************************************/
927 
928 void
align_selection(int dir)929 align_selection( int dir )
930 {
931     double x,
932            y,
933            w,
934            h,
935            gap,
936            shift;
937     int used[ MAXSEL ],
938         current;
939     int i,
940         j;
941 
942     if ( backf || ! cur_form )
943         return;         /* Cannot align the backface */
944 
945     if ( selnumb <= 1 )
946         return;         /* Nothing to align */
947 
948     compute_selbox( &x, &y, &w, &h );
949 
950     if ( dir == FD_HEQUAL ) /* Horizontal equal distance */
951     {
952         gap = 0.0;
953 
954         for ( i = 0; i < selnumb; i++ )
955             gap += selobj[ i ]->w;
956 
957         gap = ( w - gap ) / ( selnumb - 1 );
958 
959         for ( i = 0; i < selnumb; i++ )
960             used[ i ] = 0;
961 
962         for ( j = 0; j < selnumb; j++ )
963         {
964             current = -1;
965             for ( i = 0; i < selnumb; i++ )
966                 if ( ! used[ i ] )
967                     if (    current == -1
968                          || selobj[ i ]->x < selobj[ current ]->x )
969                         current = i;
970             used[ current ] = 1;
971             shift = x - selobj[ current ]->x;
972             selobj[ current ]->x   += shift;
973             selobj[ current ]->fl1 += shift;
974             selobj[ current ]->fl2 += shift;
975             selobj[ current ]->fr1 -= shift;
976             selobj[ current ]->fr2 -= shift;
977             x += selobj[ current ]->w + gap;
978         }
979     }
980     else if ( dir == FD_VEQUAL )    /* Vertical equal distance */
981     {
982         gap = 0.0;
983 
984         for ( i = 0; i < selnumb; i++ )
985             gap += selobj[ i ]->h;
986 
987         gap = ( h - gap ) / ( selnumb - 1 );
988 
989         for ( i = 0; i < selnumb; i++ )
990             used[ i ] = 0;
991 
992         for ( j = 0; j < selnumb; j++ )
993         {
994             current = -1;
995             for ( i = 0; i < selnumb; i++ )
996                 if ( ! used[ i ] )
997                     if (    current == -1
998                          || selobj[ i ]->y < selobj[ current ]->y )
999                         current = i;
1000             used[ current ] = 1;
1001             shift = y - selobj[ current ]->y;
1002             selobj[ current ]->y   += shift;
1003             selobj[ current ]->ft1 += shift;
1004             selobj[ current ]->ft2 += shift;
1005             selobj[ current ]->fb1 -= shift;
1006             selobj[ current ]->fb2 -= shift;
1007             y += selobj[ current ]->h + gap;
1008         }
1009     }
1010     else
1011         for ( i = 0; i < selnumb; i++ )
1012         {
1013             switch ( dir )
1014             {
1015                 case FD_LEFT:   /* Left */
1016                     shift = x - selobj[ i ]->x;
1017                     selobj[ i ]->x   += shift;
1018                     selobj[ i ]->fl1 += shift;
1019                     selobj[ i ]->fl2 += shift;
1020                     selobj[ i ]->fr1 -= shift;
1021                     selobj[ i ]->fr2 -= shift;
1022                     break;
1023 
1024                 case FD_HCENTER:    /* Center */
1025                     shift = x + w / 2.0 - selobj[ i ]->w / 2.0 - selobj[ i ]->x;
1026                     selobj[ i ]->x   += shift;
1027                     selobj[ i ]->fl1 += shift;
1028                     selobj[ i ]->fl2 += shift;
1029                     selobj[ i ]->fr1 -= shift;
1030                     selobj[ i ]->fr2 -= shift;
1031                     break;
1032 
1033                 case FD_RIGHT:  /* Right */
1034                     shift = x + w - selobj[ i ]->w - selobj[ i ]->x;
1035                     selobj[ i ]->x   += shift;
1036                     selobj[ i ]->fl1 += shift;
1037                     selobj[ i ]->fl2 += shift;
1038                     selobj[ i ]->fr1 -= shift;
1039                     selobj[ i ]->fr2 -= shift;
1040                     break;
1041 
1042                 case FD_TOP:
1043                     shift = y - selobj[ i ]->y;
1044                     selobj[ i ]->y   += shift;
1045                     selobj[ i ]->ft1 += shift;
1046                     selobj[ i ]->ft2 += shift;
1047                     selobj[ i ]->fb1 -= shift;
1048                     selobj[ i ]->fb2 -= shift;
1049                     break;
1050 
1051                 case FD_VCENTER:    /* Center */
1052                     shift = y + h / 2.0 - selobj[ i ]->h / 2.0 - selobj[ i ]->y;
1053                     selobj[ i ]->y   += shift;
1054                     selobj[ i ]->ft1 += shift;
1055                     selobj[ i ]->ft2 += shift;
1056                     selobj[ i ]->fb1 -= shift;
1057                     selobj[ i ]->fb2 -= shift;
1058                     break;
1059 
1060                 case FD_BOTTOM:
1061                     shift = y + h - selobj[ i ]->h - selobj[ i ]->y;
1062                     selobj[ i ]->y   += shift;
1063                     selobj[ i ]->ft1 += shift;
1064                     selobj[ i ]->ft2 += shift;
1065                     selobj[ i ]->fb1 -= shift;
1066                     selobj[ i ]->fb2 -= shift;
1067                     break;
1068             }
1069         }
1070 
1071     redraw_the_form( 0 );
1072     changed = 1;
1073 }
1074 
1075 
1076 /***************************************
1077  * Shows all objects in the selection.
1078  ***************************************/
1079 
1080 void
show_selection(void)1081 show_selection( void )
1082 {
1083     int i;
1084 
1085     if ( backf )
1086         return;         /* Cannot show the backface */
1087 
1088     if ( ! cur_form )
1089         return;
1090 
1091     for ( i = 0; i < selnumb; i++ )
1092         fl_show_object( selobj[ i ] );
1093 }
1094 
1095 
1096 /***************************************
1097  * Hides all objects in the selection.
1098  ***************************************/
1099 
1100 void
hide_selection(void)1101 hide_selection( void )
1102 {
1103     int i;
1104 
1105     if ( backf )
1106         return;         /* Cannot hide the backface */
1107 
1108     if ( ! cur_form )
1109         return;
1110 
1111     for ( i = 0; i < selnumb; i++ )
1112         fl_hide_object( selobj[ i ] );
1113 }
1114 
1115 
1116 /***************************************
1117  * Raises the selected objects
1118  ***************************************/
1119 
1120 void
raise_selection(void)1121 raise_selection( void )
1122 {
1123     int i;
1124     FL_OBJECT **tmpobj;
1125 
1126     if ( backf )
1127         return;         /* Cannot raise the backface */
1128 
1129     if ( ! cur_form )
1130         return;
1131 
1132     tmpobj = fl_malloc( selnumb * sizeof *tmpobj );
1133     memcpy( tmpobj, selobj, selnumb * sizeof *selobj );
1134 
1135     for ( i = 0; i < selnumb; i++ )
1136     {
1137         FL_OBJECT *first,
1138                   *last;
1139 
1140         first = last = selobj[ i ];
1141 
1142         if ( ! first )
1143             continue;
1144 
1145         if ( first->objclass == FL_BEGIN_GROUP )
1146         {
1147             int idx;
1148 
1149             /* If a whole group is selected we move it all at once,
1150                including the objects marking the groups begin and end */
1151 
1152             do
1153             {
1154                 last = last->next;
1155                 if ( ( idx = find_selobject( last ) ) != -1 )
1156                     selobj[ idx ] = NULL;
1157             } while ( last->objclass != FL_END_GROUP );
1158 
1159             /* If the group is already at the end of the forms objects
1160                there's nothing to raise */
1161 
1162             if ( ! last->next )
1163                 continue;
1164         }
1165         else
1166         {
1167             /* If the object has children they also need raising, set last
1168                to the last child belonging to the object */
1169 
1170             if ( last->child )
1171                 while ( last->next && last->next->parent )
1172                     last = last->next;
1173 
1174             /* Nothing to raise if we're already at the end of the list of
1175                objects of the form */
1176 
1177             if ( ! last->next )
1178                 continue;
1179 
1180             /* If the object we raise belongs to a group remove it (and all
1181                it's chilren) from the
1182                group */
1183 
1184             if ( first->group_id )
1185             {
1186                 FL_OBJECT *o;
1187 
1188                 for ( o = first; o != last; o = o->next )
1189                     o->group_id = 0;
1190                 last->group_id = 0;
1191             }
1192         }
1193 
1194         changed = 1;
1195 
1196         first->prev->next = last->next;
1197         last->next->prev  = first->prev;
1198 
1199         first->prev = cur_form->last;
1200         cur_form->last->next = first;
1201         last->next  = NULL;
1202 
1203         cur_form->last = last;
1204     }
1205 
1206     memcpy( selobj, tmpobj, selnumb * sizeof *selobj );
1207     fl_free( tmpobj );
1208     cleanup_selection( );
1209 }
1210 
1211 
1212 /***************************************
1213  * Lowers the selection
1214  ***************************************/
1215 
1216 void
lower_selection(void)1217 lower_selection( void )
1218 {
1219     int i;
1220     FL_OBJECT **tmpobj;
1221 
1222     if ( backf )
1223         return;         /* Cannot lower the backface. */
1224 
1225     if ( ! cur_form )
1226         return;
1227 
1228     tmpobj = fl_malloc( selnumb * sizeof *tmpobj );
1229     memcpy( tmpobj, selobj, selnumb * sizeof *selobj );
1230 
1231     for ( i = selnumb - 1; i >= 0; i-- )
1232     {
1233         FL_OBJECT *first,
1234                   *last;
1235 
1236         first = last = selobj[ i ];
1237 
1238         if ( ! first || first->prev == BackOBJ( ) )
1239             continue;
1240 
1241         if ( first->objclass == FL_END_GROUP )
1242         {
1243             int idx;
1244 
1245             do
1246             {
1247                 first = first->prev;
1248                 if ( ( idx = find_selobject( first ) ) != -1 )
1249                     selobj[ idx ] = NULL;
1250             } while ( first->objclass != FL_BEGIN_GROUP );
1251 
1252             /* If the group is already at the start of the forms objects
1253                (except the backface object) there's nothing to raise */
1254 
1255             if ( first->prev == BackOBJ( ) )
1256                 continue;
1257         }
1258         else
1259         {
1260             /* If the object has children they also need lowering, set last
1261                to the last child belonging to the object */
1262 
1263             if ( last->child )
1264                 while ( last->next && last->next->parent )
1265                     last = last->next;
1266 
1267             /* Nothing to lower if we're already at the start of the list of
1268                objects of the form (module the backface object) */
1269 
1270             if ( first->prev == BackOBJ( ) )
1271                 continue;
1272             /* If the object we raise belongs to a group remove it (and all
1273                it's chilren) from the
1274                group */
1275 
1276             if ( first->group_id )
1277             {
1278                 FL_OBJECT *o;
1279 
1280                 for ( o = first; o != last; o = o->next )
1281                     o->group_id = 0;
1282                 last->group_id = 0;
1283             }
1284         }
1285 
1286         changed = 1;
1287 
1288         first->prev->next = last->next;
1289         if ( last->next )
1290             last->next->prev  = first->prev;
1291         else
1292             cur_form->last = first->prev;
1293 
1294         BackOBJ( )->next->prev = last;
1295         last->next = BackOBJ( )->next;
1296         BackOBJ( )->next = first;
1297         first->prev = BackOBJ( );
1298     }
1299 
1300     memcpy( selobj, tmpobj, selnumb * sizeof *selobj );
1301     fl_free( tmpobj );
1302     cleanup_selection( );
1303 }
1304 
1305 
1306 static FL_OBJECT *cutbuf[ MAXSEL ]; /* Buffered objects */
1307 static int ncut = 0;                /* and their number */
1308 
1309 
1310 /***************************************
1311  ***************************************/
1312 
1313 static void
clear_cutbuffer(void)1314 clear_cutbuffer( void )
1315 {
1316     while ( ncut > 0 )
1317     {
1318         ncut--;
1319 
1320         if ( cutbuf[ ncut ]->u_vdata )
1321             fl_free( cutbuf[ ncut ]->u_vdata );
1322         fl_free_object( cutbuf[ ncut ] );
1323     }
1324 }
1325 
1326 
1327 /***************************************
1328  * Removes all elements in the selection
1329  ***************************************/
1330 
1331 void
cut_selection(void)1332 cut_selection( void )
1333 {
1334     int i;
1335 
1336     if ( backf )
1337         return;         /* Cannot cut the backface. */
1338 
1339     if ( ! cur_form )
1340     {
1341         addform_cb( NULL, 0 );
1342         if ( ! cur_form )
1343             return;
1344     }
1345 
1346     if ( selnumb == 0 )
1347         return;
1348 
1349     clear_cutbuffer( );
1350 
1351     /* Make new deletion and save it */
1352 
1353     for ( i = 0; i < selnumb; i++ )
1354         if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
1355              && selobj[ i ]->objclass != FL_END_GROUP )
1356         {
1357             fl_delete_object( selobj[ i ] );
1358             cutbuf[ ncut++ ] = copy_object( selobj[ i ], 1 );
1359         }
1360 
1361     selnumb = 0;
1362     clear_selection( );
1363 
1364     changed = 1;
1365 }
1366 
1367 
1368 /***************************************
1369  * Pastes elements from buffer into form
1370  ***************************************/
1371 
1372 void
paste_selection(void)1373 paste_selection( void )
1374 {
1375     FL_OBJECT *obj;
1376     double x,
1377            y,
1378            w,
1379            h,
1380            ox,
1381            oy,
1382            shift;
1383     int i;
1384 
1385     if ( ! cur_form || ! ncut )
1386         return;
1387 
1388     is_pasting = 1;     /* horrible hack */
1389 
1390     /* Copy selection from buffer */
1391 
1392     clear_selection( );
1393     redraw_the_form( 0 );
1394 
1395     for ( i = 0; i < ncut; i++ )
1396     {
1397         obj = copy_object( cutbuf[ i ], 1 );
1398 
1399         /* Fix label:  if underlining caused by cutbuf shortcut, remove it.
1400            Note can't use cutbuf as cutbuf does not contain shortcut info */
1401 
1402         if (    obj->label
1403              && strchr( obj->label, *fl_ul_magic_char )
1404              && selobj[ i ]->shortcut[ 0 ] )
1405         {
1406             char *t, *b;
1407 
1408             b = t = fl_strdup( obj->label );
1409             while ( ( b = strchr( b, *fl_ul_magic_char ) ) )
1410                 memmove( b, b + 1, strlen( b ) );
1411             fl_set_object_label( obj, t );
1412             fl_free( t );
1413         }
1414 
1415         fl_add_object( cur_form, obj );
1416         selobj[ selnumb++ ] = obj;
1417     }
1418 
1419     /* Move the selection to the correct place */
1420 
1421     compute_selbox( &x, &y, &w, &h );
1422     ox = x;
1423     oy = y;
1424     move_box( &x, &y, &w, &h, FL_FALSE );
1425 
1426     /* Recompute object position */
1427 
1428     for ( i = 0; i < selnumb; i++ )
1429         if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
1430              && selobj[ i ]->objclass != FL_END_GROUP)
1431         {
1432             shift = x - ox;
1433             selobj[ i ]->x   += shift;
1434             selobj[ i ]->fl1 += shift;
1435             selobj[ i ]->fl2 += shift;
1436             selobj[ i ]->fr1 -= shift;
1437             selobj[ i ]->fr2 -= shift;
1438 
1439             shift = y - oy;
1440             selobj[ i ]->y   += shift;
1441             selobj[ i ]->ft1 += shift;
1442             selobj[ i ]->ft2 += shift;
1443             selobj[ i ]->fb1 -= shift;
1444             selobj[ i ]->fb2 -= shift;
1445 
1446             fli_notify_object( selobj[ i ], FL_RESIZED );
1447         }
1448 
1449     cleanup_selection( );
1450     redraw_the_form( 0 );
1451     changed = 1;
1452     is_pasting = 0;
1453 }
1454 
1455 
1456 /***************************************
1457  * Copies all elements in the selection to the buffer
1458  ***************************************/
1459 
1460 void
copy_selection(void)1461 copy_selection( void )
1462 
1463 {
1464     int i;
1465 
1466     if ( backf || selnumb == 0 || ! cur_form )
1467         return;
1468 
1469     clear_cutbuffer( );
1470 
1471     /* Copy the objects */
1472 
1473     for ( i = 0; i < selnumb; i++ )
1474         if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
1475              && selobj[ i ]->objclass != FL_END_GROUP )
1476             cutbuf[ ncut++ ] = copy_object( selobj[ i ], 0 );
1477 }
1478 
1479 
1480 /***************************************
1481  * Makes a copy of the current selection
1482  ***************************************/
1483 
1484 FL_OBJECT **
dup_selection(void)1485 dup_selection( void )
1486 {
1487     FL_OBJECT **ob;
1488     int i;
1489 
1490     if ( ! selnumb )
1491         return NULL;
1492 
1493     ob = fl_malloc( ( selnumb + 1 ) * sizeof *ob );
1494 
1495     for ( i = 0; i < selnumb; i++ )
1496         ob[ i ] = copy_object( selobj[ i ], 1 );
1497 
1498     ob[ selnumb ] = NULL;
1499 
1500     return ob;
1501 }
1502 
1503 
1504 /***************************************
1505  ***************************************/
1506 
1507 void
free_dupped_selection(FL_OBJECT ** ob)1508 free_dupped_selection( FL_OBJECT ** ob )
1509 {
1510     int i;
1511 
1512     for ( i = 0; ob[ i ]; i++ )
1513         fl_free_object( ob[ i ] );
1514 
1515     fl_free( ob );
1516 }
1517 
1518 
1519 /***************************************
1520  * Changes the selection to a new list of objects and show it.
1521  * The pointer received must be an array of object pointers
1522  * with the last element being set to NULL.
1523  ***************************************/
1524 
1525 void
set_selection(FL_OBJECT ** ob)1526 set_selection( FL_OBJECT ** ob )
1527 {
1528     FL_OBJECT *obj;
1529     int i;
1530 
1531     for ( i = 0; i < selnumb; i++ )
1532         fl_delete_object( selobj[ i ] );
1533 
1534     clear_selection( );
1535     redraw_the_form( 0 );
1536 
1537     for ( selnumb = 0; selnumb < MAXSEL && ob[ selnumb ]; selnumb++ )
1538     {
1539         obj = copy_object( ob[ selnumb ], 1 );
1540         if (    selobj[ selnumb ]->objclass != FL_BEGIN_GROUP
1541              && selobj[ selnumb ]->objclass != FL_END_GROUP )
1542             fl_add_object( cur_form, obj );
1543         selobj[ selnumb ] = obj;
1544     }
1545 
1546     redraw_the_form( 0 );
1547 }
1548 
1549 
1550 /***************************************
1551  ***************************************/
1552 
1553 void
next_selection(void)1554 next_selection( void )
1555 {
1556     if ( ! cur_form || ! BackOBJ( ) )
1557         return;
1558 
1559     do
1560     {
1561         if ( ! selnumb || ! selobj[ 0 ]->next )
1562             selobj[ 0 ] = BackOBJ( )->next ? BackOBJ( )->next : BackOBJ( );
1563         else if ( selnumb && selobj[ 0 ]->next )
1564             selobj[ 0 ] = selobj[ 0 ]->next;
1565         selnumb = 1;
1566     } while (    selobj[ 0 ]->parent
1567               || selobj[ 0 ]->objclass == FL_BEGIN_GROUP
1568               || selobj[ 0 ]->objclass == FL_END_GROUP );
1569 
1570     redraw_the_form( 0 );
1571 }
1572 
1573 
1574 /***************************************
1575  ***************************************/
1576 
1577 void
prev_selection(void)1578 prev_selection( void )
1579 {
1580     if ( ! cur_form || ! BackOBJ( ) )
1581         return;
1582 
1583     do
1584     {
1585         if ( ! selnumb || ! selobj[ 0 ]->prev )
1586             selobj[ 0 ] = BackOBJ( )->prev ? BackOBJ( )->prev : BackOBJ( );
1587         else if ( selnumb && selobj[ 0 ]->prev )
1588             selobj[ 0 ] = selobj[ 0 ]->prev;
1589     } while ( selobj[ 0 ]->parent );
1590 
1591     selnumb = 1;
1592     redraw_the_form( 0 );
1593 }
1594 
1595 
1596 /***************************************
1597  * Groups all elements in the selection into a group
1598  ***************************************/
1599 
1600 void
group_selection(void)1601 group_selection( void )
1602 {
1603     int i;
1604     FL_OBJECT *obj;
1605     const char *s;
1606 
1607     if ( backf )
1608         return;         /* Cannot group the backface */
1609 
1610     if ( ! cur_form || selnumb == 0 )
1611         return;
1612 
1613  get_new_group_name:
1614 
1615     if ( ! ( s = fl_show_input( "Group name (must be usable as "
1616                                 "a C variable or empty):", "" ) ) )
1617         return;
1618 
1619     if ( *s && ! is_valid_c_name( s ) )
1620     {
1621         fl_show_alert( "Error", "Invalid C identifier for group "
1622                        "name:", s, 0 );
1623         goto get_new_group_name;
1624     }
1625 
1626     obj = add_an_object( FL_BEGIN_GROUP, -1, 0, 0, 0, 0 );
1627 
1628     for ( i = 0; i < selnumb; i++ )
1629     {
1630         if ( selobj[ i ]->form )
1631             fl_delete_object( selobj[ i ] );
1632 
1633         if (    selobj[ i ]->objclass != FL_BEGIN_GROUP
1634              && selobj[ i ]->objclass != FL_END_GROUP )
1635             fl_add_object( cur_form, selobj[ i ] );
1636     }
1637 
1638     add_an_object( FL_END_GROUP, -1, 0, 0, 0, 0 );
1639     clear_selection( );
1640     set_object_name( obj, s, "", "" );
1641     addgroupto_selection( obj );
1642     changed = 1;
1643 }
1644 
1645 
1646 /***************************************
1647  * Removes begin and endgroups from the selection
1648  ***************************************/
1649 
1650 void
flatten_selection(void)1651 flatten_selection( void )
1652 {
1653     int i, j;
1654 
1655     /* Cannot flatten the backface */
1656 
1657     if ( backf )
1658         return;
1659 
1660     if ( ! cur_form )
1661         return;
1662 
1663     for ( i = 0; i < selnumb; i++ )
1664     {
1665         /* Bothig to be done for selected object that aren't part of a group */
1666 
1667         if ( selobj[ i ]->objclass != FL_BEGIN_GROUP )
1668             continue;
1669 
1670         /* Unset the group ID of all the objects that rae part of the group
1671            (unless. of course, the object for the start and the end of the
1672            group. that will keep them from getting deleted when the object
1673            for the start of thegroup is deleted. */
1674 
1675         for ( j = i + 1; j < selnumb; j++ )
1676             if ( selobj[ j ]->objclass == FL_END_GROUP )
1677                 break;
1678             else
1679                 selobj[ j ]->group_id = 0;
1680 
1681         /* Delete the obkect for the start of the group - this will also
1682            delete the object for teh end of the group (but ot the actual
1683            members of the group since we just reset theirgroup ID) */
1684 
1685         fl_delete_object( selobj[ i ] );
1686 
1687         /* Mark start and end object in the list of selected objects as
1688            deleted */
1689 
1690         selobj[ i ] = NULL;
1691         if ( j < selnumb )
1692             selobj[ j ] = NULL;
1693 
1694         /* Look for more grouped objects in the list of selected objects */
1695 
1696         i = j;
1697     }
1698 
1699     cleanup_selection( );
1700     changed = 1;
1701 }
1702 
1703 
1704 /***************************************
1705  * Makes a copy of the object. Only if 'exact' is set
1706  * the objects name is copied.
1707  ***************************************/
1708 
1709 static FL_OBJECT *
copy_object(FL_OBJECT * obj,int exact)1710 copy_object( FL_OBJECT * obj,
1711              int         exact )
1712 {
1713     char name[ MAX_VAR_LEN ],
1714          cbname[ MAX_VAR_LEN ],
1715          argname[ MAX_VAR_LEN ];
1716     FL_OBJECT *obj2;
1717     char *label;
1718     char *s;
1719 
1720     obj2 = add_an_object( obj->objclass, obj->type, obj->x, obj->y,
1721                           obj->w, obj->h );
1722 
1723     get_object_name( obj, name, cbname, argname );
1724     set_object_name( obj2, exact ? name : "", cbname, argname );
1725     set_attribs( obj2, obj );
1726 
1727     s = label = fl_strdup( obj->label );
1728     while ( ( s = strchr( s, '\010' ) ) )
1729         memmove( s, s + 1, strlen( s ) + 1 );
1730 
1731     fl_set_object_label( obj2, label );
1732     fl_free( label );
1733 
1734     /* Also copy the object specific info */
1735 
1736     copy_superspec( obj2, obj );
1737     superspec_to_spec( obj2 );
1738 
1739     copy_iconinfo( obj2, obj );
1740     restore_spec( obj2 );
1741 
1742     fl_delete_object( obj2 );
1743 
1744     return obj2;
1745 }
1746 
1747 
1748 /***************************************
1749  * Sets the attributes of an object
1750  ***************************************/
1751 
1752 static void
set_attribs(FL_OBJECT * obj,FL_OBJECT * src)1753 set_attribs( FL_OBJECT * obj,
1754              FL_OBJECT * src )
1755 {
1756     obj->boxtype = src->boxtype;
1757     obj->col1    = src->col1;
1758     obj->col2    = src->col2;
1759     obj->lcol    = src->lcol;
1760     obj->lsize   = src->lsize;
1761     obj->lstyle  = src->lstyle;
1762 
1763     if (    obj->objclass == FL_SLIDER
1764          && ! ( obj->type & FL_VERT_PROGRESS_BAR ) )
1765     {
1766         obj->align = fl_to_outside_lalign( obj->align );
1767         if ( fl_is_center_lalign( obj->align ) )
1768             obj->align = FL_SLIDER_ALIGN;
1769     }
1770     else
1771         obj->align = src->align;
1772 
1773     obj->nwgravity  = src->nwgravity;
1774     obj->segravity  = src->segravity;
1775     obj->resize     = src->resize;
1776     obj->how_return = src->how_return;
1777 
1778     fli_handle_object( obj, FL_ATTRIB, 0, 0, 0, NULL, 0 );
1779 
1780     /* Some extra adjustments for spinner objects (this is a hack but
1781        avoiding it would require a complete change of how fdesign works) */
1782 
1783     if ( obj->objclass == FL_SPINNER )
1784     {
1785         FL_OBJECT *subobj = fl_get_spinner_input( obj );
1786 
1787         subobj->col1 = src->col1;
1788         subobj->col2 = src->col2;
1789 
1790         subobj->lstyle = src->lstyle;
1791         subobj->lsize  = src->lsize;
1792 
1793         fli_handle_object( subobj, FL_ATTRIB, 0, 0, 0, NULL, 0 );
1794    }
1795 }
1796 
1797 
1798 /*
1799  * Local variables:
1800  * tab-width: 4
1801  * indent-tabs-mode: nil
1802  * End:
1803  */
1804