Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / pal_group.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23
24 /*
25  *      $XConsortium: pal_group.c /main/6 1996/08/30 14:01:29 mustafa $
26  *
27  *      @(#)pal_group.c 1.58 08 May 1995
28  *
29  *      RESTRICTED CONFIDENTIAL INFORMATION:
30  *
31  *      The information in this document is subject to special
32  *      restrictions in a confidential disclosure agreement between
33  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
35  *      Sun's specific written approval.  This document and all copies
36  *      and derivative works thereof must be returned or destroyed at
37  *      Sun's request.
38  *
39  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40  *
41  */
42
43
44 /*
45  * pal_group.c - Implements Group object functionality
46  */
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <X11/Xlib.h>
51 #include <Xm/Xm.h>
52 #include <ab_private/ab.h>
53 #include <ab_private/trav.h>
54 #include <ab_private/pal.h>
55 #include <ab_private/prop.h>
56 #include <ab_private/brws.h>
57 #include <ab_private/abobj.h>
58 #include <ab_private/objxm.h>
59 #include <ab_private/abobj_set.h>
60 #include <ab_private/proj.h>
61 #include <ab_private/ui_util.h>
62 #include <ab_private/x_util.h>
63 #include <ab_private/abobj_edit.h>
64 #include "dtbuilder.h"
65 #include "abobjP.h"
66 #include "group_ui.h"
67
68
69 /*
70  * Bitmaps
71  */
72 #include "bitmaps/ggp_as_is.xbm"
73 #include "bitmaps/ggp_col.xbm"
74 #include "bitmaps/ggp_row.xbm"
75 #include "bitmaps/ggp_rowcol.xbm"
76 #include "bitmaps/align_top.xbm"
77 #include "bitmaps/align_hcenter.xbm"
78 #include "bitmaps/align_bottom.xbm"
79 #include "bitmaps/align_left.xbm"
80 #include "bitmaps/align_labels.xbm"
81 #include "bitmaps/align_vcenter.xbm"
82 #include "bitmaps/align_right.xbm"
83
84 /*
85  * Defines
86  */
87
88 #define HOFFSET 10
89 #define VOFFSET 8
90 #define NUMROWCOL 2
91
92 typedef struct  PROP_GROUP_SETTINGS
93 {
94     Widget                      prop_sheet;
95     PropFieldSettingRec         name;
96     PropOptionsSettingRec       frame;
97     PropRadioSettingRec         layout_type;
98     PropRadioSettingRec         grid_rowcol;
99     PropFieldSettingRec         grid_rowcol_count;
100     PropOptionsSettingRec       valign;
101     PropFieldSettingRec         vspacing;
102     PropOptionsSettingRec       halign;
103     PropFieldSettingRec         hspacing;
104     PropGeometrySettingRec      pos;
105     PropCheckboxSettingRec      init_state;
106     PropColorSettingRec         bg_color;
107     ABObj                       current_obj;
108 } PropGroupSettingsRec, *PropGroupSettings;
109
110 /*************************************************************************
111 **                                                                      **
112 **       Private Function Declarations                                  **
113 **                                                                      **
114 **************************************************************************/
115 /*
116  * Methods
117  */
118 static int      group_initialize(
119                     ABObj   obj
120                 );
121 static Widget   group_prop_init(
122                     Widget  parent,
123                     AB_PROP_TYPE type
124                 );
125
126 static int      group_prop_activate(
127                     AB_PROP_TYPE type,
128                     BOOL         active
129                 );
130 static int      group_prop_load(
131                     ABObj        obj,
132                     AB_PROP_TYPE type,
133                     unsigned long loadkey
134                 );
135 static int      group_prop_clear(
136                     AB_PROP_TYPE type
137                 );
138 static int      group_prop_apply(
139                     AB_PROP_TYPE type
140                 );
141
142 static BOOL     group_prop_pending(
143                     AB_PROP_TYPE type
144                 );
145
146 static BOOL     verify_props(
147                     AB_PROP_TYPE type
148                 );
149 static void     turnoff_changebars(
150                     AB_PROP_TYPE type
151                 );
152 static void     setup_grouptype_settings(
153                     AB_PROP_TYPE type,
154                     AB_GROUP_TYPE gtype
155                 );
156 static void     set_new_group_size(
157                     ABObj obj
158                 );
159
160 static void     group_objects(
161                     ABObj       newgroup,
162                     ABObj       *obj_list,
163                     int         count
164                 );
165
166 static void     ungroup_objects(
167                     ABObj       *obj_list,
168                     int         count
169                 );
170
171 static void     group_align_tops(
172                     ABObj   obj
173                 );
174
175 static void     group_align_hcenters(
176                     ABObj   obj,
177                     BOOL    init
178                 );
179
180 static void     group_align_horiz_same_size(
181                     ABObj   obj
182                 );
183
184 static void     group_align_bottoms(
185                     ABObj   obj
186                 );
187
188 static void     group_align_left(
189                     ABObj   obj
190                 );
191
192 static void     group_align_labels(
193                     ABObj   obj
194                 );
195
196 static void     group_align_vcenters(
197                     ABObj   obj,
198                     BOOL    init
199                 );
200
201 static void     group_align_right(
202                     ABObj   obj
203                 );
204
205 static void     create_member_list(
206                    ABObj  cobj,
207                    ABObj  **member_list,
208                    int    *member_count
209                 );
210
211 static void     get_cell_size(
212                     ABObj       group,
213                     int         *cell_width,
214                     int         *cell_height
215                 );
216
217 static void     get_row_col(
218                     ABObj       group,
219                     int         *rows,
220                     int         *cols
221                 );
222
223 static void     group_align_rows(
224                     ABObj       obj,
225                     BOOL        init
226                 );
227
228 static void     group_align_cols(
229                     ABObj       obj,
230                     BOOL        init
231                 );
232
233 static void     get_widest_label_obj(
234                     ABObj       *list,
235                     int         count,
236                     ABObj       *widest_label,
237                     int         *label_width
238                 );
239
240 static void     get_widest_value_obj(
241                     ABObj       *list,
242                     int         count,
243                     ABObj       *widest_value,
244                     int         *value_width
245                 );
246
247 /*
248  * Callbacks
249  */
250 static void     grouptypeCB(
251                     Widget   widget,
252                     XtPointer clientdata,
253                     XmToggleButtonCallbackStruct *state
254                 );
255
256 static void     undo_group(
257                     ABUndoRec   undo_rec
258                 );
259
260 static void     undo_ungroup(
261                     ABUndoRec   undo_rec
262                 );
263
264 static ABObj    get_child(
265                     ABObj       group,
266                     int         x_pos,
267                     int         y_pos
268                 );
269
270 static void     group_expose_handler(
271                     Widget      widget,
272                     XtPointer   client_data,
273                     XEvent      *event,
274                     Boolean     *cont_dispatch
275                 );
276
277 DtbGroupPropDialogInfoRec       rev_group_prop_dialog;
278
279 /*************************************************************************
280 **                                                                      **
281 **       Data                                                           **
282 **                                                                      **
283 **************************************************************************/
284 PalItemInfo group_palitem_rec = {
285     /* type             */  AB_TYPE_CONTAINER,
286     /* name             */  "Group",
287     /* animation pixmaps*/  NULL,
288     /* number of pixmaps*/  0,
289     /* rev_prop_frame   */  NULL,
290     /* fix_prop_dialog  */  NULL,
291     /* initialize       */  group_initialize,
292     /* is_a_test        */  obj_is_group,
293     /* prop_initialize  */  group_prop_init,
294     /* prop_active      */  group_prop_activate,
295     /* prop_clear       */  group_prop_clear,
296     /* prop_load        */  group_prop_load,
297     /* prop_apply       */  group_prop_apply,
298     /* prop_pending     */  group_prop_pending
299 };
300
301 PalItemInfo *ab_group_palitem = &group_palitem_rec;
302 PropGroupSettingsRec prop_group_settings_rec[AB_PROP_TYPE_NUM_VALUES];
303
304 /*************************************************************************
305 **                                                                      **
306 **       Function Definitions                                           **
307 **                                                                      **
308 **************************************************************************/
309
310 /*
311  * Create a group object out of the selected group of objects.
312  */
313 void
314 abobj_group_selected_objects(
315 )
316 {
317     ABObj         project = proj_get_project();
318     ABObj         obj;
319     ABObj         newgroup;
320     ABObj         obj_parent;
321     ABSelectedRec sel;
322     XRectangle    current_rect;
323     int           i;
324
325     /* Creation may take awhile, so set busy cursor */
326     ab_set_busy_cursor(True);
327
328     abobj_get_selected(project, False, False, &sel);
329     abobj_get_rect_for_objects(sel.list, sel.count, &current_rect);
330     obj_parent = obj_get_parent(sel.list[0]);
331
332     newgroup = obj_create(AB_TYPE_CONTAINER, obj_parent);
333     obj_set_subtype(newgroup, AB_CONT_GROUP);
334
335     if (group_initialize(newgroup) == ERROR)
336         fprintf(stderr, "create_obj_action: couldn't initialize object\n");
337     else if (abobj_show_tree(newgroup, False) == -1)
338         fprintf(stderr,"create_obj_action: couldn't show object\n");
339     else
340     {
341
342         /* Deselect any objects that happen to be selected */
343         abobj_deselect_all(project);
344         aob_deselect_all_objects(project);
345
346         group_objects(newgroup, sel.list, sel.count);
347
348         /*
349          * Can only create one group at a time, therefore
350          * only worry about undoing one group.
351          */
352         abobj_set_undo(&newgroup, 1, undo_group, AB_UNDO_GROUP);
353
354     }
355
356     /* Restore to original cursor */
357     ab_set_busy_cursor(False);
358
359 }
360
361 static void
362 group_objects(
363     ABObj       newgroup,
364     ABObj       *list,
365     int         count
366 )
367 {
368     ABObj         obj;
369     ABSelectedRec sel;
370     XRectangle    current_rect;
371     int           i;
372
373     abobj_get_rect_for_objects(list, count, &current_rect);
374
375     /*
376     * Reparent each selected object and set x,y to group
377     * coordinates.
378     */
379     for (i = 0; i < count; i++)
380     {
381         AB_TRAVERSAL    trav;
382         ABObj           cur_obj = NULL;
383
384         obj = list[i];
385         obj_reparent(obj, newgroup);
386         abobj_set_xy(obj, obj_get_x(obj) - current_rect.x,
387                           obj_get_y(obj) - current_rect.y);
388         /*
389          * Clear instantiated flag in child
390          */
391         obj_clear_flag(obj, InstantiatedFlag);
392
393         /*
394          * Clear instantiated flag in child subtree as
395          * well
396          */
397         for (trav_open(&trav, obj, AB_TRAV_ALL);
398                 (cur_obj = trav_next(&trav)) != NULL; )
399         {
400             obj_clear_flag(cur_obj, InstantiatedFlag);
401         }
402         trav_close(&trav);
403
404     }
405
406     /*
407      * For some reason, width and height need to be set on the
408      * group.
409      */
410 /*
411     obj_set_width(newgroup, current_rect.width);
412     obj_set_height(newgroup, current_rect.height);
413 */
414
415     abobj_tree_instantiate_changes(newgroup);
416
417     /* Make the new obj selected */
418     abobj_select(newgroup);
419 }
420
421
422
423 /*
424  * Ungroup a group. Get list of selected objects, look for groups
425  * in the list. If found, traverse throught the groups children and
426  * re-parent/re-position the child. Finally, keep a list of new parents
427  * to be updated (so that no parent is updated more than once) and update
428  * them after all groups have been ungrouped.
429  */
430 void
431 abobj_ungroup_selected_objects(
432 )
433 {
434     ABObj         project = proj_get_project();
435     ABSelectedRec sel;
436
437     /* Ungrouping may take awhile, so set busy cursor */
438     ab_set_busy_cursor(True);
439
440     /* Get list of selected objects */
441     abobj_get_selected(project, False, False, &sel);
442
443     /*
444      * Remember all objects that were ungrouped so can undo this later
445      */
446     abobj_set_undo(sel.list, sel.count, undo_ungroup, AB_UNDO_UNGROUP);
447
448     ungroup_objects(sel.list, sel.count);
449
450     /* Restore to original cursor */
451     ab_set_busy_cursor(False);
452 }
453
454 /*
455  * Ungroups passed objects. Look for groups in the list. If found,
456  * traverse throught the groups children and re-parent/re-position the
457  * child. Finally, keep a list of new parents to be updated so that
458  * no parent is updated more than once and update them after all groups
459  * have been ungrouped.
460  */
461 static void
462 ungroup_objects(
463     ABObj       *obj_list,
464     int         count
465 )
466 {
467     ABObj         group;
468     ABObj         group_parent;
469     ABObj         parent_list = NULL;
470     XRectangle    group_rect,
471                         rect;
472     AB_TRAVERSAL  trav;
473     ABObj         member;
474     int           i, j;
475     ABObj         *list = NULL;
476     int           list_items;
477     Boolean       parent_exists = True;
478
479     if (!obj_list || (count <= 0))
480         return;
481
482     for (i = 0; i < count; i++)
483     {
484         group = obj_list[i];
485         if (obj_is_group(group))
486         {
487             ABObj       oobj = NULL,
488                         *member_list = NULL;
489             int         num_children,
490                         cur_member = 0;
491
492             abobj_deselect(group);
493             group_parent = obj_get_parent(group);
494
495             /*
496              * Remember group's position
497              */
498             group_rect.x = group_rect.y = 0;
499             x_get_widget_rect(objxm_get_widget(group), &group_rect);
500
501             oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
502             num_children = obj_get_num_children(oobj);
503
504             member_list = (ABObj *)util_malloc(num_children * sizeof(ABObj*));
505
506             /*
507              * Group members are all direct children of the AB_CFG_OBJECT_OBJ
508              * object
509              */
510             for (trav_open(&trav, oobj, AB_TRAV_CHILDREN |
511                             AB_TRAV_MOD_SAFE);
512                 (member = trav_next(&trav)) != NULL; )
513             {
514                 Widget  member_w;
515
516                 member_w = objxm_get_widget(member);
517
518                 /*
519                  * Get member's current position
520                  */
521                 rect.x = rect.y = 0;
522                 x_get_widget_rect(member_w, &rect);
523
524                 obj_reparent(member, group_parent);
525
526                 /*
527                  * Set attachments with 0 x and y. abobj_set_xy will
528                  * set the correct values.
529                 */
530                 obj_init_attachments(member);
531                 obj_set_attachment(member, AB_CP_NORTH, AB_ATTACH_POINT,
532                                         NULL, 0);
533                 obj_set_attachment(member, AB_CP_WEST,  AB_ATTACH_POINT,
534                                         NULL, 0);
535
536                 /*
537                  * Set new position to be:
538                  *      group's (x, y) + current (x, y)
539                  */
540                 abobj_set_xy(member, group_rect.x + rect.x,
541                                      group_rect.y + rect.y);
542
543                 /*
544                  * Keep track of objects to re-instantiate later
545                  * We don't do it here because we don't want to screw up
546                  * the x_get_widget_rect() calls in the current group.
547                  */
548                 member_list[cur_member++] = member;
549
550             }
551             trav_close(&trav);
552
553             /*
554              * Un/re-instantiate former group members
555              */
556             for (cur_member = 0; cur_member < num_children; ++cur_member)
557             {
558                 ABObj           cur_obj = NULL;
559
560                 /*
561                  * Clear instantiated flag in former group member
562                  */
563                 obj_clear_flag(member_list[cur_member], InstantiatedFlag);
564
565                 /*
566                  * Clear instantiated flag in former group member's subtree
567                  * as well
568                  */
569                 for (trav_open(&trav, member_list[cur_member], AB_TRAV_ALL);
570                     (cur_obj = trav_next(&trav)) != NULL; )
571                 {
572                     obj_clear_flag(cur_obj, InstantiatedFlag);
573                 }
574
575                 /*
576                  * The manage_lat parameter used to be FALSE.
577                  * It caused list objects to get the wrong size when
578                  * ungroup was done. Changing to TRUE somehow fixes
579                  * this.
580                  */
581                 abobj_show_tree(member_list[cur_member], TRUE);
582             }
583
584             util_free(member_list);
585
586             obj_destroy(group);
587
588            /*
589             * Keep a list of parents (control panels) that need
590             * to be updated after all groups are ungrouped.
591             */
592             if (list == NULL)
593             {
594                 list = (ABObj*)XtMalloc(sizeof(ABObj));
595                 list[0] = group_parent;
596                 list_items = 1;
597             }
598             else
599             for (j = 0; j < list_items; j++)
600             {
601                 if (list[j] == group_parent)
602                     {
603                         parent_exists = True;
604                         break;
605                     }
606             }
607             if (parent_exists == False)
608             {
609                 XtRealloc((char*)list, sizeof(ABObj));
610                 list[list_items++] = group_parent;
611             }
612             parent_exists = False;
613         }
614     }
615 }
616
617
618 static int
619 group_initialize(
620     ABObj    obj
621 )
622 {
623     ABObj          iobj, mobj;
624     AB_GROUP_TYPE group_type;
625     int            i;
626     ABObj          parent = obj_get_parent(obj);
627     ABSelectedRec  sel;
628     XRectangle     current_rect;
629
630
631     abobj_get_selected(proj_get_project(), False, False, &sel);
632     abobj_get_rect_for_objects(sel.list, sel.count, &current_rect);
633
634     obj_set_unique_name(obj, "group");
635
636 /*
637     abobj_set_initial_state(obj, AB_STATE_ACTIVE);
638 */
639     obj_set_is_initially_active(obj, True);
640
641     obj_set_x(obj, current_rect.x);
642     obj_set_y(obj, current_rect.y);
643     /*
644     obj_set_width(obj, current_rect.width);
645     obj_set_height(obj, current_rect.height);
646     */
647
648     obj_set_group_type(obj, AB_GROUP_IGNORE);
649
650     /* Set up Default Layout for group*/
651     obj_set_attachment(obj, AB_CP_NORTH, AB_ATTACH_POINT, NULL, obj->y);
652     obj_set_attachment(obj, AB_CP_WEST,  AB_ATTACH_POINT, NULL, obj->x);
653
654     return OK;
655 }
656
657
658
659 static Widget
660 group_prop_init(
661     Widget    parent,
662     AB_PROP_TYPE type
663 )
664 {
665     /* Revolving Props */
666     /*
667     DtbGroupPropDialogInfoRec   rev_group_prop_dialog;
668     */
669     DtbGroupPropDialogInfo      cgen = &dtb_group_prop_dialog; /* Codegen structure */
670     DtbRevolvPropDialogInfo     rpd = &(dtb_revolv_prop_dialog);
671     PropGroupSettingsRec        *pgs = &(prop_group_settings_rec[type]);
672     Widget                      item[10];
673     int                         item_val[10];
674     int                         n;
675     int                         i;
676
677     if (type == AB_PROP_REVOLVING)
678     {
679         /* Cloning Trick:
680          * Only the Attributes ControlPanel needs to be created within
681          * the existing Revolving Prop dialog, so fill out all other
682          * fields with the Revolving Prop dialog equivelents, so the
683          * dtb initialize proc will skip those non-NULL fields...
684          */
685         dtbGroupPropDialogInfo_clear(&rev_group_prop_dialog);
686
687         cgen = &(rev_group_prop_dialog);
688         cgen->prop_dialog = rpd->prop_dialog;
689         cgen->prop_dialog_shellform = rpd->prop_dialog_shellform;
690         cgen->prop_dialog_panedwin = rpd->prop_dialog_panedwin;
691         cgen->prop_dialog_form = rpd->prop_dialog_form;
692         cgen->objlist_panel = rpd->objlist_panel;
693         cgen->objlist_label = rpd->objlist_label2;
694         cgen->objlist_scrolledwin = rpd->objlist_scrolledwin;
695         cgen->objlist = rpd->objlist;
696         cgen->attrs_ctrlpanel_frame = rpd->attrs_ctrlpanel_frame;
697         cgen->activate_panel = rpd->activate_panel;
698         cgen->apply_button = rpd->apply_button;
699         cgen->ok_button = rpd->ok_button;
700         cgen->cancel_button = rpd->cancel_button;
701         cgen->reset_button = rpd->reset_button;
702         cgen->help_button = rpd->help_button;
703
704     }
705     else /* AB_PROP_FIXED */
706         cgen = &dtb_group_prop_dialog;
707
708     if (dtb_group_prop_dialog_initialize(cgen, parent) == 0)
709     {
710         pgs->prop_sheet = cgen->attrs_ctrlpanel;
711         pgs->current_obj = NULL;
712
713         if (type == AB_PROP_REVOLVING)
714                 XtVaSetValues(parent,
715                         XmNuserData, pgs->current_obj,
716                         NULL);
717
718         /* Dialog/Object List */
719         if (type == AB_PROP_FIXED)
720         {
721             prop_fixed_dialog_init(ab_group_palitem,
722                         cgen->prop_dialog_shellform, cgen->objlist);
723             prop_activate_panel_init(type, ab_group_palitem,
724                         cgen->ok_button, cgen->apply_button,
725                         cgen->reset_button, cgen->cancel_button,
726                         cgen->help_button);
727         }
728
729         /* Alternate Editor Buttons */
730         prop_editors_panel_init(type, ab_group_palitem,
731                     cgen->attach_button, cgen->conn_button, cgen->helptxt_button);
732
733         /*
734           * Prop Sheet Settings....
735          */
736
737         /* Name */
738         prop_field_init(&(pgs->name), cgen->name_field_label,
739                             cgen->name_field, cgen->name_cb);
740
741         /* Border Frame Setting */
742         n = 0;
743         item[n] = cgen->bframe_opmenu_items.None_item;
744         item_val[n] = AB_LINE_NONE; n++;
745         item[n] = cgen->bframe_opmenu_items.Shadow_Out_item;
746         item_val[n] = AB_LINE_SHADOW_OUT; n++;
747         item[n] = cgen->bframe_opmenu_items.Shadow_In_item;
748         item_val[n] = AB_LINE_SHADOW_IN; n++;
749         item[n] = cgen->bframe_opmenu_items.Etched_Out_item;
750         item_val[n] = AB_LINE_ETCHED_OUT; n++;
751         item[n] = cgen->bframe_opmenu_items.Etched_In_item;
752         item_val[n] = AB_LINE_ETCHED_IN; n++;
753         prop_options_init(&(pgs->frame), cgen->bframe_opmenu_label,
754                             cgen->bframe_opmenu, cgen->bframe_opmenu_menu,
755                             n, item, (XtPointer*)item_val,
756                             cgen->bframe_cb);
757
758         /* Layout Type */
759         n = 0;
760         item[n] = cgen->layout_rbox_items.bitmaps_ggp_as_is_xbm_item;
761         item_val[n] = AB_GROUP_IGNORE; n++;
762         item[n] = cgen->layout_rbox_items.bitmaps_ggp_col_xbm_item;
763         item_val[n] = AB_GROUP_COLUMNS; n++;
764         item[n] = cgen->layout_rbox_items.bitmaps_ggp_row_xbm_item;
765         item_val[n] = AB_GROUP_ROWS; n++;
766         item[n] = cgen->layout_rbox_items.bitmaps_ggp_rowcol_xbm_item;
767         item_val[n] = AB_GROUP_ROWSCOLUMNS; n++;
768         prop_radiobox_init(&(pgs->layout_type), cgen->layout_rbox_label,
769                         cgen->layout_rbox, n, item, (XtPointer*)item_val,
770                         cgen->layout_cb1);
771
772         for (i=0; i < n; i++)
773             XtAddCallback(item[i], XmNvalueChangedCallback,
774                         (XtCallbackProc)grouptypeCB, (XtPointer)type);
775
776         /*
777         ui_set_active(cgen->layout_rbox_items.bitmaps_ggp_rowcol_xbm_item, False);
778         */
779
780         /* Grid Row/Columns */
781         n = 0;
782         item[n] = cgen->gridrowcol_rbox_items.Rows_item;
783         item_val[n] = AB_ORIENT_HORIZONTAL; n++;
784         item[n] = cgen->gridrowcol_rbox_items.Columns_item;
785         item_val[n] = AB_ORIENT_VERTICAL; n++;
786         prop_radiobox_init(&(pgs->grid_rowcol), NULL,
787                         cgen->gridrowcol_rbox, n, item, (XtPointer*)item_val,
788                         cgen->gridrowcol_cb);
789
790         /* Grid Row/Column count */
791         prop_field_init(&(pgs->grid_rowcol_count), NULL,
792                         cgen->gridrowcol_field, cgen->gridrowcol_cb);
793
794         /* Vertical Alignment */
795         n = 0;
796         item[n] = cgen->valign_opmenu_items.bitmaps_align_left_xbm_item;
797         item_val[n] = AB_ALIGN_LEFT; n++;
798         item[n] = cgen->valign_opmenu_items.bitmaps_align_labels_xbm_item;
799         item_val[n] = AB_ALIGN_LABELS; n++;
800         item[n] = cgen->valign_opmenu_items.bitmaps_align_vcenter_xbm_item;
801         item_val[n] = AB_ALIGN_VCENTER; n++;
802         item[n] = cgen->valign_opmenu_items.bitmaps_align_right_xbm_item;
803         item_val[n] = AB_ALIGN_RIGHT; n++;
804         prop_options_init(&(pgs->valign), cgen->valign_opmenu_label,
805                             cgen->valign_opmenu, cgen->valign_opmenu_menu,
806                             n, item, (XtPointer*)item_val,
807                             cgen->valign_cb);
808
809         /* Vertical spacing value */
810         prop_field_init(&(pgs->vspacing), NULL,
811                         cgen->vert_spacing_field, cgen->valign_cb);
812
813         /* Horizontal Alignment */
814         n = 0;
815         item[n] = cgen->halign_opmenu_items.bitmaps_align_top_xbm_item;
816         item_val[n] = AB_ALIGN_TOP; n++;
817         item[n] = cgen->halign_opmenu_items.bitmaps_align_hcenter_xbm_item;
818         item_val[n] = AB_ALIGN_HCENTER; n++;
819         item[n] = cgen->halign_opmenu_items.bitmaps_align_bottom_xbm_item;
820         item_val[n] = AB_ALIGN_BOTTOM; n++;
821         prop_options_init(&(pgs->halign), cgen->halign_opmenu_label,
822                             cgen->halign_opmenu, cgen->halign_opmenu_menu,
823                             n, item, (XtPointer*)item_val,
824                             cgen->halign_cb);
825
826         /* Horizontal spacing value */
827         prop_field_init(&(pgs->hspacing), NULL,
828                         cgen->horiz_spacing_field, cgen->halign_cb);
829
830         /* Position */
831         prop_geomfield_init(&(pgs->pos), cgen->pos_label,
832                             cgen->x_field_label, cgen->x_field,
833                             cgen->y_field_label, cgen->y_field,
834                             NULL, NULL, NULL, NULL,
835                             cgen->pos_cb);
836
837         /* Initial State */
838         n = 0;
839         item[n] = cgen->istate_ckbox_items.Visible_item;
840         item_val[n] = AB_STATE_VISIBLE; n++;
841         item[n] = cgen->istate_ckbox_items.Active_item;
842         item_val[n] = AB_STATE_ACTIVE; n++;
843         prop_checkbox_init(&(pgs->init_state), cgen->istate_ckbox_label,
844                             cgen->istate_ckbox, n, item, item_val,
845                             cgen->istate_cb);
846
847         /* Color */
848         prop_colorfield_init(&(pgs->bg_color), cgen->bg_mbutton,
849                 cgen->bg_mbutton_bg_mbutton_menu_items.None_item,
850                 cgen->bg_mbutton_bg_mbutton_menu_items.Color_Chooser_item,
851                 cgen->bg_swatch, cgen->bg_field, cgen->bg_cb);
852
853         prop_changebars_cleared(pgs->prop_sheet);
854
855         return (cgen->prop_dialog_shellform);
856     }
857     else
858         return NULL;
859
860 }
861
862 static int
863 group_prop_clear(
864     AB_PROP_TYPE type
865 )
866 {
867     PropGroupSettingsRec        *pgs = &(prop_group_settings_rec[type]);
868
869     if (pgs->current_obj == NULL)
870         return OK;
871
872     /* Clear Name */
873     prop_field_set_value(&(pgs->name), "", False);
874
875     /* Clear Border Frame */
876     prop_options_set_value(&(pgs->frame), (XtPointer)AB_LINE_NONE, False);
877
878     /* Clear Layout Type */
879     prop_radiobox_set_value(&(pgs->layout_type),
880                             (XtPointer)AB_GROUP_IGNORE, False);
881
882     /* Clear Grid Rows/Columns */
883     prop_radiobox_set_value(&(pgs->grid_rowcol),
884                             (XtPointer)AB_ORIENT_HORIZONTAL, False);
885     prop_field_set_numeric_value(&(pgs->grid_rowcol_count), NUMROWCOL, False);
886
887     /* Clear Vertical Alignment */
888     prop_options_set_value(&(pgs->valign), (XtPointer)AB_ALIGN_LEFT, False);
889     prop_field_set_numeric_value(&(pgs->vspacing), 0, False);
890
891     /* Clear Horizontal Alignment */
892     prop_options_set_value(&(pgs->halign), (XtPointer)AB_ALIGN_TOP, False);
893     prop_field_set_numeric_value(&(pgs->hspacing), 0, False);
894
895     /* Clear Object Size */
896
897     /* Clear Object Resizing */
898
899     /* Clear Position */
900     prop_geomfield_clear(&(pgs->pos), GEOM_X);
901     prop_geomfield_clear(&(pgs->pos), GEOM_Y);
902
903     /* Clear Initial State */
904     prop_checkbox_set_value(&(pgs->init_state), AB_STATE_VISIBLE, True, False);
905     prop_checkbox_set_value(&(pgs->init_state), AB_STATE_ACTIVE, True, False);
906
907     /* Clear Color */
908     prop_colorfield_set_value(&(pgs->bg_color), "", False);
909
910     pgs->current_obj = NULL;
911
912     turnoff_changebars(type);
913
914     return OK;
915 }
916
917
918
919 static int
920 group_prop_activate(
921     AB_PROP_TYPE type,
922     BOOL         active
923 )
924 {
925     ui_set_active(prop_group_settings_rec[type].prop_sheet, active);
926
927     return OK;
928 }
929
930
931 static int
932 group_prop_load(
933     ABObjPtr     obj,
934     AB_PROP_TYPE type,
935     unsigned long loadkey
936 )
937 {
938     PropGroupSettingsRec        *pgs = &(prop_group_settings_rec[type]);
939     AB_GROUP_TYPE               gtype;
940     BOOL                        load_all = (loadkey & LoadAll);
941
942     if (obj == NULL)
943     {
944         if (pgs->current_obj != NULL)
945             obj = pgs->current_obj;
946         else
947             return ERROR;
948     }
949     else if (!obj_is_group(obj))
950         return ERROR;
951     else
952         pgs->current_obj = obj;
953
954     /* Load Name */
955     if (load_all || loadkey & LoadName)
956         prop_field_set_value(&(pgs->name), obj_get_name(obj), False);
957
958     if (load_all)
959     {
960         /* Load Border Frame */
961         prop_options_set_value(&(pgs->frame), (XtPointer)obj_get_border_frame(obj), False);
962
963         /* Load Layout Type */
964         gtype = obj_get_group_type(obj);
965         prop_radiobox_set_value(&(pgs->layout_type), (XtPointer)gtype, False);
966         setup_grouptype_settings(type, gtype);
967
968         /* Load Alignment, Grid-Rows/Columns */
969         switch(gtype)
970         {
971 /*
972         case AB_GROUP_IGNORE:
973                 prop_radiobox_set_value(&(pgs->spacing_type),
974                                 AB_ATTACH_OBJ, False);
975                 prop_field_set_numeric_value(&(pgs->spacing),
976                         0, False);
977                 break;
978 */
979
980         case AB_GROUP_ROWS:
981                 prop_options_set_value(&(pgs->halign),
982                                 (XtPointer)obj_get_row_align(obj), False);
983
984                 prop_field_set_numeric_value(&(pgs->hspacing),
985                                 obj_get_hoffset(obj), False);
986                 break;
987
988         case AB_GROUP_COLUMNS:
989                 prop_options_set_value(&(pgs->valign),
990                                 (XtPointer)obj_get_col_align(obj), False);
991
992                 prop_field_set_numeric_value(&(pgs->vspacing),
993                                 obj_get_voffset(obj), False);
994                 break;
995         case AB_GROUP_ROWSCOLUMNS:
996                 if (obj_get_num_rows(obj) ||
997                         (!obj_get_num_rows(obj) &&
998                                 !obj_get_num_columns(obj)))
999                 {
1000                     prop_radiobox_set_value(&(pgs->grid_rowcol),
1001                                 (XtPointer)AB_ORIENT_HORIZONTAL, False);
1002                     prop_field_set_numeric_value(&(pgs->grid_rowcol_count),
1003                                 obj_get_num_rows(obj), False);
1004                 }
1005                 else
1006                 {
1007                     prop_radiobox_set_value(&(pgs->grid_rowcol),
1008                                 (XtPointer)AB_ORIENT_VERTICAL, False);
1009                     prop_field_set_numeric_value(&(pgs->grid_rowcol_count),
1010                                 obj_get_num_columns(obj), False);
1011                 }
1012
1013                 prop_options_set_value(&(pgs->halign),
1014                                 (XtPointer)obj_get_row_align(obj), False);
1015
1016                 prop_field_set_numeric_value(&(pgs->hspacing),
1017                                 obj_get_hoffset(obj), False);
1018
1019                 prop_options_set_value(&(pgs->valign),
1020                                 (XtPointer)obj_get_col_align(obj), False);
1021
1022                 prop_field_set_numeric_value(&(pgs->vspacing),
1023                                 obj_get_voffset(obj), False);
1024                 break;
1025
1026         }
1027
1028         /* Load Object Size */
1029
1030         /* Load Object Resizing */
1031
1032         /* Load Initial State */
1033         prop_checkbox_set_value(&(pgs->init_state), AB_STATE_VISIBLE,
1034                 obj_is_initially_visible(obj), False);
1035         prop_checkbox_set_value(&(pgs->init_state), AB_STATE_ACTIVE,
1036                 obj_is_initially_active(obj), False);
1037
1038         /* Load Color */
1039         prop_colorfield_set_value(&(pgs->bg_color), obj_get_bg_color(obj), False);
1040
1041         turnoff_changebars(type);
1042     }
1043
1044     /* Load Position */
1045     if (load_all || loadkey & LoadPosition)
1046         prop_load_obj_position(obj, &(pgs->pos));
1047
1048     return OK;
1049 }
1050
1051
1052 static int
1053 group_prop_apply(
1054     AB_PROP_TYPE   type
1055 )
1056 {
1057     PropGroupSettingsRec        *pgs = &(prop_group_settings_rec[type]);
1058     STRING                      value;
1059     AB_GROUP_TYPE               gtype;
1060     int                         num_rc;
1061     int                         space_val;
1062     int                         i;
1063     ABObj                       obj;
1064     BOOL                        changed = False;
1065     BOOL                        reset_bg = False;
1066
1067     obj = pgs->current_obj;
1068     gtype = (AB_GROUP_TYPE)prop_radiobox_get_value(&(pgs->layout_type));
1069
1070     if (obj == NULL)
1071         return ERROR;
1072
1073     if (!verify_props(type))
1074         return ERROR;
1075
1076     if (prop_changed(pgs->name.changebar))
1077     {
1078         value = prop_field_get_value(&(pgs->name));
1079         abobj_set_name(pgs->current_obj, value);
1080         util_free(value);
1081     }
1082     /*
1083      * Set rows/columns based on new layout type. If we are
1084      * changing from AB_GROUP_IGNORE to something else, we need
1085      * to sort the children so that the group comes out looking
1086      * close to the initial layout, regardless of the order of
1087      * creation.
1088      */
1089     if (prop_changed(pgs->layout_type.changebar))
1090     {
1091         changed = True;
1092
1093         switch (gtype)
1094         {
1095             case AB_GROUP_IGNORE:
1096                 abobj_set_num_rows(obj, 0);
1097                 abobj_set_num_columns(obj, 0);
1098
1099                 break;
1100
1101             case AB_GROUP_ROWS:
1102                 abobj_set_num_rows(obj, 1);
1103                 abobj_set_num_columns(obj, 0);
1104                 if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
1105                         abobj_sort_children(obj, XSORT);
1106                 /*
1107                  * If changing types, set defaults for row stuff
1108                  * in case the user doesn't change them.
1109
1110                 if (obj_get_group_type(obj) != AB_GROUP_ROWS)
1111                 {
1112                     abobj_set_row_alignment(obj, AB_ALIGN_TOP);
1113                     abobj_set_row_attach_type(obj, AB_ATTACH_OBJ);
1114                     abobj_set_row_offset(obj, HOFFSET);
1115                 }
1116                  */
1117                 break;
1118             case AB_GROUP_COLUMNS:
1119                 abobj_set_num_rows(obj, 0);
1120                 abobj_set_num_columns(obj, 1);
1121                 if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
1122                         abobj_sort_children(obj, YSORT);
1123                 /*
1124                  * If changing types, set defaults for column stuff
1125                  * in case the user doesn't change them.
1126
1127                 if (obj_get_group_type(obj) != AB_GROUP_COLUMNS)
1128                 {
1129                     abobj_set_col_alignment(obj, AB_ALIGN_LEFT);
1130                     abobj_set_col_attach_type(obj, AB_ATTACH_OBJ);
1131                     abobj_set_col_offset(obj, VOFFSET);
1132                 }
1133                  */
1134                 break;
1135
1136
1137             case AB_GROUP_ROWSCOLUMNS:
1138
1139                 num_rc = prop_field_get_numeric_value(&(pgs->grid_rowcol_count));
1140
1141                 if (prop_radiobox_get_value(&(pgs->grid_rowcol))
1142                                         == AB_ORIENT_HORIZONTAL)
1143                 {
1144                     abobj_set_num_rows(obj, num_rc < 2 ? 2 : num_rc);
1145                     abobj_set_num_columns(obj, 0);
1146                     if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
1147                             abobj_sort_children(obj, YSORT);
1148                 }
1149                 else
1150                 {
1151                     abobj_set_num_columns(obj, num_rc < 2 ? 2 : num_rc);
1152                     abobj_set_num_rows(obj, 0);
1153                     if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
1154                             abobj_sort_children(obj, XSORT);
1155                 }
1156                 /*
1157                  * If changing types, set defaults for row/column stuff
1158                  * in case the user doesn't change them.
1159                  */
1160                 if (obj_get_group_type(obj) != AB_GROUP_ROWSCOLUMNS)
1161                 {
1162                     /*
1163                     abobj_set_row_alignment(obj, AB_ALIGN_TOP);
1164                     abobj_set_row_attach_type(obj, AB_ATTACH_OBJ);
1165                     abobj_set_row_offset(obj, HOFFSET);
1166
1167                     abobj_set_col_alignment(obj, AB_ALIGN_LEFT);
1168                     abobj_set_col_attach_type(obj, AB_ATTACH_OBJ);
1169                     abobj_set_col_offset(obj, VOFFSET);
1170
1171
1172                      * Add this later
1173                     abobj_set_row_alignment(obj,
1174                         (AB_ALIGNMENT)prop_options_get_value(&(pgs->halign)));
1175                     abobj_set_row_attach_type(obj,
1176                         (AB_ATTACH_TYPE)prop_options_get_value(&(pgs->hspacing_type)));
1177                     abobj_set_row_offset(obj,
1178                         prop_field_get_numeric_value(&(pgs->hspacing)));
1179
1180                     abobj_set_col_alignment(obj,
1181                         (AB_ALIGNMENT)prop_options_get_value(&(pgs->valign)));
1182                     abobj_set_col_attach_type(obj,
1183                         (AB_ATTACH_TYPE)prop_options_get_value(&(pgs->vspacing_type)));
1184                     abobj_set_col_offset(obj,
1185                         prop_field_get_numeric_value(&(pgs->vspacing)));
1186                     */
1187                 }
1188                 break;
1189         }
1190         abobj_set_group_type(obj, gtype);
1191     }
1192     if (prop_changed(pgs->grid_rowcol_count.changebar))
1193     {
1194         /*
1195          * Fix this!!
1196          */
1197         changed = True;
1198
1199         num_rc = prop_field_get_numeric_value(&(pgs->grid_rowcol_count));
1200         if (prop_radiobox_get_value(&(pgs->grid_rowcol))
1201                 == AB_ORIENT_HORIZONTAL)
1202         {
1203             abobj_set_num_rows(obj, num_rc < 2 ? 2 : num_rc);
1204             abobj_set_num_columns(obj, 0);
1205             if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
1206                 abobj_sort_children(obj, YSORT);
1207         }
1208         else
1209         {
1210             abobj_set_num_columns(obj, num_rc < 2 ? 2 : num_rc);
1211             abobj_set_num_rows(obj, 0);
1212             if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
1213                 abobj_sort_children(obj, XSORT);
1214         }
1215     }
1216     if (prop_changed(pgs->halign.changebar))
1217     {
1218         changed = True;
1219
1220         abobj_set_row_alignment(obj,
1221             (AB_ALIGNMENT)prop_options_get_value(&(pgs->halign)));
1222
1223         space_val = prop_field_get_numeric_value(&(pgs->hspacing));
1224
1225         abobj_set_row_offset(obj, space_val);
1226     }
1227     if (prop_changed(pgs->valign.changebar))
1228     {
1229         changed = True;
1230         abobj_set_col_alignment(obj,
1231             (AB_ALIGNMENT)prop_options_get_value(&(pgs->valign)));
1232
1233         space_val = prop_field_get_numeric_value(&(pgs->vspacing));
1234
1235         abobj_set_col_offset(obj, space_val);
1236     }
1237
1238     if (changed)
1239     {
1240         ABObj   oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
1241         Widget  w = objxm_get_widget(oobj);
1242         WidgetList      children_list = NULL;
1243         int             num_children = 0;
1244
1245         XtVaGetValues(w,
1246             XmNnumChildren, &num_children,
1247             XmNchildren, &children_list,
1248             NULL);
1249
1250         XtUnmanageChildren(children_list, num_children);
1251
1252         abobj_layout_group(obj, FALSE);
1253
1254         XtManageChildren(children_list, num_children);
1255     }
1256
1257     /* Border Frame and Margin */
1258     if (prop_changed(pgs->frame.changebar))
1259     {
1260         abobj_set_border_frame(pgs->current_obj,
1261                 (AB_LINE_TYPE)prop_options_get_value(&(pgs->frame)));
1262     }
1263     if (prop_changed(pgs->pos.changebar))
1264     {
1265         if (abobj_is_movable(pgs->current_obj))
1266             abobj_set_xy(pgs->current_obj,
1267                 prop_geomfield_get_value(&(pgs->pos), GEOM_X),
1268                 prop_geomfield_get_value(&(pgs->pos), GEOM_Y));
1269     }
1270     if (prop_changed(pgs->init_state.changebar))
1271     {
1272         abobj_set_visible(pgs->current_obj,
1273                 prop_checkbox_get_value(&(pgs->init_state), AB_STATE_VISIBLE));
1274         abobj_set_active(pgs->current_obj,
1275                 prop_checkbox_get_value(&(pgs->init_state), AB_STATE_ACTIVE));
1276     }
1277     if (prop_changed(pgs->bg_color.changebar))
1278     {
1279         value = prop_colorfield_get_value(&(pgs->bg_color));
1280         abobj_set_background_color(pgs->current_obj, value);
1281         if (util_strempty(value))
1282             reset_bg = True;
1283         util_free(value);
1284         prop_colorfield_set_value(&(pgs->bg_color),
1285                 obj_get_bg_color(pgs->current_obj), False);
1286     }
1287
1288     abobj_tree_instantiate_changes(pgs->current_obj);
1289
1290     if (reset_bg) /* Set back to No Color */
1291         abobj_reset_colors(pgs->current_obj, reset_bg, False);
1292
1293     turnoff_changebars(type);
1294
1295     return OK;
1296 }
1297
1298 static BOOL
1299 group_prop_pending(
1300     AB_PROP_TYPE type
1301 )
1302 {
1303     return(prop_changebars_pending(prop_group_settings_rec[type].prop_sheet));
1304 }
1305
1306 static BOOL
1307 verify_props(
1308     AB_PROP_TYPE type
1309 )
1310 {
1311     PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
1312
1313     if (prop_changed(pgs->name.changebar) && !prop_name_ok(pgs->current_obj, pgs->name.field))
1314         return False;
1315
1316     if (prop_changed(pgs->bg_color.changebar) && !prop_color_ok(pgs->bg_color.field))
1317         return False;
1318
1319     if (prop_changed(pgs->grid_rowcol_count.changebar) &&
1320             !prop_number_ok(pgs->grid_rowcol_count.field, (STRING)RowColFieldStr, 1, SHRT_MAX))
1321         return False;
1322
1323     if (prop_changed(pgs->valign.changebar) &&
1324             !prop_number_ok(pgs->vspacing.field, (STRING)VertSpacingFieldStr,
1325                 -SHRT_MAX, SHRT_MAX))
1326         return False;
1327
1328     if (prop_changed(pgs->halign.changebar) &&
1329             !prop_number_ok(pgs->hspacing.field, (STRING)HorizSpacingFieldStr,
1330                 -SHRT_MAX, SHRT_MAX))
1331         return False;
1332
1333
1334     if (prop_changed(pgs->pos.changebar) &&
1335             (!prop_number_ok(pgs->pos.x_field, (STRING)XFieldStr, -SHRT_MAX, SHRT_MAX) ||
1336             !prop_number_ok(pgs->pos.y_field, (STRING)YFieldStr, -SHRT_MAX, SHRT_MAX)))
1337         return False;
1338
1339     return True;
1340 }
1341
1342 static void
1343 turnoff_changebars(
1344     AB_PROP_TYPE type
1345 )
1346 {
1347     PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
1348
1349     prop_set_changebar(pgs->name.changebar,             PROP_CB_OFF);
1350     prop_set_changebar(pgs->frame.changebar,            PROP_CB_OFF);
1351     prop_set_changebar(pgs->layout_type.changebar,      PROP_CB_OFF);
1352     prop_set_changebar(pgs->grid_rowcol.changebar,      PROP_CB_OFF);
1353     prop_set_changebar(pgs->valign.changebar,           PROP_CB_OFF);
1354     prop_set_changebar(pgs->halign.changebar,           PROP_CB_OFF);
1355     prop_set_changebar(pgs->pos.changebar,              PROP_CB_OFF);
1356     prop_set_changebar(pgs->init_state.changebar,       PROP_CB_OFF);
1357     prop_set_changebar(pgs->bg_color.changebar,         PROP_CB_OFF);
1358
1359     prop_changebars_cleared(pgs->prop_sheet);
1360 }
1361
1362
1363 static void
1364 grouptypeCB(
1365     Widget   item,
1366     XtPointer clientdata,
1367     XmToggleButtonCallbackStruct *state
1368 )
1369 {
1370     AB_PROP_TYPE        type = (AB_PROP_TYPE)clientdata;
1371     AB_GROUP_TYPE       value = AB_GROUP_UNDEF;
1372
1373     if (state->set)
1374     {
1375         XtVaGetValues(item, XmNuserData, &value, NULL);
1376         setup_grouptype_settings(type, value);
1377     }
1378
1379 }
1380
1381
1382 static void
1383 setup_grouptype_settings(
1384     AB_PROP_TYPE type,
1385     AB_GROUP_TYPE gtype
1386 )
1387 {
1388     PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
1389     DtbGroupPropDialogInfo      cgen;
1390
1391     if (type == AB_PROP_REVOLVING)
1392         cgen = &rev_group_prop_dialog;
1393     else
1394         cgen = &dtb_group_prop_dialog;
1395
1396     if (!cgen || !cgen->initialized)
1397         return;
1398
1399     switch(gtype)
1400     {
1401         case AB_GROUP_IGNORE:
1402             ui_set_active(cgen->valign_grp, False);
1403             ui_set_active(cgen->halign_grp, False);
1404             ui_set_active(cgen->grid_rowcol_grp, False);
1405             break;
1406
1407         case AB_GROUP_COLUMNS:
1408             ui_set_active(cgen->valign_grp, True);
1409             ui_set_active(cgen->halign_grp, False);
1410             ui_set_active(cgen->grid_rowcol_grp, False);
1411             break;
1412
1413         case AB_GROUP_ROWS:
1414             ui_set_active(cgen->valign_grp, False);
1415             ui_set_active(cgen->halign_grp, True);
1416             ui_set_active(cgen->grid_rowcol_grp, False);
1417             break;
1418
1419         case AB_GROUP_ROWSCOLUMNS:
1420             ui_set_active(cgen->valign_grp, True);
1421             ui_set_active(cgen->halign_grp, True);
1422             ui_set_active(cgen->grid_rowcol_grp, True);
1423             break;
1424     }
1425 }
1426
1427 static void
1428 undo_group(
1429     ABUndoRec   undo_rec
1430 )
1431 {
1432     if (!undo_rec)
1433         return;
1434
1435     /*
1436      * Remember all objects that will be ungrouped here can
1437      * undo this later (undo of undo)
1438      */
1439     abobj_set_undo(undo_rec->list, undo_rec->count,
1440                 undo_ungroup, AB_UNDO_UNGROUP);
1441
1442     /*
1443      * Ungroup objects
1444      */
1445     ungroup_objects(undo_rec->list, undo_rec->count);
1446 }
1447
1448
1449 static void
1450 undo_ungroup(
1451     ABUndoRec   undo_rec
1452 )
1453 {
1454     ABObj       newgroup,
1455                 parent,
1456                 *new_list,
1457                 *member_list,
1458                 project;
1459     int         i,
1460                 member_count;
1461
1462     if (!undo_rec)
1463         return;
1464
1465     new_list = (ABObj *)malloc(undo_rec->count * sizeof(ABObj));
1466
1467     project = proj_get_project();
1468
1469     /* Deselect any objects that happen to be selected */
1470     abobj_deselect_all(project);
1471     aob_deselect_all_objects(project);
1472
1473     for (i = 0; i < undo_rec->count; ++i)
1474     {
1475         ABUndoInfo      undo_info;
1476
1477         undo_info = &(undo_rec->info_list[i]);
1478
1479         /*
1480          * If undo record is not the right type, something is WRONG !!
1481          */
1482         if (undo_info->type != AB_UNDO_UNGROUP)
1483             continue;
1484
1485         newgroup = abobj_dup_tree(undo_info->info.ungroup.dup_old_group);
1486
1487         member_list = undo_info->info.ungroup.member_list;
1488         member_count = undo_info->info.ungroup.member_count;
1489
1490         parent = obj_get_parent(member_list[0]);
1491
1492         obj_append_child(parent, newgroup);
1493
1494         if (abobj_show_tree(newgroup, False) == -1)
1495             fprintf(stderr,"create_obj_action: couldn't show object\n");
1496         else
1497         {
1498             group_objects(newgroup, member_list, member_count);
1499         }
1500
1501         new_list[i] = newgroup;
1502     }
1503
1504     abobj_set_undo(new_list, undo_rec->count, undo_group, AB_UNDO_GROUP);
1505
1506     if (new_list)
1507         free(new_list);
1508 }
1509
1510 void
1511 set_new_group_size(
1512     ABObj obj
1513 )
1514 {
1515     ABObj         oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
1516     int           member_count;
1517     ABObj         *member_list;
1518     int           width, height;
1519     XRectangle    rect;
1520
1521     create_member_list(oobj, &member_list, &member_count);
1522
1523     /*
1524      * Reset groups width and height. for rows, the new height is that of
1525      * the tallest member, the new width is the width of the
1526      * rect occupied by all of the members. For colums, the new
1527      * width is that of the widest member, the new height is the
1528      * height of the rect occupied by all of the members.
1529      */
1530     abobj_get_rect_for_objects(member_list, member_count, &rect);
1531     abobj_get_greatest_size(member_list, member_count,
1532                                  &width, &height,
1533                                  (ABObj *) NULL, (ABObj *) NULL);
1534     if (obj_get_group_type(oobj) == AB_GROUP_ROWS)
1535     {
1536         abobj_set_pixel_width(obj, rect.width, 0);
1537         abobj_set_pixel_height(obj, height, 0);
1538     }
1539     else if (obj_get_group_type(oobj) == AB_GROUP_ROWS)
1540     {
1541         abobj_set_pixel_width(obj, width, 0);
1542         abobj_set_pixel_height(obj, rect.height, 0);
1543     }
1544     util_free(member_list);
1545 }
1546
1547 void
1548 abobj_layout_group(
1549     ABObj       obj,
1550     BOOL        init
1551 )
1552 {
1553     ABObj         pobj;
1554     ABObj         child;
1555     AB_GROUP_TYPE type;
1556     int           i;
1557     int           child_old_x, child_old_y;
1558     int           group_new_x, group_new_y;
1559     XRectangle    rect;
1560
1561
1562     if (!obj_has_flag(obj, XmConfiguredFlag))
1563         return;
1564
1565     pobj = objxm_comp_get_subobj(obj, AB_CFG_PARENT_OBJ);
1566
1567     if (obj_get_num_children(pobj) <= 0)
1568         return;
1569
1570     type = obj_get_group_type(obj);
1571
1572     /*
1573      * Save leftmost objects real x and y to determine group's new
1574      * x and y.
1575      */
1576     child = obj_get_child(pobj, 0);
1577
1578     child_old_x = obj_get_x(child);
1579     child_old_y = obj_get_y(child);
1580
1581     abobj_clear_layout(pobj, True, (type != AB_GROUP_IGNORE));
1582
1583     /*
1584      * CLEANUP:
1585      * The code to do group layout here should be the code
1586      * used in dtb_utils.c to make sure the behaviour is the
1587      * same. Unfortunately, at this time, this is a big risky
1588      * change. So, some behavioral differences will exist.
1589      * This needs to be fixed in the future.
1590      */
1591     switch (type)
1592     {
1593         case AB_GROUP_IGNORE:
1594             break;
1595
1596         case AB_GROUP_ROWS:
1597             obj_set_num_rows(obj, 1);
1598             obj_set_num_columns(obj, 0);
1599             group_align_rows(obj, init);
1600             group_align_left(obj);
1601             break;
1602
1603         case AB_GROUP_COLUMNS:
1604             obj_set_num_rows(obj, 0);
1605             obj_set_num_columns(obj, 1);
1606             group_align_cols(obj, init);
1607             group_align_tops(obj);
1608             break;
1609
1610         case AB_GROUP_ROWSCOLUMNS:
1611             group_align_rows(obj, init);
1612             group_align_cols(obj, init);
1613             break;
1614     }
1615
1616     /*
1617     group_align_rows(obj);
1618     group_align_cols(obj);
1619     */
1620
1621
1622     /*
1623      * Re-instantiate all of the children and then the group.
1624      */
1625     for (i = 0; i < obj_get_num_children(pobj); i++)
1626     {
1627         abobj_instantiate_changes(obj_get_child(pobj, i));
1628     }
1629
1630
1631     /*
1632      * Set the childrens x,y's so obj is update with reality.
1633      */
1634     for (i = 0; i < obj_get_num_children(pobj); i++)
1635     {
1636         child = obj_get_child(pobj, i);
1637         x_get_widget_rect(objxm_get_widget(child), &rect);
1638         obj_set_x(child, rect.x);
1639         obj_set_y(child, rect.y);
1640     }
1641
1642     /*
1643      * Place the group so that the topmost/leftmost child remains
1644      * in the same place.
1645     group_new_x = obj_get_x(pobj) +
1646                 (child_old_x - obj_get_x(obj_get_child(pobj, 0)));
1647
1648     group_new_y = obj_get_y(pobj) +
1649                 (child_old_y - obj_get_y(obj_get_child(pobj, 0)));
1650
1651     abobj_set_xy(pobj, group_new_x, group_new_y);
1652      */
1653
1654     abobj_instantiate_changes(pobj);
1655
1656     /*
1657      * For some reason, width and height need to be set on the
1658      * group.
1659     pobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
1660     x_get_widget_rect(objxm_get_widget(pobj), &rect);
1661      */
1662
1663 /*
1664     obj_set_width(pobj, rect.width);
1665     obj_set_height(pobj, rect.height);
1666 */
1667
1668 }
1669
1670 void
1671 abobj_register_group_expose_handler(
1672     ABObj       obj
1673 )
1674 {
1675     AB_GROUP_TYPE       type;
1676     AB_ALIGNMENT        row_alignment,
1677                         col_alignment;
1678     Widget              group_widget;
1679
1680
1681     Boolean             register_expose = False;
1682
1683     if (!obj || !obj_is_group(obj))
1684         return;
1685
1686     group_widget = objxm_get_widget(obj);
1687
1688     if (!group_widget)
1689         return;
1690
1691     type = obj_get_group_type(obj);
1692
1693     switch (type)
1694     {
1695         case AB_GROUP_IGNORE:
1696             break;
1697
1698         case AB_GROUP_ROWS:
1699             row_alignment = obj_get_row_align(obj);
1700
1701             if (row_alignment == AB_ALIGN_HCENTER)
1702                 register_expose = True;
1703             break;
1704
1705         case AB_GROUP_COLUMNS:
1706             col_alignment = obj_get_col_align(obj);
1707
1708             if ((col_alignment == AB_ALIGN_VCENTER) ||
1709                     (col_alignment == AB_ALIGN_LABELS))
1710                 register_expose = True;
1711             break;
1712
1713         case AB_GROUP_ROWSCOLUMNS:
1714             row_alignment = obj_get_row_align(obj);
1715             col_alignment = obj_get_col_align(obj);
1716
1717             if ((row_alignment == AB_ALIGN_HCENTER) ||
1718                 (col_alignment == AB_ALIGN_LEFT) ||
1719                 (col_alignment == AB_ALIGN_LABELS))
1720                 register_expose = True;
1721             break;
1722     }
1723
1724     if (register_expose)
1725     {
1726
1727         XtAddEventHandler(group_widget,
1728                 ExposureMask, False,
1729                 group_expose_handler, (XtPointer)obj);
1730     }
1731 }
1732
1733 /*
1734  * Group expose handler.
1735  *
1736  * Some group objects depend on it's members' sizes for their layout.
1737  * Unfortunately, some group members have invalid sizes prior to
1738  * XtRealize(), so the group layout has to be recalculated after the
1739  * group is realized or exposed in this case, since there is no realize
1740  * callback.
1741  */
1742 static void
1743 group_expose_handler(
1744     Widget      widget,
1745     XtPointer   client_data,
1746     XEvent      *event,
1747     Boolean     *cont_dispatch
1748 )
1749 {
1750     ABObj               obj = (ABObj)client_data;
1751     WidgetList          children_list;
1752     int                 i,
1753                         num_children = 0;
1754     Boolean             relayout_all = False,
1755                         register_align_handler = False;
1756
1757
1758     if (event->type != Expose)
1759         return;
1760
1761     if (!obj || !obj_is_group(obj))
1762         return;
1763
1764     /*
1765      * Get children list
1766      */
1767     XtVaGetValues(widget,
1768             XmNnumChildren, &num_children,
1769             XmNchildren, &children_list,
1770             NULL);
1771
1772     if (num_children <= 0)
1773         return;
1774
1775     XtRemoveEventHandler(widget,
1776                 ExposureMask, False,
1777                 group_expose_handler, (XtPointer)client_data);
1778
1779     /*
1780      * Turn off 'save needed' temporarily
1781      */
1782     abobj_disable_save_needed();
1783
1784     abobj_layout_group(obj, FALSE);
1785
1786     abobj_enable_save_needed();
1787 }
1788
1789 static void
1790 group_align_tops(
1791         ABObj   obj
1792 )
1793 {
1794     ABAttachment        attach;
1795     ABObj       child,
1796                 previous_child,
1797                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
1798     int         num_children = obj_get_num_children(oobj),
1799                 num_columns,
1800                 num_rows,
1801                 cell_height,
1802                 cell_width,
1803                 i,
1804                 j;
1805
1806     if (num_children <= 0)
1807         return;
1808
1809     get_cell_size(obj, &cell_width, &cell_height);
1810
1811     get_row_col(obj, &num_rows, &num_columns);
1812
1813     for (j = 0; j < num_rows; j++)
1814     {
1815         for (i = 0; i < num_columns; i++)
1816         {
1817             child = get_child(obj, i, j);
1818
1819             if (!child)
1820                 continue;
1821
1822             if ((i == 0) && (j == 0))
1823             {
1824                 attach.type = AB_ATTACH_POINT;
1825                 attach.value = (void *)0;
1826                 attach.offset = 0;
1827
1828                 abobj_set_attachment(child, AB_CP_NORTH, &attach);
1829
1830                 continue;
1831             }
1832
1833             if (i == 0)
1834             {
1835                 previous_child = get_child(obj, 0, j-1);
1836
1837                 if (previous_child)
1838                 {
1839                     int         offset = obj_get_voffset(obj);
1840                     AB_GROUP_TYPE type = obj_get_group_type(obj);
1841
1842                     if (type == AB_GROUP_ROWSCOLUMNS)
1843                         offset +=
1844                             (cell_height - abobj_get_actual_height(previous_child));
1845
1846                     attach.type = AB_ATTACH_OBJ;
1847                     attach.value = (void *)previous_child;
1848                     attach.offset = offset;
1849
1850                     abobj_set_attachment(child, AB_CP_NORTH, &attach);
1851                 }
1852                 continue;
1853             }
1854
1855             previous_child = get_child(obj, i-1, j);
1856
1857             if (previous_child)
1858             {
1859                 attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
1860                 attach.value = (void *)previous_child;
1861                 attach.offset = 0;
1862
1863                 abobj_set_attachment(child, AB_CP_NORTH, &attach);
1864             }
1865         }
1866     }
1867 }
1868
1869 static void
1870 group_align_hcenters(
1871         ABObj   obj,
1872         BOOL    init
1873 )
1874 {
1875     ABAttachment        attach;
1876     ABObj       child,
1877                 previous_child,
1878                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
1879     AB_GROUP_TYPE type = obj_get_group_type(obj);
1880     int         num_children = obj_get_num_children(oobj),
1881                 num_columns,
1882                 num_rows,
1883                 cell_width,
1884                 cell_height,
1885                 group_width,
1886                 group_height,
1887                 offset,
1888                 gridline,
1889                 i,
1890                 j;
1891
1892     if (num_children <= 0)
1893         return;
1894
1895     get_cell_size(obj, &cell_width, &cell_height);
1896
1897     get_row_col(obj, &num_rows, &num_columns);
1898
1899     offset = obj_get_voffset(obj);
1900
1901     if (type == AB_GROUP_ROWSCOLUMNS)
1902     {
1903         group_height = (num_rows * cell_height) + ((num_rows-1) * offset);
1904         abobj_set_pixel_width(obj, group_height, 0);
1905         abobj_instantiate_changes(obj);
1906     }
1907
1908     for (j = 0; j < num_rows; j++)
1909     {
1910         if (type == AB_GROUP_ROWSCOLUMNS)
1911             gridline = (((j * (cell_height + offset)) + (cell_height/2)) * 100)/group_height;
1912         else
1913             gridline = 50;
1914
1915         for (i = 0; i < num_columns; i++)
1916         {
1917             child = get_child(obj, i, j);
1918
1919             if (!child)
1920                 continue;
1921
1922             if (init)
1923             {
1924                 int     init_offset = 0;
1925                 Widget  child_widget = objxm_get_widget(child);
1926
1927                 if (child_widget &&
1928                    !XtIsSubclass(child_widget, compositeWidgetClass))
1929                 {
1930                     int         height = abobj_get_actual_height(child);
1931
1932                     init_offset = (cell_height - height)/2;
1933                     if (type == AB_GROUP_ROWSCOLUMNS)
1934                         init_offset += (j * (cell_height + offset));
1935                 }
1936
1937                 attach.type = AB_ATTACH_POINT;
1938                 attach.value = (void *)0;
1939                 attach.offset = init_offset;
1940             }
1941             else
1942             {
1943                 int             height = abobj_get_actual_height(child);
1944
1945                 attach.type = AB_ATTACH_GRIDLINE;
1946                 attach.value = (void *)gridline;
1947                 attach.offset = -(height/2);
1948             }
1949
1950             abobj_set_attachment(child, AB_CP_NORTH, &attach);
1951         }
1952     }
1953
1954     if (type == AB_GROUP_ROWSCOLUMNS)
1955     {
1956         abobj_set_pixel_width(obj, -1, 0);
1957         abobj_instantiate_changes(obj);
1958     }
1959 }
1960
1961 static void
1962 group_align_horiz_same_size(
1963         ABObj   obj
1964 )
1965 {
1966     ABObj sibling, previous_sibling;
1967     ABObj oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
1968     int   num_children = obj_get_num_children(oobj);
1969     int   i;
1970
1971     sibling = obj_get_child(oobj, num_children - 1);
1972     /*
1973      * Set up childrens attachments from right to left.
1974      * All objects North and South attachments are to
1975      * the form.
1976      */
1977     for (i = num_children - 2; i >= 0; i--)
1978     {
1979         previous_sibling = obj_get_child(oobj, i);
1980
1981         obj_set_attachment(sibling,
1982                 AB_CP_NORTH,
1983                 AB_ATTACH_OBJ,
1984                 (void *) oobj,
1985                 0);
1986
1987         obj_set_attachment(sibling,
1988                 AB_CP_WEST,
1989                 AB_ATTACH_OBJ,
1990                 (void *) previous_sibling,
1991                 obj_get_hoffset(oobj));
1992
1993         obj_set_attachment(sibling,
1994                 AB_CP_SOUTH,
1995                 AB_ATTACH_OBJ,
1996                 (void *) oobj,
1997                 0);
1998
1999         objxm_obj_set_attachment_args(sibling, OBJXM_CONFIG_BUILD);
2000         obj_clear_flag(sibling, BeingDestroyedFlag);
2001
2002         sibling = previous_sibling;
2003     }
2004
2005     obj_set_attachment(sibling,
2006             AB_CP_NORTH,
2007             AB_ATTACH_OBJ,
2008             (void *) oobj,
2009             0);
2010     obj_set_attachment(sibling,
2011             AB_CP_WEST,
2012             AB_ATTACH_OBJ,
2013             (void *) oobj,
2014             0);
2015
2016     obj_set_attachment(sibling,
2017             AB_CP_SOUTH,
2018             AB_ATTACH_OBJ,
2019             (void *) oobj,
2020             0);
2021
2022     objxm_obj_set_attachment_args(sibling, OBJXM_CONFIG_BUILD);
2023     obj_clear_flag(sibling, BeingDestroyedFlag);
2024 }
2025
2026 static void
2027 group_align_bottoms(
2028         ABObj   obj
2029 )
2030 {
2031     ABAttachment        attach;
2032     ABObj       child,
2033                 previous_child,
2034                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
2035     AB_GROUP_TYPE type = obj_get_group_type(obj);
2036     int         num_children = obj_get_num_children(oobj),
2037                 num_columns,
2038                 num_rows,
2039                 cell_height,
2040                 cell_width,
2041                 offset,
2042                 i,
2043                 j;
2044
2045     if (num_children <= 0)
2046         return;
2047
2048     get_cell_size(obj, &cell_width, &cell_height);
2049
2050     get_row_col(obj, &num_rows, &num_columns);
2051
2052     for (j = 0; j < num_rows; j++)
2053     {
2054         for (i = 0; i < num_columns; i++)
2055         {
2056             child = get_child(obj, i, j);
2057
2058             if (!child)
2059                 continue;
2060
2061             if ((i == 0) && (j == 0))
2062             {
2063                 offset = (cell_height - abobj_get_actual_height(child));
2064
2065                 attach.type = AB_ATTACH_POINT;
2066                 attach.value = (void *)0;
2067                 attach.offset = offset;
2068
2069                 abobj_set_attachment(child, AB_CP_NORTH, &attach);
2070
2071                 continue;
2072             }
2073
2074             if (i == 0)
2075             {
2076                 previous_child = get_child(obj, 0, j-1);
2077
2078                 if (previous_child)
2079                 {
2080                     offset = obj_get_voffset(obj);
2081
2082                     if (type == AB_GROUP_ROWSCOLUMNS)
2083                         offset +=
2084                             (cell_height - abobj_get_actual_height(child));
2085
2086                     attach.type = AB_ATTACH_OBJ;
2087                     attach.value = (void *)previous_child;
2088                     attach.offset = offset;
2089
2090                     abobj_set_attachment(child, AB_CP_NORTH, &attach);
2091                 }
2092                 continue;
2093             }
2094
2095             previous_child = get_child(obj, i-1, j);
2096
2097             if (child && previous_child)
2098             {
2099                 attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
2100                 attach.value = (void *)previous_child;
2101                 attach.offset = 0;
2102
2103                 abobj_set_attachment(child, AB_CP_SOUTH, &attach);
2104             }
2105         }
2106     }
2107 }
2108
2109 static void
2110 group_align_left(
2111         ABObj   obj
2112 )
2113 {
2114     ABAttachment        attach;
2115     ABObj       child,
2116                 previous_child,
2117                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
2118     int         num_children = obj_get_num_children(oobj),
2119                 num_columns,
2120                 num_rows,
2121                 cell_width,
2122                 cell_height,
2123                 i,
2124                 j;
2125
2126     if (num_children <= 0)
2127         return;
2128
2129     get_cell_size(obj, &cell_width, &cell_height);
2130
2131     get_row_col(obj, &num_rows, &num_columns);
2132
2133     for (j = 0; j < num_rows; j++)
2134     {
2135         for (i = 0; i < num_columns; i++)
2136         {
2137             child = get_child(obj, i, j);
2138
2139             if (!child)
2140                 continue;
2141
2142             if ((i == 0) && (j == 0))
2143             {
2144                 attach.type = AB_ATTACH_POINT;
2145                 attach.value = (void *)0;
2146                 attach.offset = 0;
2147
2148                 abobj_set_attachment(child, AB_CP_WEST, &attach);
2149                 continue;
2150             }
2151
2152             if (j == 0)
2153             {
2154                 int             offset = obj_get_hoffset(obj);
2155                 AB_GROUP_TYPE type = obj_get_group_type(obj);
2156
2157                 previous_child = get_child(obj, i-1, j);
2158
2159                 if (!previous_child)
2160                     continue;
2161
2162                 if (type == AB_GROUP_ROWSCOLUMNS)
2163                     offset +=
2164                         (cell_width - abobj_get_actual_width(previous_child));
2165
2166                 attach.type = AB_ATTACH_OBJ;
2167                 attach.value = (void *)previous_child;
2168                 attach.offset = offset;
2169
2170                 abobj_set_attachment(child, AB_CP_WEST, &attach);
2171
2172                 continue;
2173             }
2174
2175             previous_child = get_child(obj, i, j-1);
2176
2177             if (previous_child)
2178             {
2179                 attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
2180                 attach.value = (void *)previous_child;
2181                 attach.offset = 0;
2182
2183                 abobj_set_attachment(child, AB_CP_WEST, &attach);
2184             }
2185         }
2186     }
2187 }
2188
2189 static void
2190 group_align_labels(
2191         ABObj   obj
2192 )
2193 {
2194     ABAttachment        attach;
2195     ABObj       child,
2196                 previous_child,
2197                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ),
2198                 *one_col = NULL,
2199                 *child_list,
2200                 previous_ref_obj = NULL;
2201     int         num_children = 0,
2202                 num_columns,
2203                 num_rows,
2204                 cell_width,
2205                 cell_height,
2206                 offset,
2207                 max_label_width = 0,
2208                 max_value_width = 0,
2209                 i,
2210                 j;
2211
2212     if (oobj)
2213         num_children = obj_get_num_children(oobj);
2214
2215     if (num_children <= 0)
2216         return;
2217
2218     get_cell_size(obj, &cell_width, &cell_height);
2219
2220     create_member_list(oobj, &child_list, &num_children);
2221
2222     get_widest_label_obj(child_list, num_children, &child, &max_label_width);
2223     get_widest_value_obj(child_list, num_children, &child, &max_value_width);
2224
2225     util_free(child_list);
2226
2227     if (cell_width < max_label_width + max_value_width)
2228         cell_width = max_label_width + max_value_width;
2229
2230     get_row_col(obj, &num_rows, &num_columns);
2231
2232     if (num_rows > 0)
2233         one_col = (ABObj *)util_malloc(num_rows * sizeof(ABObj));
2234
2235     for (i = 0; i < num_columns; i++)
2236     {
2237         ABObj   ref_obj;
2238         int     ref_width;
2239
2240         for (j = 0; j < num_rows; j++)
2241             one_col[j] = get_child(obj, i, j);
2242
2243         get_widest_label_obj(one_col, num_rows, &ref_obj, &ref_width);
2244
2245         if (!ref_obj)
2246             continue;
2247
2248         if (previous_ref_obj)
2249         {
2250             offset = (i * (obj_get_hoffset(obj) + cell_width));
2251
2252             attach.offset = offset;
2253         }
2254         else
2255             attach.offset = 0;
2256
2257         attach.type = AB_ATTACH_POINT;
2258         attach.value = (void *)NULL;
2259
2260         abobj_set_attachment(ref_obj, AB_CP_WEST, &attach);
2261
2262         for (j = 0; j < num_rows; j++)
2263         {
2264             child = get_child(obj, i, j);
2265
2266             if (!child || (child == ref_obj))
2267                 continue;
2268
2269             offset = (i * (obj_get_hoffset(obj) + cell_width));
2270             offset += ref_width - abobj_get_label_width(child);
2271
2272             attach.type = AB_ATTACH_POINT;
2273             attach.value = (void *)NULL;
2274             /*
2275             attach.offset = ref_x - abobj_get_label_width(child);
2276             */
2277             attach.offset = offset;
2278
2279             abobj_set_attachment(child, AB_CP_WEST, &attach);
2280         }
2281
2282         previous_ref_obj = ref_obj;
2283     }
2284 }
2285
2286 static void
2287 group_align_vcenters(
2288         ABObj   obj,
2289         BOOL    init
2290 )
2291 {
2292     ABAttachment        attach;
2293     ABObj       child,
2294                 previous_child,
2295                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
2296     AB_GROUP_TYPE type = obj_get_group_type(obj);
2297     int         num_children = obj_get_num_children(oobj),
2298                 num_columns,
2299                 num_rows,
2300                 cell_width,
2301                 cell_height,
2302                 group_width,
2303                 group_height,
2304                 offset,
2305                 gridline,
2306                 i,
2307                 j;
2308
2309     if (num_children <= 0)
2310         return;
2311
2312     get_cell_size(obj, &cell_width, &cell_height);
2313
2314     get_row_col(obj, &num_rows, &num_columns);
2315
2316     offset = obj_get_hoffset(obj);
2317
2318     if (type == AB_GROUP_ROWSCOLUMNS)
2319     {
2320         group_width = (num_columns * cell_width) + ((num_columns-1) * offset);
2321         abobj_set_pixel_width(obj, group_width, 0);
2322         abobj_instantiate_changes(obj);
2323     }
2324
2325     for (i = 0; i < num_columns; i++)
2326     {
2327         if (type == AB_GROUP_ROWSCOLUMNS)
2328             gridline = (((i * (cell_width + offset)) + (cell_width/2)) * 100)/group_width;
2329         else
2330             gridline = 50;
2331
2332         for (j = 0; j < num_rows; j++)
2333         {
2334             child = get_child(obj, i, j);
2335
2336             if (!child)
2337                 continue;
2338
2339             if (init)
2340             {
2341                 int     init_offset = 0;
2342                 Widget  child_widget = objxm_get_widget(child);
2343
2344                 if (child_widget && !XtIsSubclass(child_widget, compositeWidgetClass))
2345                 {
2346                     int         width = abobj_get_actual_width(child);
2347
2348                     init_offset = (cell_width - width)/2;
2349
2350                     if (type == AB_GROUP_ROWSCOLUMNS)
2351                         init_offset += (i * (cell_width + offset));
2352                 }
2353
2354                 attach.type = AB_ATTACH_POINT;
2355                 attach.value = (void *)0;
2356                 attach.offset = init_offset;
2357             }
2358             else
2359             {
2360                 int             width = abobj_get_actual_width(child);
2361
2362                 attach.type = AB_ATTACH_GRIDLINE;
2363                 attach.value = (void *)gridline;
2364                 attach.offset = -(width/2);
2365             }
2366
2367             abobj_set_attachment(child, AB_CP_WEST, &attach);
2368         }
2369     }
2370
2371     if (type == AB_GROUP_ROWSCOLUMNS)
2372     {
2373         abobj_set_pixel_width(obj, -1, 0);
2374         abobj_instantiate_changes(obj);
2375     }
2376 }
2377
2378 static void
2379 group_align_right(
2380         ABObj   obj
2381 )
2382 {
2383     ABAttachment        attach;
2384     ABObj       child,
2385                 previous_child,
2386                 oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
2387     AB_GROUP_TYPE type = obj_get_group_type(obj);
2388     int         num_children = obj_get_num_children(oobj),
2389                 num_columns,
2390                 num_rows,
2391                 cell_width,
2392                 cell_height,
2393                 offset,
2394                 i,
2395                 j;
2396
2397     if (num_children <= 0)
2398         return;
2399
2400     get_cell_size(obj, &cell_width, &cell_height);
2401
2402     get_row_col(obj, &num_rows, &num_columns);
2403
2404     for (j = 0; j < num_rows; j++)
2405     {
2406         for (i = 0; i < num_columns; i++)
2407         {
2408             child = get_child(obj, i, j);
2409
2410             if (!child)
2411                 continue;
2412
2413             if ((i == 0) && (j == 0))
2414             {
2415                 offset = (cell_width - abobj_get_actual_width(child));
2416
2417                 attach.type = AB_ATTACH_POINT;
2418                 attach.value = (void *)0;
2419                 attach.offset = offset;
2420
2421                 abobj_set_attachment(child, AB_CP_WEST, &attach);
2422
2423                 continue;
2424             }
2425
2426             if (j == 0)
2427             {
2428                 previous_child = get_child(obj, i-1, j);
2429
2430                 if (!previous_child)
2431                     continue;
2432
2433                 offset = obj_get_hoffset(obj);
2434
2435                 if (type == AB_GROUP_ROWSCOLUMNS)
2436                     offset +=
2437                         (cell_width - abobj_get_actual_width(child));
2438
2439                 attach.type = AB_ATTACH_OBJ;
2440                 attach.value = (void *)previous_child;
2441                 attach.offset = offset;
2442
2443                 abobj_set_attachment(child, AB_CP_WEST, &attach);
2444
2445                 continue;
2446             }
2447
2448             previous_child = get_child(obj, i, j-1);
2449
2450             if (previous_child)
2451             {
2452                 attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
2453                 attach.value = (void *)previous_child;
2454                 attach.offset = 0;
2455
2456                 abobj_set_attachment(child, AB_CP_EAST, &attach);
2457             }
2458         }
2459     }
2460 }
2461
2462 static void
2463 create_member_list(
2464     ABObj  cobj,
2465     ABObj **member_list,
2466     int    *member_count
2467 )
2468 {
2469     AB_TRAVERSAL  trav;
2470     int           member_index;
2471     ABObj         member;
2472
2473     *member_count = trav_count(cobj,
2474                 AB_TRAV_SALIENT_CHILDREN | AB_TRAV_MOD_SAFE);
2475
2476     *member_list = (ABObj *)malloc(*member_count * sizeof(ABObj));
2477
2478     /*
2479      * Create list of members.
2480      */
2481     for (trav_open(&trav, cobj, AB_TRAV_SALIENT_CHILDREN |
2482                 AB_TRAV_MOD_SAFE), member_index = 0;
2483                 (member = trav_next(&trav)) != NULL; ++member_index)
2484     {
2485         (*member_list)[member_index] = member;
2486     }
2487
2488     trav_close(&trav);
2489 }
2490
2491 static ABObj
2492 get_child(
2493     ABObj       group,
2494     int         x_pos,
2495     int         y_pos
2496 )
2497 {
2498     AB_GROUP_TYPE       type;
2499     ABObj               ret_child = NULL,
2500                         oobj;
2501     int                 num_children,
2502                         num_rows,
2503                         num_columns,
2504                         i = -1;
2505
2506     if (!group || !obj_is_group(group) ||
2507        (x_pos < 0) || (y_pos < 0))
2508         return (NULL);
2509
2510     type = obj_get_group_type(group);
2511     num_rows = obj_get_num_rows(group);
2512     num_columns = obj_get_num_columns(group);
2513
2514     oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
2515     num_children = obj_get_num_children(oobj);
2516
2517     switch (type)
2518     {
2519         case AB_GROUP_IGNORE:
2520         break;
2521
2522         case AB_GROUP_ROWS:
2523             /*
2524              * num_rows = 1
2525              * y_pos is ignored
2526              */
2527             i = x_pos;
2528         break;
2529
2530         case AB_GROUP_COLUMNS:
2531             /*
2532              * num_columns = 1
2533              * x_pos is ignored
2534              */
2535             i = y_pos;
2536         break;
2537
2538         case AB_GROUP_ROWSCOLUMNS:
2539             if (!num_rows && !num_columns)
2540                 break;
2541
2542             if (num_rows > 0)
2543             {
2544                 /*
2545                  * ROWFIRST
2546                  */
2547                 if (y_pos < num_rows)
2548                     i = (x_pos * num_rows) + y_pos;
2549             }
2550             else
2551             {
2552                 /*
2553                  * COLFIRST
2554                  */
2555                 if (x_pos < num_columns)
2556                     i = x_pos + (y_pos * num_columns);
2557             }
2558         break;
2559
2560         default:
2561         break;
2562     }
2563
2564     if ((i >= 0) && (i < num_children))
2565     {
2566         ret_child = obj_get_child(oobj, i);
2567     }
2568
2569     return (ret_child);
2570 }
2571
2572 static void
2573 get_cell_size(
2574     ABObj       group,
2575     int         *cell_width,
2576     int         *cell_height
2577 )
2578 {
2579     AB_GROUP_TYPE type;
2580
2581     if (!group)
2582     {
2583         *cell_width = *cell_height = -1;
2584
2585         return;
2586     }
2587
2588     type = obj_get_group_type(group);
2589
2590     /*
2591     if (type == AB_GROUP_ROWSCOLUMNS)
2592     */
2593     if (1)
2594     {
2595         ABObj   *member_list,
2596                 oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
2597         int     member_count;
2598
2599         create_member_list(oobj, &member_list, &member_count);
2600         abobj_get_greatest_size(member_list, member_count,
2601                 cell_width, cell_height,
2602                 (ABObj *) NULL, (ABObj *) NULL);
2603
2604         util_free(member_list);
2605     }
2606     else
2607         *cell_width = *cell_height = -1;
2608 }
2609
2610 static void
2611 get_row_col(
2612     ABObj       group,
2613     int         *rows,
2614     int         *cols
2615 )
2616 {
2617     ABObj       oobj;
2618     int         num_rows,
2619                 num_cols,
2620                 num_children;
2621
2622     if (!group)
2623     {
2624         *rows = *cols = -1;
2625
2626         return;
2627     }
2628
2629     oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
2630
2631     num_rows = obj_get_num_rows(group);
2632     num_cols = obj_get_num_columns(group);
2633     num_children = obj_get_num_children(oobj);
2634
2635     if ((num_rows <= 0) && (num_cols <= 0))
2636     {
2637         *rows = *cols = -1;
2638
2639         return;
2640     }
2641
2642     if (num_cols <= 0)
2643         num_cols = (num_children/num_rows) + ((num_children % num_rows) ? 1 : 0);
2644
2645     if (num_rows <= 0)
2646         num_rows = (num_children/num_cols) + ((num_children % num_cols) ? 1 : 0);
2647
2648     *rows = num_rows;
2649     *cols = num_cols;
2650 }
2651
2652 static void
2653 group_align_rows(
2654     ABObj       obj,
2655     BOOL        init
2656 )
2657 {
2658
2659     if (!obj || !obj_is_group(obj))
2660         return;
2661
2662     switch (obj_get_row_align(obj))
2663     {
2664         case AB_ALIGN_TOP:
2665             group_align_tops(obj);
2666         break;
2667
2668         case AB_ALIGN_HCENTER:
2669             group_align_hcenters(obj, init);
2670         break;
2671
2672         case AB_ALIGN_BOTTOM:
2673             group_align_bottoms(obj);
2674         break;
2675
2676         default:
2677             /*
2678              * Default to AB_ALIGN_TOP
2679              */
2680             group_align_tops(obj);
2681             break;
2682     }
2683
2684 }
2685
2686 static void
2687 group_align_cols(
2688     ABObj       obj,
2689     BOOL        init
2690 )
2691 {
2692
2693     if (!obj || !obj_is_group(obj))
2694         return;
2695
2696     switch (obj_get_col_align(obj))
2697     {
2698         case AB_ALIGN_LEFT:
2699             group_align_left(obj);
2700         break;
2701
2702         case AB_ALIGN_LABELS:
2703             group_align_labels(obj);
2704         break;
2705
2706         case AB_ALIGN_VCENTER:
2707             group_align_vcenters(obj, init);
2708         break;
2709
2710         case AB_ALIGN_RIGHT:
2711             group_align_right(obj);
2712         break;
2713
2714         default:
2715             /*
2716              * Default to AB_ALIGN_LEFT
2717              */
2718             group_align_left(obj);
2719             break;
2720     }
2721 }
2722
2723 static void
2724 get_widest_label_obj(
2725     ABObj       *list,
2726     int         count,
2727     ABObj       *widest_label,
2728     int         *label_width
2729 )
2730 {
2731     int         i,
2732                 tmp_width,
2733                 cur_width = 0;
2734     ABObj       widest = NULL;
2735
2736     if (!list || !widest_label)
2737         return;
2738
2739     for (i = 0; i < count; ++i)
2740     {
2741         if (list[i])
2742         {
2743             tmp_width = abobj_get_label_width(list[i]);
2744
2745             if (tmp_width > cur_width)
2746             {
2747                 cur_width = tmp_width;
2748                 widest = list[i];
2749             }
2750         }
2751     }
2752
2753     *widest_label = widest;
2754
2755     if (label_width)
2756         *label_width = cur_width;
2757 }
2758
2759 static void
2760 get_widest_value_obj(
2761     ABObj       *list,
2762     int         count,
2763     ABObj       *widest_value,
2764     int         *value_width
2765 )
2766 {
2767     int         i,
2768                 tmp_width,
2769                 cur_width = 0;
2770     ABObj       widest = NULL;
2771
2772     if (!list || !widest_value)
2773         return;
2774
2775     for (i = 0; i < count; ++i)
2776     {
2777         if (list[i])
2778         {
2779             int         label_width,
2780                         obj_width;
2781
2782             label_width = abobj_get_label_width(list[i]);
2783             obj_width = abobj_get_actual_width(list[i]);
2784
2785             tmp_width = obj_width - label_width;
2786
2787             if (tmp_width > cur_width)
2788             {
2789                 cur_width = tmp_width;
2790                 widest = list[i];
2791             }
2792         }
2793     }
2794
2795     *widest_value = widest;
2796
2797     if (value_width)
2798         *value_width = cur_width;
2799 }