Files
cdesktop/cde/programs/dtappbuilder/src/ab/pal_group.c

2801 lines
66 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
* $XConsortium: pal_group.c /main/6 1996/08/30 14:01:29 mustafa $
*
* @(#)pal_group.c 1.58 08 May 1995
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement between
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel without
* Sun's specific written approval. This document and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*/
/*
* pal_group.c - Implements Group object functionality
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <Xm/Xm.h>
#include "dtb_utils.h"
#include <ab_private/ab.h>
#include <ab_private/trav.h>
#include <ab_private/pal.h>
#include <ab_private/prop.h>
#include <ab_private/brws.h>
#include <ab_private/abobj.h>
#include <ab_private/objxm.h>
#include <ab_private/abobj_set.h>
#include <ab_private/proj.h>
#include <ab_private/ui_util.h>
#include <ab_private/x_util.h>
#include <ab_private/abobj_edit.h>
#include "dtbuilder.h"
#include "abobjP.h"
#include "group_ui.h"
/*
* Bitmaps
*/
#include "bitmaps/ggp_as_is.xbm"
#include "bitmaps/ggp_col.xbm"
#include "bitmaps/ggp_row.xbm"
#include "bitmaps/ggp_rowcol.xbm"
#include "bitmaps/align_top.xbm"
#include "bitmaps/align_hcenter.xbm"
#include "bitmaps/align_bottom.xbm"
#include "bitmaps/align_left.xbm"
#include "bitmaps/align_labels.xbm"
#include "bitmaps/align_vcenter.xbm"
#include "bitmaps/align_right.xbm"
/*
* Defines
*/
#define HOFFSET 10
#define VOFFSET 8
#define NUMROWCOL 2
typedef struct PROP_GROUP_SETTINGS
{
Widget prop_sheet;
PropFieldSettingRec name;
PropOptionsSettingRec frame;
PropRadioSettingRec layout_type;
PropRadioSettingRec grid_rowcol;
PropFieldSettingRec grid_rowcol_count;
PropOptionsSettingRec valign;
PropFieldSettingRec vspacing;
PropOptionsSettingRec halign;
PropFieldSettingRec hspacing;
PropGeometrySettingRec pos;
PropCheckboxSettingRec init_state;
PropColorSettingRec bg_color;
ABObj current_obj;
} PropGroupSettingsRec, *PropGroupSettings;
/*************************************************************************
** **
** Private Function Declarations **
** **
**************************************************************************/
/*
* Methods
*/
static int group_initialize(
ABObj obj
);
static Widget group_prop_init(
Widget parent,
AB_PROP_TYPE type
);
static int group_prop_activate(
AB_PROP_TYPE type,
BOOL active
);
static int group_prop_load(
ABObj obj,
AB_PROP_TYPE type,
unsigned long loadkey
);
static int group_prop_clear(
AB_PROP_TYPE type
);
static int group_prop_apply(
AB_PROP_TYPE type
);
static BOOL group_prop_pending(
AB_PROP_TYPE type
);
static BOOL verify_props(
AB_PROP_TYPE type
);
static void turnoff_changebars(
AB_PROP_TYPE type
);
static void setup_grouptype_settings(
AB_PROP_TYPE type,
AB_GROUP_TYPE gtype
);
static void set_new_group_size(
ABObj obj
);
static void group_objects(
ABObj newgroup,
ABObj *obj_list,
int count
);
static void ungroup_objects(
ABObj *obj_list,
int count
);
static void group_align_tops(
ABObj obj
);
static void group_align_hcenters(
ABObj obj,
BOOL init
);
static void group_align_horiz_same_size(
ABObj obj
);
static void group_align_bottoms(
ABObj obj
);
static void group_align_left(
ABObj obj
);
static void group_align_labels(
ABObj obj
);
static void group_align_vcenters(
ABObj obj,
BOOL init
);
static void group_align_right(
ABObj obj
);
static void create_member_list(
ABObj cobj,
ABObj **member_list,
int *member_count
);
static void get_cell_size(
ABObj group,
int *cell_width,
int *cell_height
);
static void get_row_col(
ABObj group,
int *rows,
int *cols
);
static void group_align_rows(
ABObj obj,
BOOL init
);
static void group_align_cols(
ABObj obj,
BOOL init
);
static void get_widest_label_obj(
ABObj *list,
int count,
ABObj *widest_label,
int *label_width
);
static void get_widest_value_obj(
ABObj *list,
int count,
ABObj *widest_value,
int *value_width
);
/*
* Callbacks
*/
static void grouptypeCB(
Widget widget,
XtPointer clientdata,
XmToggleButtonCallbackStruct *state
);
static void undo_group(
ABUndoRec undo_rec
);
static void undo_ungroup(
ABUndoRec undo_rec
);
static ABObj get_child(
ABObj group,
int x_pos,
int y_pos
);
static void group_expose_handler(
Widget widget,
XtPointer client_data,
XEvent *event,
Boolean *cont_dispatch
);
DtbGroupPropDialogInfoRec rev_group_prop_dialog;
/*************************************************************************
** **
** Data **
** **
**************************************************************************/
PalItemInfo group_palitem_rec = {
/* type */ AB_TYPE_CONTAINER,
/* name */ "Group",
/* animation pixmaps*/ NULL,
/* number of pixmaps*/ 0,
/* rev_prop_frame */ NULL,
/* fix_prop_dialog */ NULL,
/* initialize */ group_initialize,
/* is_a_test */ obj_is_group,
/* prop_initialize */ group_prop_init,
/* prop_active */ group_prop_activate,
/* prop_clear */ group_prop_clear,
/* prop_load */ group_prop_load,
/* prop_apply */ group_prop_apply,
/* prop_pending */ group_prop_pending
};
PalItemInfo *ab_group_palitem = &group_palitem_rec;
PropGroupSettingsRec prop_group_settings_rec[AB_PROP_TYPE_NUM_VALUES];
/*************************************************************************
** **
** Function Definitions **
** **
**************************************************************************/
/*
* Create a group object out of the selected group of objects.
*/
void
abobj_group_selected_objects(void)
{
ABObj project = proj_get_project();
ABObj obj;
ABObj newgroup;
ABObj obj_parent;
ABSelectedRec sel;
XRectangle current_rect;
int i;
/* Creation may take awhile, so set busy cursor */
ab_set_busy_cursor(True);
abobj_get_selected(project, False, False, &sel);
abobj_get_rect_for_objects(sel.list, sel.count, &current_rect);
obj_parent = obj_get_parent(sel.list[0]);
newgroup = obj_create(AB_TYPE_CONTAINER, obj_parent);
obj_set_subtype(newgroup, AB_CONT_GROUP);
if (group_initialize(newgroup) == ERROR)
fprintf(stderr, "create_obj_action: couldn't initialize object\n");
else if (abobj_show_tree(newgroup, False) == -1)
fprintf(stderr,"create_obj_action: couldn't show object\n");
else
{
/* Deselect any objects that happen to be selected */
abobj_deselect_all(project);
aob_deselect_all_objects(project);
group_objects(newgroup, sel.list, sel.count);
/*
* Can only create one group at a time, therefore
* only worry about undoing one group.
*/
abobj_set_undo(&newgroup, 1, undo_group, AB_UNDO_GROUP);
}
/* Restore to original cursor */
ab_set_busy_cursor(False);
}
static void
group_objects(
ABObj newgroup,
ABObj *list,
int count
)
{
ABObj obj;
ABSelectedRec sel;
XRectangle current_rect;
int i;
abobj_get_rect_for_objects(list, count, &current_rect);
/*
* Reparent each selected object and set x,y to group
* coordinates.
*/
for (i = 0; i < count; i++)
{
AB_TRAVERSAL trav;
ABObj cur_obj = NULL;
obj = list[i];
obj_reparent(obj, newgroup);
abobj_set_xy(obj, obj_get_x(obj) - current_rect.x,
obj_get_y(obj) - current_rect.y);
/*
* Clear instantiated flag in child
*/
obj_clear_flag(obj, InstantiatedFlag);
/*
* Clear instantiated flag in child subtree as
* well
*/
for (trav_open(&trav, obj, AB_TRAV_ALL);
(cur_obj = trav_next(&trav)) != NULL; )
{
obj_clear_flag(cur_obj, InstantiatedFlag);
}
trav_close(&trav);
}
/*
* For some reason, width and height need to be set on the
* group.
*/
/*
obj_set_width(newgroup, current_rect.width);
obj_set_height(newgroup, current_rect.height);
*/
abobj_tree_instantiate_changes(newgroup);
/* Make the new obj selected */
abobj_select(newgroup);
}
/*
* Ungroup a group. Get list of selected objects, look for groups
* in the list. If found, traverse throught the groups children and
* re-parent/re-position the child. Finally, keep a list of new parents
* to be updated (so that no parent is updated more than once) and update
* them after all groups have been ungrouped.
*/
void
abobj_ungroup_selected_objects(void)
{
ABObj project = proj_get_project();
ABSelectedRec sel;
/* Ungrouping may take awhile, so set busy cursor */
ab_set_busy_cursor(True);
/* Get list of selected objects */
abobj_get_selected(project, False, False, &sel);
/*
* Remember all objects that were ungrouped so can undo this later
*/
abobj_set_undo(sel.list, sel.count, undo_ungroup, AB_UNDO_UNGROUP);
ungroup_objects(sel.list, sel.count);
/* Restore to original cursor */
ab_set_busy_cursor(False);
}
/*
* Ungroups passed objects. Look for groups in the list. If found,
* traverse throught the groups children and re-parent/re-position the
* child. Finally, keep a list of new parents to be updated so that
* no parent is updated more than once and update them after all groups
* have been ungrouped.
*/
static void
ungroup_objects(
ABObj *obj_list,
int count
)
{
ABObj group;
ABObj group_parent;
ABObj parent_list = NULL;
XRectangle group_rect,
rect;
AB_TRAVERSAL trav;
ABObj member;
int i, j;
ABObj *list = NULL;
int list_items;
Boolean parent_exists = True;
if (!obj_list || (count <= 0))
return;
for (i = 0; i < count; i++)
{
group = obj_list[i];
if (obj_is_group(group))
{
ABObj oobj = NULL,
*member_list = NULL;
int num_children,
cur_member = 0;
abobj_deselect(group);
group_parent = obj_get_parent(group);
/*
* Remember group's position
*/
group_rect.x = group_rect.y = 0;
x_get_widget_rect(objxm_get_widget(group), &group_rect);
oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
num_children = obj_get_num_children(oobj);
member_list = (ABObj *)util_malloc(num_children * sizeof(ABObj*));
/*
* Group members are all direct children of the AB_CFG_OBJECT_OBJ
* object
*/
for (trav_open(&trav, oobj, AB_TRAV_CHILDREN |
AB_TRAV_MOD_SAFE);
(member = trav_next(&trav)) != NULL; )
{
Widget member_w;
member_w = objxm_get_widget(member);
/*
* Get member's current position
*/
rect.x = rect.y = 0;
x_get_widget_rect(member_w, &rect);
obj_reparent(member, group_parent);
/*
* Set attachments with 0 x and y. abobj_set_xy will
* set the correct values.
*/
obj_init_attachments(member);
obj_set_attachment(member, AB_CP_NORTH, AB_ATTACH_POINT,
NULL, 0);
obj_set_attachment(member, AB_CP_WEST, AB_ATTACH_POINT,
NULL, 0);
/*
* Set new position to be:
* group's (x, y) + current (x, y)
*/
abobj_set_xy(member, group_rect.x + rect.x,
group_rect.y + rect.y);
/*
* Keep track of objects to re-instantiate later
* We don't do it here because we don't want to screw up
* the x_get_widget_rect() calls in the current group.
*/
member_list[cur_member++] = member;
}
trav_close(&trav);
/*
* Un/re-instantiate former group members
*/
for (cur_member = 0; cur_member < num_children; ++cur_member)
{
ABObj cur_obj = NULL;
/*
* Clear instantiated flag in former group member
*/
obj_clear_flag(member_list[cur_member], InstantiatedFlag);
/*
* Clear instantiated flag in former group member's subtree
* as well
*/
for (trav_open(&trav, member_list[cur_member], AB_TRAV_ALL);
(cur_obj = trav_next(&trav)) != NULL; )
{
obj_clear_flag(cur_obj, InstantiatedFlag);
}
/*
* The manage_lat parameter used to be FALSE.
* It caused list objects to get the wrong size when
* ungroup was done. Changing to TRUE somehow fixes
* this.
*/
abobj_show_tree(member_list[cur_member], TRUE);
}
util_free(member_list);
obj_destroy(group);
/*
* Keep a list of parents (control panels) that need
* to be updated after all groups are ungrouped.
*/
if (list == NULL)
{
list = (ABObj*)XtMalloc(sizeof(ABObj));
list[0] = group_parent;
list_items = 1;
}
else
for (j = 0; j < list_items; j++)
{
if (list[j] == group_parent)
{
parent_exists = True;
break;
}
}
if (parent_exists == False)
{
XtRealloc((char*)list, sizeof(ABObj));
list[list_items++] = group_parent;
}
parent_exists = False;
}
}
}
static int
group_initialize(
ABObj obj
)
{
ABObj iobj, mobj;
AB_GROUP_TYPE group_type;
int i;
ABObj parent = obj_get_parent(obj);
ABSelectedRec sel;
XRectangle current_rect;
abobj_get_selected(proj_get_project(), False, False, &sel);
abobj_get_rect_for_objects(sel.list, sel.count, &current_rect);
obj_set_unique_name(obj, "group");
/*
abobj_set_initial_state(obj, AB_STATE_ACTIVE);
*/
obj_set_is_initially_active(obj, True);
obj_set_x(obj, current_rect.x);
obj_set_y(obj, current_rect.y);
/*
obj_set_width(obj, current_rect.width);
obj_set_height(obj, current_rect.height);
*/
obj_set_group_type(obj, AB_GROUP_IGNORE);
/* Set up Default Layout for group*/
obj_set_attachment(obj, AB_CP_NORTH, AB_ATTACH_POINT, NULL, obj->y);
obj_set_attachment(obj, AB_CP_WEST, AB_ATTACH_POINT, NULL, obj->x);
return OK;
}
static Widget
group_prop_init(
Widget parent,
AB_PROP_TYPE type
)
{
/* Revolving Props */
/*
DtbGroupPropDialogInfoRec rev_group_prop_dialog;
*/
DtbGroupPropDialogInfo cgen = &dtb_group_prop_dialog; /* Codegen structure */
DtbRevolvPropDialogInfo rpd = &(dtb_revolv_prop_dialog);
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
Widget item[10];
XtArgVal item_val[10];
XtPointer item_ptr[10];
int n;
int i;
if (type == AB_PROP_REVOLVING)
{
/* Cloning Trick:
* Only the Attributes ControlPanel needs to be created within
* the existing Revolving Prop dialog, so fill out all other
* fields with the Revolving Prop dialog equivelents, so the
* dtb initialize proc will skip those non-NULL fields...
*/
dtbGroupPropDialogInfo_clear(&rev_group_prop_dialog);
cgen = &(rev_group_prop_dialog);
cgen->prop_dialog = rpd->prop_dialog;
cgen->prop_dialog_shellform = rpd->prop_dialog_shellform;
cgen->prop_dialog_panedwin = rpd->prop_dialog_panedwin;
cgen->prop_dialog_form = rpd->prop_dialog_form;
cgen->objlist_panel = rpd->objlist_panel;
cgen->objlist_label = rpd->objlist_label2;
cgen->objlist_scrolledwin = rpd->objlist_scrolledwin;
cgen->objlist = rpd->objlist;
cgen->attrs_ctrlpanel_frame = rpd->attrs_ctrlpanel_frame;
cgen->activate_panel = rpd->activate_panel;
cgen->apply_button = rpd->apply_button;
cgen->ok_button = rpd->ok_button;
cgen->cancel_button = rpd->cancel_button;
cgen->reset_button = rpd->reset_button;
cgen->help_button = rpd->help_button;
}
else /* AB_PROP_FIXED */
cgen = &dtb_group_prop_dialog;
if (dtb_group_prop_dialog_initialize(cgen, parent) == 0)
{
pgs->prop_sheet = cgen->attrs_ctrlpanel;
pgs->current_obj = NULL;
if (type == AB_PROP_REVOLVING)
XtVaSetValues(parent,
XmNuserData, pgs->current_obj,
NULL);
/* Dialog/Object List */
if (type == AB_PROP_FIXED)
{
prop_fixed_dialog_init(ab_group_palitem,
cgen->prop_dialog_shellform, cgen->objlist);
prop_activate_panel_init(type, ab_group_palitem,
cgen->ok_button, cgen->apply_button,
cgen->reset_button, cgen->cancel_button,
cgen->help_button);
}
/* Alternate Editor Buttons */
prop_editors_panel_init(type, ab_group_palitem,
cgen->attach_button, cgen->conn_button, cgen->helptxt_button);
/*
* Prop Sheet Settings....
*/
/* Name */
prop_field_init(&(pgs->name), cgen->name_field_label,
cgen->name_field, cgen->name_cb);
/* Border Frame Setting */
n = 0;
item[n] = cgen->bframe_opmenu_items.None_item;
item_ptr[n] = AB_LINE_NONE; n++;
item[n] = cgen->bframe_opmenu_items.Shadow_Out_item;
item_ptr[n] = AB_LINE_SHADOW_OUT; n++;
item[n] = cgen->bframe_opmenu_items.Shadow_In_item;
item_ptr[n] = AB_LINE_SHADOW_IN; n++;
item[n] = cgen->bframe_opmenu_items.Etched_Out_item;
item_ptr[n] = AB_LINE_ETCHED_OUT; n++;
item[n] = cgen->bframe_opmenu_items.Etched_In_item;
item_ptr[n] = AB_LINE_ETCHED_IN; n++;
prop_options_init(&(pgs->frame), cgen->bframe_opmenu_label,
cgen->bframe_opmenu, cgen->bframe_opmenu_menu,
n, item, item_ptr,
cgen->bframe_cb);
/* Layout Type */
n = 0;
item[n] = cgen->layout_rbox_items.bitmaps_ggp_as_is_xbm_item;
item_ptr[n] = AB_GROUP_IGNORE; n++;
item[n] = cgen->layout_rbox_items.bitmaps_ggp_col_xbm_item;
item_ptr[n] = AB_GROUP_COLUMNS; n++;
item[n] = cgen->layout_rbox_items.bitmaps_ggp_row_xbm_item;
item_ptr[n] = AB_GROUP_ROWS; n++;
item[n] = cgen->layout_rbox_items.bitmaps_ggp_rowcol_xbm_item;
item_ptr[n] = AB_GROUP_ROWSCOLUMNS; n++;
prop_radiobox_init(&(pgs->layout_type), cgen->layout_rbox_label,
cgen->layout_rbox, n, item, item_ptr,
cgen->layout_cb1);
for (i=0; i < n; i++)
XtAddCallback(item[i], XmNvalueChangedCallback,
(XtCallbackProc)grouptypeCB, (XtPointer)type);
/*
ui_set_active(cgen->layout_rbox_items.bitmaps_ggp_rowcol_xbm_item, False);
*/
/* Grid Row/Columns */
n = 0;
item[n] = cgen->gridrowcol_rbox_items.Rows_item;
item_ptr[n] = AB_ORIENT_HORIZONTAL; n++;
item[n] = cgen->gridrowcol_rbox_items.Columns_item;
item_ptr[n] = AB_ORIENT_VERTICAL; n++;
prop_radiobox_init(&(pgs->grid_rowcol), NULL,
cgen->gridrowcol_rbox, n, item, item_ptr,
cgen->gridrowcol_cb);
/* Grid Row/Column count */
prop_field_init(&(pgs->grid_rowcol_count), NULL,
cgen->gridrowcol_field, cgen->gridrowcol_cb);
/* Vertical Alignment */
n = 0;
item[n] = cgen->valign_opmenu_items.bitmaps_align_left_xbm_item;
item_ptr[n] = AB_ALIGN_LEFT; n++;
item[n] = cgen->valign_opmenu_items.bitmaps_align_labels_xbm_item;
item_ptr[n] = AB_ALIGN_LABELS; n++;
item[n] = cgen->valign_opmenu_items.bitmaps_align_vcenter_xbm_item;
item_ptr[n] = AB_ALIGN_VCENTER; n++;
item[n] = cgen->valign_opmenu_items.bitmaps_align_right_xbm_item;
item_ptr[n] = AB_ALIGN_RIGHT; n++;
prop_options_init(&(pgs->valign), cgen->valign_opmenu_label,
cgen->valign_opmenu, cgen->valign_opmenu_menu,
n, item, item_ptr,
cgen->valign_cb);
/* Vertical spacing value */
prop_field_init(&(pgs->vspacing), NULL,
cgen->vert_spacing_field, cgen->valign_cb);
/* Horizontal Alignment */
n = 0;
item[n] = cgen->halign_opmenu_items.bitmaps_align_top_xbm_item;
item_ptr[n] = AB_ALIGN_TOP; n++;
item[n] = cgen->halign_opmenu_items.bitmaps_align_hcenter_xbm_item;
item_ptr[n] = AB_ALIGN_HCENTER; n++;
item[n] = cgen->halign_opmenu_items.bitmaps_align_bottom_xbm_item;
item_ptr[n] = AB_ALIGN_BOTTOM; n++;
prop_options_init(&(pgs->halign), cgen->halign_opmenu_label,
cgen->halign_opmenu, cgen->halign_opmenu_menu,
n, item, item_ptr,
cgen->halign_cb);
/* Horizontal spacing value */
prop_field_init(&(pgs->hspacing), NULL,
cgen->horiz_spacing_field, cgen->halign_cb);
/* Position */
prop_geomfield_init(&(pgs->pos), cgen->pos_label,
cgen->x_field_label, cgen->x_field,
cgen->y_field_label, cgen->y_field,
NULL, NULL, NULL, NULL,
cgen->pos_cb);
/* Initial State */
n = 0;
item[n] = cgen->istate_ckbox_items.Visible_item;
item_val[n] = AB_STATE_VISIBLE; n++;
item[n] = cgen->istate_ckbox_items.Active_item;
item_val[n] = AB_STATE_ACTIVE; n++;
prop_checkbox_init(&(pgs->init_state), cgen->istate_ckbox_label,
cgen->istate_ckbox, n, item, item_val,
cgen->istate_cb);
/* Color */
prop_colorfield_init(&(pgs->bg_color), cgen->bg_mbutton,
cgen->bg_mbutton_bg_mbutton_menu_items.None_item,
cgen->bg_mbutton_bg_mbutton_menu_items.Color_Chooser_item,
cgen->bg_swatch, cgen->bg_field, cgen->bg_cb);
prop_changebars_cleared(pgs->prop_sheet);
return (cgen->prop_dialog_shellform);
}
else
return NULL;
}
static int
group_prop_clear(
AB_PROP_TYPE type
)
{
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
if (pgs->current_obj == NULL)
return OK;
/* Clear Name */
prop_field_set_value(&(pgs->name), "", False);
/* Clear Border Frame */
prop_options_set_value(&(pgs->frame), (XtPointer)AB_LINE_NONE, False);
/* Clear Layout Type */
prop_radiobox_set_value(&(pgs->layout_type),
(XtPointer)AB_GROUP_IGNORE, False);
/* Clear Grid Rows/Columns */
prop_radiobox_set_value(&(pgs->grid_rowcol),
(XtPointer)AB_ORIENT_HORIZONTAL, False);
prop_field_set_numeric_value(&(pgs->grid_rowcol_count), NUMROWCOL, False);
/* Clear Vertical Alignment */
prop_options_set_value(&(pgs->valign), (XtPointer)AB_ALIGN_LEFT, False);
prop_field_set_numeric_value(&(pgs->vspacing), 0, False);
/* Clear Horizontal Alignment */
prop_options_set_value(&(pgs->halign), (XtPointer)AB_ALIGN_TOP, False);
prop_field_set_numeric_value(&(pgs->hspacing), 0, False);
/* Clear Object Size */
/* Clear Object Resizing */
/* Clear Position */
prop_geomfield_clear(&(pgs->pos), GEOM_X);
prop_geomfield_clear(&(pgs->pos), GEOM_Y);
/* Clear Initial State */
prop_checkbox_set_value(&(pgs->init_state), AB_STATE_VISIBLE, True, False);
prop_checkbox_set_value(&(pgs->init_state), AB_STATE_ACTIVE, True, False);
/* Clear Color */
prop_colorfield_set_value(&(pgs->bg_color), "", False);
pgs->current_obj = NULL;
turnoff_changebars(type);
return OK;
}
static int
group_prop_activate(
AB_PROP_TYPE type,
BOOL active
)
{
ui_set_active(prop_group_settings_rec[type].prop_sheet, active);
return OK;
}
static int
group_prop_load(
ABObjPtr obj,
AB_PROP_TYPE type,
unsigned long loadkey
)
{
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
AB_GROUP_TYPE gtype;
BOOL load_all = (loadkey & LoadAll);
if (obj == NULL)
{
if (pgs->current_obj != NULL)
obj = pgs->current_obj;
else
return ERROR;
}
else if (!obj_is_group(obj))
return ERROR;
else
pgs->current_obj = obj;
/* Load Name */
if (load_all || loadkey & LoadName)
prop_field_set_value(&(pgs->name), obj_get_name(obj), False);
if (load_all)
{
/* Load Border Frame */
prop_options_set_value(&(pgs->frame), (XtPointer)obj_get_border_frame(obj), False);
/* Load Layout Type */
gtype = obj_get_group_type(obj);
prop_radiobox_set_value(&(pgs->layout_type), (XtPointer)gtype, False);
setup_grouptype_settings(type, gtype);
/* Load Alignment, Grid-Rows/Columns */
switch(gtype)
{
/*
case AB_GROUP_IGNORE:
prop_radiobox_set_value(&(pgs->spacing_type),
AB_ATTACH_OBJ, False);
prop_field_set_numeric_value(&(pgs->spacing),
0, False);
break;
*/
case AB_GROUP_ROWS:
prop_options_set_value(&(pgs->halign),
(XtPointer)obj_get_row_align(obj), False);
prop_field_set_numeric_value(&(pgs->hspacing),
obj_get_hoffset(obj), False);
break;
case AB_GROUP_COLUMNS:
prop_options_set_value(&(pgs->valign),
(XtPointer)obj_get_col_align(obj), False);
prop_field_set_numeric_value(&(pgs->vspacing),
obj_get_voffset(obj), False);
break;
case AB_GROUP_ROWSCOLUMNS:
if (obj_get_num_rows(obj) ||
(!obj_get_num_rows(obj) &&
!obj_get_num_columns(obj)))
{
prop_radiobox_set_value(&(pgs->grid_rowcol),
(XtPointer)AB_ORIENT_HORIZONTAL, False);
prop_field_set_numeric_value(&(pgs->grid_rowcol_count),
obj_get_num_rows(obj), False);
}
else
{
prop_radiobox_set_value(&(pgs->grid_rowcol),
(XtPointer)AB_ORIENT_VERTICAL, False);
prop_field_set_numeric_value(&(pgs->grid_rowcol_count),
obj_get_num_columns(obj), False);
}
prop_options_set_value(&(pgs->halign),
(XtPointer)obj_get_row_align(obj), False);
prop_field_set_numeric_value(&(pgs->hspacing),
obj_get_hoffset(obj), False);
prop_options_set_value(&(pgs->valign),
(XtPointer)obj_get_col_align(obj), False);
prop_field_set_numeric_value(&(pgs->vspacing),
obj_get_voffset(obj), False);
break;
}
/* Load Object Size */
/* Load Object Resizing */
/* Load Initial State */
prop_checkbox_set_value(&(pgs->init_state), AB_STATE_VISIBLE,
obj_is_initially_visible(obj), False);
prop_checkbox_set_value(&(pgs->init_state), AB_STATE_ACTIVE,
obj_is_initially_active(obj), False);
/* Load Color */
prop_colorfield_set_value(&(pgs->bg_color), obj_get_bg_color(obj), False);
turnoff_changebars(type);
}
/* Load Position */
if (load_all || loadkey & LoadPosition)
prop_load_obj_position(obj, &(pgs->pos));
return OK;
}
static int
group_prop_apply(
AB_PROP_TYPE type
)
{
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
STRING value;
AB_GROUP_TYPE gtype;
int num_rc;
int space_val;
int i;
ABObj obj;
BOOL changed = False;
BOOL reset_bg = False;
obj = pgs->current_obj;
gtype = (AB_GROUP_TYPE)prop_radiobox_get_value(&(pgs->layout_type));
if (obj == NULL)
return ERROR;
if (!verify_props(type))
return ERROR;
if (prop_changed(pgs->name.changebar))
{
value = prop_field_get_value(&(pgs->name));
abobj_set_name(pgs->current_obj, value);
util_free(value);
}
/*
* Set rows/columns based on new layout type. If we are
* changing from AB_GROUP_IGNORE to something else, we need
* to sort the children so that the group comes out looking
* close to the initial layout, regardless of the order of
* creation.
*/
if (prop_changed(pgs->layout_type.changebar))
{
changed = True;
switch (gtype)
{
case AB_GROUP_IGNORE:
abobj_set_num_rows(obj, 0);
abobj_set_num_columns(obj, 0);
break;
case AB_GROUP_ROWS:
abobj_set_num_rows(obj, 1);
abobj_set_num_columns(obj, 0);
if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
abobj_sort_children(obj, XSORT);
/*
* If changing types, set defaults for row stuff
* in case the user doesn't change them.
if (obj_get_group_type(obj) != AB_GROUP_ROWS)
{
abobj_set_row_alignment(obj, AB_ALIGN_TOP);
abobj_set_row_attach_type(obj, AB_ATTACH_OBJ);
abobj_set_row_offset(obj, HOFFSET);
}
*/
break;
case AB_GROUP_COLUMNS:
abobj_set_num_rows(obj, 0);
abobj_set_num_columns(obj, 1);
if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
abobj_sort_children(obj, YSORT);
/*
* If changing types, set defaults for column stuff
* in case the user doesn't change them.
if (obj_get_group_type(obj) != AB_GROUP_COLUMNS)
{
abobj_set_col_alignment(obj, AB_ALIGN_LEFT);
abobj_set_col_attach_type(obj, AB_ATTACH_OBJ);
abobj_set_col_offset(obj, VOFFSET);
}
*/
break;
case AB_GROUP_ROWSCOLUMNS:
num_rc = prop_field_get_numeric_value(&(pgs->grid_rowcol_count));
if (prop_radiobox_get_value(&(pgs->grid_rowcol))
== AB_ORIENT_HORIZONTAL)
{
abobj_set_num_rows(obj, num_rc < 2 ? 2 : num_rc);
abobj_set_num_columns(obj, 0);
if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
abobj_sort_children(obj, YSORT);
}
else
{
abobj_set_num_columns(obj, num_rc < 2 ? 2 : num_rc);
abobj_set_num_rows(obj, 0);
if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
abobj_sort_children(obj, XSORT);
}
/*
* If changing types, set defaults for row/column stuff
* in case the user doesn't change them.
*/
if (obj_get_group_type(obj) != AB_GROUP_ROWSCOLUMNS)
{
/*
abobj_set_row_alignment(obj, AB_ALIGN_TOP);
abobj_set_row_attach_type(obj, AB_ATTACH_OBJ);
abobj_set_row_offset(obj, HOFFSET);
abobj_set_col_alignment(obj, AB_ALIGN_LEFT);
abobj_set_col_attach_type(obj, AB_ATTACH_OBJ);
abobj_set_col_offset(obj, VOFFSET);
* Add this later
abobj_set_row_alignment(obj,
(AB_ALIGNMENT)prop_options_get_value(&(pgs->halign)));
abobj_set_row_attach_type(obj,
(AB_ATTACH_TYPE)prop_options_get_value(&(pgs->hspacing_type)));
abobj_set_row_offset(obj,
prop_field_get_numeric_value(&(pgs->hspacing)));
abobj_set_col_alignment(obj,
(AB_ALIGNMENT)prop_options_get_value(&(pgs->valign)));
abobj_set_col_attach_type(obj,
(AB_ATTACH_TYPE)prop_options_get_value(&(pgs->vspacing_type)));
abobj_set_col_offset(obj,
prop_field_get_numeric_value(&(pgs->vspacing)));
*/
}
break;
}
abobj_set_group_type(obj, gtype);
}
if (prop_changed(pgs->grid_rowcol_count.changebar))
{
/*
* Fix this!!
*/
changed = True;
num_rc = prop_field_get_numeric_value(&(pgs->grid_rowcol_count));
if (prop_radiobox_get_value(&(pgs->grid_rowcol))
== AB_ORIENT_HORIZONTAL)
{
abobj_set_num_rows(obj, num_rc < 2 ? 2 : num_rc);
abobj_set_num_columns(obj, 0);
if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
abobj_sort_children(obj, YSORT);
}
else
{
abobj_set_num_columns(obj, num_rc < 2 ? 2 : num_rc);
abobj_set_num_rows(obj, 0);
if (obj_get_group_type(obj) == AB_GROUP_IGNORE)
abobj_sort_children(obj, XSORT);
}
}
if (prop_changed(pgs->halign.changebar))
{
changed = True;
abobj_set_row_alignment(obj,
(AB_ALIGNMENT)prop_options_get_value(&(pgs->halign)));
space_val = prop_field_get_numeric_value(&(pgs->hspacing));
abobj_set_row_offset(obj, space_val);
}
if (prop_changed(pgs->valign.changebar))
{
changed = True;
abobj_set_col_alignment(obj,
(AB_ALIGNMENT)prop_options_get_value(&(pgs->valign)));
space_val = prop_field_get_numeric_value(&(pgs->vspacing));
abobj_set_col_offset(obj, space_val);
}
if (changed)
{
ABObj oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
Widget w = objxm_get_widget(oobj);
WidgetList children_list = NULL;
int num_children = 0;
XtVaGetValues(w,
XmNnumChildren, &num_children,
XmNchildren, &children_list,
NULL);
XtUnmanageChildren(children_list, num_children);
abobj_layout_group(obj, FALSE);
XtManageChildren(children_list, num_children);
}
/* Border Frame and Margin */
if (prop_changed(pgs->frame.changebar))
{
abobj_set_border_frame(pgs->current_obj,
(AB_LINE_TYPE)prop_options_get_value(&(pgs->frame)));
}
if (prop_changed(pgs->pos.changebar))
{
if (abobj_is_movable(pgs->current_obj))
abobj_set_xy(pgs->current_obj,
prop_geomfield_get_value(&(pgs->pos), GEOM_X),
prop_geomfield_get_value(&(pgs->pos), GEOM_Y));
}
if (prop_changed(pgs->init_state.changebar))
{
abobj_set_visible(pgs->current_obj,
prop_checkbox_get_value(&(pgs->init_state), AB_STATE_VISIBLE));
abobj_set_active(pgs->current_obj,
prop_checkbox_get_value(&(pgs->init_state), AB_STATE_ACTIVE));
}
if (prop_changed(pgs->bg_color.changebar))
{
value = prop_colorfield_get_value(&(pgs->bg_color));
abobj_set_background_color(pgs->current_obj, value);
if (util_strempty(value))
reset_bg = True;
util_free(value);
prop_colorfield_set_value(&(pgs->bg_color),
obj_get_bg_color(pgs->current_obj), False);
}
abobj_tree_instantiate_changes(pgs->current_obj);
if (reset_bg) /* Set back to No Color */
abobj_reset_colors(pgs->current_obj, reset_bg, False);
turnoff_changebars(type);
return OK;
}
static BOOL
group_prop_pending(
AB_PROP_TYPE type
)
{
return(prop_changebars_pending(prop_group_settings_rec[type].prop_sheet));
}
static BOOL
verify_props(
AB_PROP_TYPE type
)
{
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
if (prop_changed(pgs->name.changebar) && !prop_name_ok(pgs->current_obj, pgs->name.field))
return False;
if (prop_changed(pgs->bg_color.changebar) && !prop_color_ok(pgs->bg_color.field))
return False;
if (prop_changed(pgs->grid_rowcol_count.changebar) &&
!prop_number_ok(pgs->grid_rowcol_count.field, (STRING)RowColFieldStr, 1, SHRT_MAX))
return False;
if (prop_changed(pgs->valign.changebar) &&
!prop_number_ok(pgs->vspacing.field, (STRING)VertSpacingFieldStr,
-SHRT_MAX, SHRT_MAX))
return False;
if (prop_changed(pgs->halign.changebar) &&
!prop_number_ok(pgs->hspacing.field, (STRING)HorizSpacingFieldStr,
-SHRT_MAX, SHRT_MAX))
return False;
if (prop_changed(pgs->pos.changebar) &&
(!prop_number_ok(pgs->pos.x_field, (STRING)XFieldStr, -SHRT_MAX, SHRT_MAX) ||
!prop_number_ok(pgs->pos.y_field, (STRING)YFieldStr, -SHRT_MAX, SHRT_MAX)))
return False;
return True;
}
static void
turnoff_changebars(
AB_PROP_TYPE type
)
{
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
prop_set_changebar(pgs->name.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->frame.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->layout_type.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->grid_rowcol.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->valign.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->halign.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->pos.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->init_state.changebar, PROP_CB_OFF);
prop_set_changebar(pgs->bg_color.changebar, PROP_CB_OFF);
prop_changebars_cleared(pgs->prop_sheet);
}
static void
grouptypeCB(
Widget item,
XtPointer clientdata,
XmToggleButtonCallbackStruct *state
)
{
AB_PROP_TYPE type = (AB_PROP_TYPE)clientdata;
AB_GROUP_TYPE value = AB_GROUP_UNDEF;
if (state->set)
{
XtVaGetValues(item, XmNuserData, &value, NULL);
setup_grouptype_settings(type, value);
}
}
static void
setup_grouptype_settings(
AB_PROP_TYPE type,
AB_GROUP_TYPE gtype
)
{
PropGroupSettingsRec *pgs = &(prop_group_settings_rec[type]);
DtbGroupPropDialogInfo cgen;
if (type == AB_PROP_REVOLVING)
cgen = &rev_group_prop_dialog;
else
cgen = &dtb_group_prop_dialog;
if (!cgen || !cgen->initialized)
return;
switch(gtype)
{
case AB_GROUP_IGNORE:
ui_set_active(cgen->valign_grp, False);
ui_set_active(cgen->halign_grp, False);
ui_set_active(cgen->grid_rowcol_grp, False);
break;
case AB_GROUP_COLUMNS:
ui_set_active(cgen->valign_grp, True);
ui_set_active(cgen->halign_grp, False);
ui_set_active(cgen->grid_rowcol_grp, False);
break;
case AB_GROUP_ROWS:
ui_set_active(cgen->valign_grp, False);
ui_set_active(cgen->halign_grp, True);
ui_set_active(cgen->grid_rowcol_grp, False);
break;
case AB_GROUP_ROWSCOLUMNS:
ui_set_active(cgen->valign_grp, True);
ui_set_active(cgen->halign_grp, True);
ui_set_active(cgen->grid_rowcol_grp, True);
break;
}
}
static void
undo_group(
ABUndoRec undo_rec
)
{
if (!undo_rec)
return;
/*
* Remember all objects that will be ungrouped here can
* undo this later (undo of undo)
*/
abobj_set_undo(undo_rec->list, undo_rec->count,
undo_ungroup, AB_UNDO_UNGROUP);
/*
* Ungroup objects
*/
ungroup_objects(undo_rec->list, undo_rec->count);
}
static void
undo_ungroup(
ABUndoRec undo_rec
)
{
ABObj newgroup,
parent,
*new_list,
*member_list,
project;
int i,
member_count;
if (!undo_rec)
return;
new_list = (ABObj *)malloc(undo_rec->count * sizeof(ABObj));
project = proj_get_project();
/* Deselect any objects that happen to be selected */
abobj_deselect_all(project);
aob_deselect_all_objects(project);
for (i = 0; i < undo_rec->count; ++i)
{
ABUndoInfo undo_info;
undo_info = &(undo_rec->info_list[i]);
/*
* If undo record is not the right type, something is WRONG !!
*/
if (undo_info->type != AB_UNDO_UNGROUP)
continue;
newgroup = abobj_dup_tree(undo_info->info.ungroup.dup_old_group);
member_list = undo_info->info.ungroup.member_list;
member_count = undo_info->info.ungroup.member_count;
parent = obj_get_parent(member_list[0]);
obj_append_child(parent, newgroup);
if (abobj_show_tree(newgroup, False) == -1)
fprintf(stderr,"create_obj_action: couldn't show object\n");
else
{
group_objects(newgroup, member_list, member_count);
}
new_list[i] = newgroup;
}
abobj_set_undo(new_list, undo_rec->count, undo_group, AB_UNDO_GROUP);
if (new_list)
free(new_list);
}
void
set_new_group_size(
ABObj obj
)
{
ABObj oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
int member_count;
ABObj *member_list;
int width, height;
XRectangle rect;
create_member_list(oobj, &member_list, &member_count);
/*
* Reset groups width and height. for rows, the new height is that of
* the tallest member, the new width is the width of the
* rect occupied by all of the members. For colums, the new
* width is that of the widest member, the new height is the
* height of the rect occupied by all of the members.
*/
abobj_get_rect_for_objects(member_list, member_count, &rect);
abobj_get_greatest_size(member_list, member_count,
&width, &height,
(ABObj *) NULL, (ABObj *) NULL);
if (obj_get_group_type(oobj) == AB_GROUP_ROWS)
{
abobj_set_pixel_width(obj, rect.width, 0);
abobj_set_pixel_height(obj, height, 0);
}
else if (obj_get_group_type(oobj) == AB_GROUP_ROWS)
{
abobj_set_pixel_width(obj, width, 0);
abobj_set_pixel_height(obj, rect.height, 0);
}
util_free(member_list);
}
void
abobj_layout_group(
ABObj obj,
BOOL init
)
{
ABObj pobj;
ABObj child;
AB_GROUP_TYPE type;
int i;
int child_old_x, child_old_y;
int group_new_x, group_new_y;
XRectangle rect;
if (!obj_has_flag(obj, XmConfiguredFlag))
return;
pobj = objxm_comp_get_subobj(obj, AB_CFG_PARENT_OBJ);
if (obj_get_num_children(pobj) <= 0)
return;
type = obj_get_group_type(obj);
/*
* Save leftmost objects real x and y to determine group's new
* x and y.
*/
child = obj_get_child(pobj, 0);
child_old_x = obj_get_x(child);
child_old_y = obj_get_y(child);
abobj_clear_layout(pobj, True, (type != AB_GROUP_IGNORE));
/*
* CLEANUP:
* The code to do group layout here should be the code
* used in dtb_utils.c to make sure the behaviour is the
* same. Unfortunately, at this time, this is a big risky
* change. So, some behavioral differences will exist.
* This needs to be fixed in the future.
*/
switch (type)
{
case AB_GROUP_IGNORE:
break;
case AB_GROUP_ROWS:
obj_set_num_rows(obj, 1);
obj_set_num_columns(obj, 0);
group_align_rows(obj, init);
group_align_left(obj);
break;
case AB_GROUP_COLUMNS:
obj_set_num_rows(obj, 0);
obj_set_num_columns(obj, 1);
group_align_cols(obj, init);
group_align_tops(obj);
break;
case AB_GROUP_ROWSCOLUMNS:
group_align_rows(obj, init);
group_align_cols(obj, init);
break;
}
/*
group_align_rows(obj);
group_align_cols(obj);
*/
/*
* Re-instantiate all of the children and then the group.
*/
for (i = 0; i < obj_get_num_children(pobj); i++)
{
abobj_instantiate_changes(obj_get_child(pobj, i));
}
/*
* Set the childrens x,y's so obj is update with reality.
*/
for (i = 0; i < obj_get_num_children(pobj); i++)
{
child = obj_get_child(pobj, i);
x_get_widget_rect(objxm_get_widget(child), &rect);
obj_set_x(child, rect.x);
obj_set_y(child, rect.y);
}
/*
* Place the group so that the topmost/leftmost child remains
* in the same place.
group_new_x = obj_get_x(pobj) +
(child_old_x - obj_get_x(obj_get_child(pobj, 0)));
group_new_y = obj_get_y(pobj) +
(child_old_y - obj_get_y(obj_get_child(pobj, 0)));
abobj_set_xy(pobj, group_new_x, group_new_y);
*/
abobj_instantiate_changes(pobj);
/*
* For some reason, width and height need to be set on the
* group.
pobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
x_get_widget_rect(objxm_get_widget(pobj), &rect);
*/
/*
obj_set_width(pobj, rect.width);
obj_set_height(pobj, rect.height);
*/
}
void
abobj_register_group_expose_handler(
ABObj obj
)
{
AB_GROUP_TYPE type;
AB_ALIGNMENT row_alignment,
col_alignment;
Widget group_widget;
Boolean register_expose = False;
if (!obj || !obj_is_group(obj))
return;
group_widget = objxm_get_widget(obj);
if (!group_widget)
return;
type = obj_get_group_type(obj);
switch (type)
{
case AB_GROUP_IGNORE:
break;
case AB_GROUP_ROWS:
row_alignment = obj_get_row_align(obj);
if (row_alignment == AB_ALIGN_HCENTER)
register_expose = True;
break;
case AB_GROUP_COLUMNS:
col_alignment = obj_get_col_align(obj);
if ((col_alignment == AB_ALIGN_VCENTER) ||
(col_alignment == AB_ALIGN_LABELS))
register_expose = True;
break;
case AB_GROUP_ROWSCOLUMNS:
row_alignment = obj_get_row_align(obj);
col_alignment = obj_get_col_align(obj);
if ((row_alignment == AB_ALIGN_HCENTER) ||
(col_alignment == AB_ALIGN_LEFT) ||
(col_alignment == AB_ALIGN_LABELS))
register_expose = True;
break;
}
if (register_expose)
{
XtAddEventHandler(group_widget,
ExposureMask, False,
group_expose_handler, (XtPointer)obj);
}
}
/*
* Group expose handler.
*
* Some group objects depend on it's members' sizes for their layout.
* Unfortunately, some group members have invalid sizes prior to
* XtRealize(), so the group layout has to be recalculated after the
* group is realized or exposed in this case, since there is no realize
* callback.
*/
static void
group_expose_handler(
Widget widget,
XtPointer client_data,
XEvent *event,
Boolean *cont_dispatch
)
{
ABObj obj = (ABObj)client_data;
WidgetList children_list;
int i,
num_children = 0;
Boolean relayout_all = False,
register_align_handler = False;
if (event->type != Expose)
return;
if (!obj || !obj_is_group(obj))
return;
/*
* Get children list
*/
XtVaGetValues(widget,
XmNnumChildren, &num_children,
XmNchildren, &children_list,
NULL);
if (num_children <= 0)
return;
XtRemoveEventHandler(widget,
ExposureMask, False,
group_expose_handler, (XtPointer)client_data);
/*
* Turn off 'save needed' temporarily
*/
abobj_disable_save_needed();
abobj_layout_group(obj, FALSE);
abobj_enable_save_needed();
}
static void
group_align_tops(
ABObj obj
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
int num_children = obj_get_num_children(oobj),
num_columns,
num_rows,
cell_height,
cell_width,
i,
j;
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
get_row_col(obj, &num_rows, &num_columns);
for (j = 0; j < num_rows; j++)
{
for (i = 0; i < num_columns; i++)
{
child = get_child(obj, i, j);
if (!child)
continue;
if ((i == 0) && (j == 0))
{
attach.type = AB_ATTACH_POINT;
attach.value = (void *)0;
attach.offset = 0;
abobj_set_attachment(child, AB_CP_NORTH, &attach);
continue;
}
if (i == 0)
{
previous_child = get_child(obj, 0, j-1);
if (previous_child)
{
int offset = obj_get_voffset(obj);
AB_GROUP_TYPE type = obj_get_group_type(obj);
if (type == AB_GROUP_ROWSCOLUMNS)
offset +=
(cell_height - abobj_get_actual_height(previous_child));
attach.type = AB_ATTACH_OBJ;
attach.value = (void *)previous_child;
attach.offset = offset;
abobj_set_attachment(child, AB_CP_NORTH, &attach);
}
continue;
}
previous_child = get_child(obj, i-1, j);
if (previous_child)
{
attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
attach.value = (void *)previous_child;
attach.offset = 0;
abobj_set_attachment(child, AB_CP_NORTH, &attach);
}
}
}
}
static void
group_align_hcenters(
ABObj obj,
BOOL init
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
AB_GROUP_TYPE type = obj_get_group_type(obj);
int num_children = obj_get_num_children(oobj),
num_columns,
num_rows,
cell_width,
cell_height,
group_width,
group_height,
offset,
gridline,
i,
j;
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
get_row_col(obj, &num_rows, &num_columns);
offset = obj_get_voffset(obj);
if (type == AB_GROUP_ROWSCOLUMNS)
{
group_height = (num_rows * cell_height) + ((num_rows-1) * offset);
abobj_set_pixel_width(obj, group_height, 0);
abobj_instantiate_changes(obj);
}
for (j = 0; j < num_rows; j++)
{
if (type == AB_GROUP_ROWSCOLUMNS)
gridline = (((j * (cell_height + offset)) + (cell_height/2)) * 100)/group_height;
else
gridline = 50;
for (i = 0; i < num_columns; i++)
{
child = get_child(obj, i, j);
if (!child)
continue;
if (init)
{
int init_offset = 0;
Widget child_widget = objxm_get_widget(child);
if (child_widget &&
!XtIsSubclass(child_widget, compositeWidgetClass))
{
int height = abobj_get_actual_height(child);
init_offset = (cell_height - height)/2;
if (type == AB_GROUP_ROWSCOLUMNS)
init_offset += (j * (cell_height + offset));
}
attach.type = AB_ATTACH_POINT;
attach.value = (void *)0;
attach.offset = init_offset;
}
else
{
int height = abobj_get_actual_height(child);
attach.type = AB_ATTACH_GRIDLINE;
attach.value = (void *)(intptr_t) gridline;
attach.offset = -(height/2);
}
abobj_set_attachment(child, AB_CP_NORTH, &attach);
}
}
if (type == AB_GROUP_ROWSCOLUMNS)
{
abobj_set_pixel_width(obj, -1, 0);
abobj_instantiate_changes(obj);
}
}
static void
group_align_horiz_same_size(
ABObj obj
)
{
ABObj sibling, previous_sibling;
ABObj oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
int num_children = obj_get_num_children(oobj);
int i;
sibling = obj_get_child(oobj, num_children - 1);
/*
* Set up childrens attachments from right to left.
* All objects North and South attachments are to
* the form.
*/
for (i = num_children - 2; i >= 0; i--)
{
previous_sibling = obj_get_child(oobj, i);
obj_set_attachment(sibling,
AB_CP_NORTH,
AB_ATTACH_OBJ,
(void *) oobj,
0);
obj_set_attachment(sibling,
AB_CP_WEST,
AB_ATTACH_OBJ,
(void *) previous_sibling,
obj_get_hoffset(oobj));
obj_set_attachment(sibling,
AB_CP_SOUTH,
AB_ATTACH_OBJ,
(void *) oobj,
0);
objxm_obj_set_attachment_args(sibling, OBJXM_CONFIG_BUILD);
obj_clear_flag(sibling, BeingDestroyedFlag);
sibling = previous_sibling;
}
obj_set_attachment(sibling,
AB_CP_NORTH,
AB_ATTACH_OBJ,
(void *) oobj,
0);
obj_set_attachment(sibling,
AB_CP_WEST,
AB_ATTACH_OBJ,
(void *) oobj,
0);
obj_set_attachment(sibling,
AB_CP_SOUTH,
AB_ATTACH_OBJ,
(void *) oobj,
0);
objxm_obj_set_attachment_args(sibling, OBJXM_CONFIG_BUILD);
obj_clear_flag(sibling, BeingDestroyedFlag);
}
static void
group_align_bottoms(
ABObj obj
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
AB_GROUP_TYPE type = obj_get_group_type(obj);
int num_children = obj_get_num_children(oobj),
num_columns,
num_rows,
cell_height,
cell_width,
offset,
i,
j;
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
get_row_col(obj, &num_rows, &num_columns);
for (j = 0; j < num_rows; j++)
{
for (i = 0; i < num_columns; i++)
{
child = get_child(obj, i, j);
if (!child)
continue;
if ((i == 0) && (j == 0))
{
offset = (cell_height - abobj_get_actual_height(child));
attach.type = AB_ATTACH_POINT;
attach.value = (void *)0;
attach.offset = offset;
abobj_set_attachment(child, AB_CP_NORTH, &attach);
continue;
}
if (i == 0)
{
previous_child = get_child(obj, 0, j-1);
if (previous_child)
{
offset = obj_get_voffset(obj);
if (type == AB_GROUP_ROWSCOLUMNS)
offset +=
(cell_height - abobj_get_actual_height(child));
attach.type = AB_ATTACH_OBJ;
attach.value = (void *)previous_child;
attach.offset = offset;
abobj_set_attachment(child, AB_CP_NORTH, &attach);
}
continue;
}
previous_child = get_child(obj, i-1, j);
if (child && previous_child)
{
attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
attach.value = (void *)previous_child;
attach.offset = 0;
abobj_set_attachment(child, AB_CP_SOUTH, &attach);
}
}
}
}
static void
group_align_left(
ABObj obj
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
int num_children = obj_get_num_children(oobj),
num_columns,
num_rows,
cell_width,
cell_height,
i,
j;
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
get_row_col(obj, &num_rows, &num_columns);
for (j = 0; j < num_rows; j++)
{
for (i = 0; i < num_columns; i++)
{
child = get_child(obj, i, j);
if (!child)
continue;
if ((i == 0) && (j == 0))
{
attach.type = AB_ATTACH_POINT;
attach.value = (void *)0;
attach.offset = 0;
abobj_set_attachment(child, AB_CP_WEST, &attach);
continue;
}
if (j == 0)
{
int offset = obj_get_hoffset(obj);
AB_GROUP_TYPE type = obj_get_group_type(obj);
previous_child = get_child(obj, i-1, j);
if (!previous_child)
continue;
if (type == AB_GROUP_ROWSCOLUMNS)
offset +=
(cell_width - abobj_get_actual_width(previous_child));
attach.type = AB_ATTACH_OBJ;
attach.value = (void *)previous_child;
attach.offset = offset;
abobj_set_attachment(child, AB_CP_WEST, &attach);
continue;
}
previous_child = get_child(obj, i, j-1);
if (previous_child)
{
attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
attach.value = (void *)previous_child;
attach.offset = 0;
abobj_set_attachment(child, AB_CP_WEST, &attach);
}
}
}
}
static void
group_align_labels(
ABObj obj
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ),
*one_col = NULL,
*child_list,
previous_ref_obj = NULL;
int num_children = 0,
num_columns,
num_rows,
cell_width,
cell_height,
offset,
max_label_width = 0,
max_value_width = 0,
i,
j;
if (oobj)
num_children = obj_get_num_children(oobj);
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
create_member_list(oobj, &child_list, &num_children);
get_widest_label_obj(child_list, num_children, &child, &max_label_width);
get_widest_value_obj(child_list, num_children, &child, &max_value_width);
util_free(child_list);
if (cell_width < max_label_width + max_value_width)
cell_width = max_label_width + max_value_width;
get_row_col(obj, &num_rows, &num_columns);
if (num_rows > 0)
one_col = (ABObj *)util_malloc(num_rows * sizeof(ABObj));
for (i = 0; i < num_columns; i++)
{
ABObj ref_obj;
int ref_width;
for (j = 0; j < num_rows; j++)
one_col[j] = get_child(obj, i, j);
get_widest_label_obj(one_col, num_rows, &ref_obj, &ref_width);
if (!ref_obj)
continue;
if (previous_ref_obj)
{
offset = (i * (obj_get_hoffset(obj) + cell_width));
attach.offset = offset;
}
else
attach.offset = 0;
attach.type = AB_ATTACH_POINT;
attach.value = (void *)NULL;
abobj_set_attachment(ref_obj, AB_CP_WEST, &attach);
for (j = 0; j < num_rows; j++)
{
child = get_child(obj, i, j);
if (!child || (child == ref_obj))
continue;
offset = (i * (obj_get_hoffset(obj) + cell_width));
offset += ref_width - abobj_get_label_width(child);
attach.type = AB_ATTACH_POINT;
attach.value = (void *)NULL;
/*
attach.offset = ref_x - abobj_get_label_width(child);
*/
attach.offset = offset;
abobj_set_attachment(child, AB_CP_WEST, &attach);
}
previous_ref_obj = ref_obj;
}
}
static void
group_align_vcenters(
ABObj obj,
BOOL init
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
AB_GROUP_TYPE type = obj_get_group_type(obj);
int num_children = obj_get_num_children(oobj),
num_columns,
num_rows,
cell_width,
cell_height,
group_width,
group_height,
offset,
gridline,
i,
j;
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
get_row_col(obj, &num_rows, &num_columns);
offset = obj_get_hoffset(obj);
if (type == AB_GROUP_ROWSCOLUMNS)
{
group_width = (num_columns * cell_width) + ((num_columns-1) * offset);
abobj_set_pixel_width(obj, group_width, 0);
abobj_instantiate_changes(obj);
}
for (i = 0; i < num_columns; i++)
{
if (type == AB_GROUP_ROWSCOLUMNS)
gridline = (((i * (cell_width + offset)) + (cell_width/2)) * 100)/group_width;
else
gridline = 50;
for (j = 0; j < num_rows; j++)
{
child = get_child(obj, i, j);
if (!child)
continue;
if (init)
{
int init_offset = 0;
Widget child_widget = objxm_get_widget(child);
if (child_widget && !XtIsSubclass(child_widget, compositeWidgetClass))
{
int width = abobj_get_actual_width(child);
init_offset = (cell_width - width)/2;
if (type == AB_GROUP_ROWSCOLUMNS)
init_offset += (i * (cell_width + offset));
}
attach.type = AB_ATTACH_POINT;
attach.value = (void *)0;
attach.offset = init_offset;
}
else
{
int width = abobj_get_actual_width(child);
attach.type = AB_ATTACH_GRIDLINE;
attach.value = (void *)(intptr_t) gridline;
attach.offset = -(width/2);
}
abobj_set_attachment(child, AB_CP_WEST, &attach);
}
}
if (type == AB_GROUP_ROWSCOLUMNS)
{
abobj_set_pixel_width(obj, -1, 0);
abobj_instantiate_changes(obj);
}
}
static void
group_align_right(
ABObj obj
)
{
ABAttachment attach;
ABObj child,
previous_child,
oobj = objxm_comp_get_subobj(obj, AB_CFG_OBJECT_OBJ);
AB_GROUP_TYPE type = obj_get_group_type(obj);
int num_children = obj_get_num_children(oobj),
num_columns,
num_rows,
cell_width,
cell_height,
offset,
i,
j;
if (num_children <= 0)
return;
get_cell_size(obj, &cell_width, &cell_height);
get_row_col(obj, &num_rows, &num_columns);
for (j = 0; j < num_rows; j++)
{
for (i = 0; i < num_columns; i++)
{
child = get_child(obj, i, j);
if (!child)
continue;
if ((i == 0) && (j == 0))
{
offset = (cell_width - abobj_get_actual_width(child));
attach.type = AB_ATTACH_POINT;
attach.value = (void *)0;
attach.offset = offset;
abobj_set_attachment(child, AB_CP_WEST, &attach);
continue;
}
if (j == 0)
{
previous_child = get_child(obj, i-1, j);
if (!previous_child)
continue;
offset = obj_get_hoffset(obj);
if (type == AB_GROUP_ROWSCOLUMNS)
offset +=
(cell_width - abobj_get_actual_width(child));
attach.type = AB_ATTACH_OBJ;
attach.value = (void *)previous_child;
attach.offset = offset;
abobj_set_attachment(child, AB_CP_WEST, &attach);
continue;
}
previous_child = get_child(obj, i, j-1);
if (previous_child)
{
attach.type = AB_ATTACH_ALIGN_OBJ_EDGE;
attach.value = (void *)previous_child;
attach.offset = 0;
abobj_set_attachment(child, AB_CP_EAST, &attach);
}
}
}
}
static void
create_member_list(
ABObj cobj,
ABObj **member_list,
int *member_count
)
{
AB_TRAVERSAL trav;
int member_index;
ABObj member;
*member_count = trav_count(cobj,
AB_TRAV_SALIENT_CHILDREN | AB_TRAV_MOD_SAFE);
*member_list = (ABObj *)malloc(*member_count * sizeof(ABObj));
/*
* Create list of members.
*/
for (trav_open(&trav, cobj, AB_TRAV_SALIENT_CHILDREN |
AB_TRAV_MOD_SAFE), member_index = 0;
(member = trav_next(&trav)) != NULL; ++member_index)
{
(*member_list)[member_index] = member;
}
trav_close(&trav);
}
static ABObj
get_child(
ABObj group,
int x_pos,
int y_pos
)
{
AB_GROUP_TYPE type;
ABObj ret_child = NULL,
oobj;
int num_children,
num_rows,
num_columns,
i = -1;
if (!group || !obj_is_group(group) ||
(x_pos < 0) || (y_pos < 0))
return (NULL);
type = obj_get_group_type(group);
num_rows = obj_get_num_rows(group);
num_columns = obj_get_num_columns(group);
oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
num_children = obj_get_num_children(oobj);
switch (type)
{
case AB_GROUP_IGNORE:
break;
case AB_GROUP_ROWS:
/*
* num_rows = 1
* y_pos is ignored
*/
i = x_pos;
break;
case AB_GROUP_COLUMNS:
/*
* num_columns = 1
* x_pos is ignored
*/
i = y_pos;
break;
case AB_GROUP_ROWSCOLUMNS:
if (!num_rows && !num_columns)
break;
if (num_rows > 0)
{
/*
* ROWFIRST
*/
if (y_pos < num_rows)
i = (x_pos * num_rows) + y_pos;
}
else
{
/*
* COLFIRST
*/
if (x_pos < num_columns)
i = x_pos + (y_pos * num_columns);
}
break;
default:
break;
}
if ((i >= 0) && (i < num_children))
{
ret_child = obj_get_child(oobj, i);
}
return (ret_child);
}
static void
get_cell_size(
ABObj group,
int *cell_width,
int *cell_height
)
{
AB_GROUP_TYPE type;
if (!group)
{
*cell_width = *cell_height = -1;
return;
}
type = obj_get_group_type(group);
/*
if (type == AB_GROUP_ROWSCOLUMNS)
*/
if (1)
{
ABObj *member_list,
oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
int member_count;
create_member_list(oobj, &member_list, &member_count);
abobj_get_greatest_size(member_list, member_count,
cell_width, cell_height,
(ABObj *) NULL, (ABObj *) NULL);
util_free(member_list);
}
else
*cell_width = *cell_height = -1;
}
static void
get_row_col(
ABObj group,
int *rows,
int *cols
)
{
ABObj oobj;
int num_rows,
num_cols,
num_children;
if (!group)
{
*rows = *cols = -1;
return;
}
oobj = objxm_comp_get_subobj(group, AB_CFG_OBJECT_OBJ);
num_rows = obj_get_num_rows(group);
num_cols = obj_get_num_columns(group);
num_children = obj_get_num_children(oobj);
if ((num_rows <= 0) && (num_cols <= 0))
{
*rows = *cols = -1;
return;
}
if (num_cols <= 0)
num_cols = (num_children/num_rows) + ((num_children % num_rows) ? 1 : 0);
if (num_rows <= 0)
num_rows = (num_children/num_cols) + ((num_children % num_cols) ? 1 : 0);
*rows = num_rows;
*cols = num_cols;
}
static void
group_align_rows(
ABObj obj,
BOOL init
)
{
if (!obj || !obj_is_group(obj))
return;
switch (obj_get_row_align(obj))
{
case AB_ALIGN_TOP:
group_align_tops(obj);
break;
case AB_ALIGN_HCENTER:
group_align_hcenters(obj, init);
break;
case AB_ALIGN_BOTTOM:
group_align_bottoms(obj);
break;
default:
/*
* Default to AB_ALIGN_TOP
*/
group_align_tops(obj);
break;
}
}
static void
group_align_cols(
ABObj obj,
BOOL init
)
{
if (!obj || !obj_is_group(obj))
return;
switch (obj_get_col_align(obj))
{
case AB_ALIGN_LEFT:
group_align_left(obj);
break;
case AB_ALIGN_LABELS:
group_align_labels(obj);
break;
case AB_ALIGN_VCENTER:
group_align_vcenters(obj, init);
break;
case AB_ALIGN_RIGHT:
group_align_right(obj);
break;
default:
/*
* Default to AB_ALIGN_LEFT
*/
group_align_left(obj);
break;
}
}
static void
get_widest_label_obj(
ABObj *list,
int count,
ABObj *widest_label,
int *label_width
)
{
int i,
tmp_width,
cur_width = 0;
ABObj widest = NULL;
if (!list || !widest_label)
return;
for (i = 0; i < count; ++i)
{
if (list[i])
{
tmp_width = abobj_get_label_width(list[i]);
if (tmp_width > cur_width)
{
cur_width = tmp_width;
widest = list[i];
}
}
}
*widest_label = widest;
if (label_width)
*label_width = cur_width;
}
static void
get_widest_value_obj(
ABObj *list,
int count,
ABObj *widest_value,
int *value_width
)
{
int i,
tmp_width,
cur_width = 0;
ABObj widest = NULL;
if (!list || !widest_value)
return;
for (i = 0; i < count; ++i)
{
if (list[i])
{
int label_width,
obj_width;
label_width = abobj_get_label_width(list[i]);
obj_width = abobj_get_actual_width(list[i]);
tmp_width = obj_width - label_width;
if (tmp_width > cur_width)
{
cur_width = tmp_width;
widest = list[i];
}
}
}
*widest_value = widest;
if (value_width)
*value_width = cur_width;
}