/* * 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: prop.c /main/5 1996/08/08 17:57:58 mustafa $ * * @(#)prop.c 1.89 26 Feb 1994 * * 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. * */ /* ***************************************************************** * prop.c - Implements all common property sheet functionality * ***************************************************************** */ #ifndef _POSIX_SOURCE #define _POSIX_SOURCE 1 #endif #include #include #include #include
#include #include #include #include #include #include #include #include #include #include #include #include #include #include "dtb_utils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dtbuilder.h" #include "revolv_ui.h" #if defined(CSRG_BASED) #define MAXINT INT_MAX #endif char *LabelForString = NULL; char *LabelForGraphic = NULL; char *NoneItem = NULL; char *XFieldStr = NULL; char *YFieldStr = NULL; char *WFieldStr = NULL; char *HFieldStr = NULL; char *OffsetFieldStr = NULL; char *PercentageFieldStr = NULL; char *RowColFieldStr = NULL; char *VertSpacingFieldStr = NULL; char *HorizSpacingFieldStr = NULL; static char *menu_strs[4]; static char *menu_names[] = {"none_item", "new_menu_item", "menus_item", "edit_item"}; static const char *Name_ok_test="_"; typedef struct _PROP_STATE_INFO { PalItemInfo *palitem; Widget objlist; ABObj loaded_obj; } PropStateInfo; /************************************************************************* ** ** ** Private Function Declarations ** ** ** *************************************************************************/ /* Revolving Dialog Functions */ static void revolv_dialog_init( Widget parent ); static void revolv_objectspane_init( DtbRevolvPropDialogInfo cgen ); static void revolv_basicframe_init( DtbRevolvPropDialogInfo cgen ); static PalItemInfo * revolv_set_prop_type( PalItemInfo* palitem, ABObj loadobj ); static void revolv_change_prop_frame( PalItemInfo *palitem ); static PalItemInfo * revolv_invoke_props( PalItemInfo *palitem, ABObj loadobj ); /* Fixed Dialog Functions */ static void fixed_invoke_props( PalItemInfo *palitem ); /* General Prop Manipulation Functions */ static int apply_props( AB_PROP_TYPE ptype, Widget dialog ); static int apply_prop_changes( AB_PROP_TYPE ptype, ABObj obj, PalItemInfo *palitem ); static DTB_MODAL_ANSWER handle_auto_apply( AB_PROP_TYPE ptype, PropStateInfo *pstate, PalItemInfo *new_palitem, ABObj new_obj, PalItemInfo **result ); static PropStateInfo * get_prop_state_info( Widget widget ); static void init_prop_state_info( Widget dialog, PalItemInfo *palitem, Widget objlist, ABObj loaded_obj ); static void load_props( AB_PROP_TYPE ptype, PropStateInfo *pstate, ABObj obj ); static void create_obj_option_item( PropObjOptionsSetting pos, Widget item, ABObj obj ); /* Object List Manipulation Functions */ static int objlist_delete_obj( AB_PROP_TYPE type, PalItemInfo *palitem, ObjEvDestroyInfo info ); static void objlist_ensure_selection( Widget objlist ); static void objlist_load( AB_PROP_TYPE type, PropStateInfo *pstate ); static int objlist_rename_obj( AB_PROP_TYPE type, PalItemInfo *palitem, ObjEvAttChangeInfo info ); static int objlist_show_or_hide_obj( AB_PROP_TYPE type, PalItemInfo *palitem, ObjEvUpdateInfo info ); static BOOL objlist_test_func( ABObj test_obj ); /* * Object-Callbacks */ static int obj_renamedOCB( ObjEvAttChangeInfo info ); static int obj_shown_or_hiddenOCB( ObjEvUpdateInfo info ); static int obj_geom_changedOCB( ObjEvAttChangeInfo info ); static int obj_destroyedOCB( ObjEvDestroyInfo info ); /* * Xt-Callbacks */ /* General Prop Callbacks */ static void apply_propsCB( Widget w, XtPointer clientdata, XtPointer calldata ); static void cancel_propsCB( Widget w, XtPointer clientdata, XtPointer calldata ); static void change_objecttypeCB( Widget w, XtPointer clientdata, XtPointer calldata ); static void close_propsCB( Widget w, XtPointer clientdata, XtPointer calldata ); static void invoke_attach_editorCB( Widget w, XtPointer cldata, XtPointer calldata ); static void invoke_connectionsCB( Widget w, XtPointer cldata, XtPointer calldata ); static void invoke_help_editorCB( Widget w, XtPointer cldata, XtPointer calldata ); static void objlist_selectCB( Widget widget, XtPointer client_data, XmListCallbackStruct *listdata ); static void ok_propsCB( Widget w, XtPointer clientdata, XtPointer calldata ); static void reset_propsCB( Widget w, XtPointer clientdata, XtPointer calldata ); static void tearoff_propsCB( Widget w, XtPointer clientdata, XtPointer calldata ); /* Color Field Callbacks */ static void color_chooserCB( Widget widget, XtPointer clientdata, XtPointer calldata ); static void color_noneCB( Widget widget, XtPointer clientdata, XtPointer calldata ); /* Menu Name Setting Callbacks */ static void menu_newCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void menu_editCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void menu_edit_set_stateCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void menulist_buildCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void menulist_destroyCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void menuname_clearCB( Widget widget, XtPointer clientdata, XtPointer calldata ); static void menuname_setCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void menu_field_chgCB( Widget widget, XtPointer client_data, XtPointer call_data ); static void obj_options_buildCB( Widget widget, XtPointer client_data, XtPointer call_data ); /* * Misc Functions */ static void find_submenu_owners( ABObj submenu, ABObj *menulist, int menu_count, ABObj *i_menulist, int *i_count_ptr ); static BOOL is_submenu_of( STRING submenu_name, ABObj menu ); static BOOL menu_in_list( ABObj *menulist, int menu_count, ABObj target_menu ); static void strings_init( ); /************************************************************************* ** ** ** Data Declarations ** ** ** *************************************************************************/ extern PalItemInfo* palette_item[]; extern int palette_item_cnt; extern PalItemInfo *ab_menu_palitem; extern PalItemInfo *ab_group_palitem; static PalItemInfo *cur_list_palitem = NULL; static Widget revolv_current_frame = NULL; static Widget revolv_optionmenu = NULL; static BOOL apply_in_progress = False; static char Buf[512]; /************************************************************************* ** ** ** Function Definitions ** ** ** *************************************************************************/ /* * Initialize Props: * Create Revolving Prop dialog * Add callbacks for object rename & destroy */ void prop_init( Widget toplevel ) { strings_init(); revolv_dialog_init(toplevel); obj_add_rename_callback(obj_renamedOCB, "PROPS"); obj_add_update_callback(obj_shown_or_hiddenOCB, "PROPS"); obj_add_geometry_change_callback(obj_geom_changedOCB, "PROPS"); obj_add_destroy_callback(obj_destroyedOCB, "PROPS"); } /* * Popup the Revolving Prop dialog. * If an object is currently selected, Set the * corresponding revolving prop-type and Load the object */ void prop_show_dialog( Widget widget, XtPointer client_data, XtPointer call_data ) { ABSelectedRec sel; PalItemInfo *palitem = NULL; PropStateInfo *pstate; ab_set_busy_cursor(TRUE); abobj_get_selected(proj_get_project(), FALSE, FALSE, &sel); if (sel.count > 0) { palitem = pal_get_item_info(sel.list[0]); util_free(sel.list); } /* If no objects selected, set to First type */ if (palitem == NULL) palitem = palette_item[0]; revolv_invoke_props(palitem, NULL); pstate = get_prop_state_info(AB_rev_prop_dialog); objlist_ensure_selection(pstate->objlist); ab_set_busy_cursor(FALSE); } /* * Popup the Fixed Prop dialog for the specified * Palette Item type. */ void prop_show_fixed( PalItemInfo *palitem ) { PropStateInfo *pstate; ab_set_busy_cursor(TRUE); fixed_invoke_props(palitem); pstate = get_prop_state_info(palitem->fix_prop_dialog); objlist_ensure_selection(pstate->objlist); ab_set_busy_cursor(FALSE); } /* * Popup the Fixed Prop dialog for Menus */ void prop_show_menu_props( Widget w, XtPointer client_data, XtPointer calldata ) { prop_show_fixed(ab_menu_palitem); } /* * Popup the Fixed Group dialog for menus. */ void prop_show_group_props( Widget w, XtPointer client_data, XtPointer calldata ) { prop_show_fixed(ab_group_palitem); } /* * Load an object into the Prop dialog of the * specified prop type (Revolving or Fixed). */ void prop_load_obj( ABObj obj, AB_PROP_TYPE ptype ) { PalItemInfo *palitem; PalItemInfo *viz_palitem; Widget dialog = NULL; PropStateInfo *pstate; STRING modname = NULL; if (obj_is_module(obj) || obj_is_project(obj)) return; ab_set_busy_cursor(TRUE); if (obj_is_item(obj)) obj = obj_get_parent(obj); obj = obj_get_root(obj); if ((viz_palitem = palitem = pal_get_item_info(obj)) != NULL) { if (ptype == AB_PROP_REVOLVING) { viz_palitem = revolv_invoke_props(palitem, obj); dialog = AB_rev_prop_dialog; } else /* AB_PROP_FIXED */ { fixed_invoke_props(palitem); dialog = palitem->fix_prop_dialog; } pstate = get_prop_state_info(dialog); modname = abobj_get_moduled_name(obj); } else util_dprintf(1,"prop_load_obj: %s : could not get Palette info\n", util_strsafe(obj_get_name(obj))); ab_set_busy_cursor(FALSE); if (dialog != NULL && modname != NULL && viz_palitem == palitem) { ui_list_select_item(pstate->objlist, modname, TRUE); util_free(modname); } } void prop_fixed_dialog_init( PalItemInfo *palitem, Widget dialog, Widget objlist ) { Widget shell = XtParent(dialog); init_prop_state_info(dialog, palitem, objlist, NULL); /* The initial position of a Fixed Prop dialog is dependent on * how it is invoked and whether the Revolving Prop editor is up, * so don't specify an initial position relative to the palette. */ ab_register_window(dialog, AB_WIN_DIALOG, WindowHidden, NULL, AB_WPOS_UNSPECIFIED, close_propsCB, (XtPointer)AB_PROP_FIXED); /* Store current-object in List (init to NULL) */ XtVaSetValues(objlist, XmNselectionPolicy, XmBROWSE_SELECT, XmNuserData, NULL, NULL); XtAddCallback(objlist, XmNbrowseSelectionCallback, (XtCallbackProc)objlist_selectCB, (XtPointer)AB_PROP_FIXED); } void prop_activate_panel_init( AB_PROP_TYPE type, PalItemInfo *palitem, Widget ok_button, Widget apply_button, Widget reset_button, Widget cancel_button, Widget help_button ) { Widget dialog; /* Ensure "Apply" is default button */ dialog = ui_get_ancestor_dialog(apply_button); XtVaSetValues(dialog, XmNdefaultButton, apply_button, NULL); XtVaSetValues(apply_button, XmNshowAsDefault, True, XmNdefaultButtonShadowThickness, 1, NULL); XtVaSetValues(ok_button, XmNdefaultButtonShadowThickness, 1, NULL); XtVaSetValues(reset_button, XmNdefaultButtonShadowThickness, 1, NULL); XtVaSetValues(cancel_button, XmNdefaultButtonShadowThickness, 1, NULL); if (help_button != NULL) XtVaSetValues(help_button, XmNdefaultButtonShadowThickness, 1, NULL); XtAddCallback(apply_button, XmNactivateCallback, apply_propsCB, (XtPointer)type); XtAddCallback(reset_button, XmNactivateCallback, reset_propsCB, (XtPointer)type); XtAddCallback(ok_button, XmNactivateCallback, ok_propsCB, (XtPointer)type); XtAddCallback(cancel_button,XmNactivateCallback, cancel_propsCB,(XtPointer)type); } void prop_editors_panel_init( AB_PROP_TYPE type, PalItemInfo *palitem, Widget attach_ed_button, Widget conn_ed_button, Widget help_ed_button ) { if (attach_ed_button) { XtAddCallback(attach_ed_button, XmNactivateCallback, invoke_attach_editorCB, (XtPointer)type); } if (conn_ed_button) { XtAddCallback(conn_ed_button, XmNactivateCallback, invoke_connectionsCB, (XtPointer)type); } if (help_ed_button) { XtAddCallback(help_ed_button, XmNactivateCallback, invoke_help_editorCB, (XtPointer)type); } } void prop_checkbox_init( PropCheckboxSetting pcs, Widget label, Widget checkbox, int num_items, WidgetList items, XtArgVal *item_keys, Widget changebar ) { int i; /* Store Widget-IDs */ pcs->label = label; pcs->checkbox = checkbox; pcs->changebar = changebar; propP_changebar_init(changebar, checkbox); for (i=0; i < num_items; i++) { XtVaSetValues(items[i], XmNuserData, item_keys[i], NULL); XtAddCallback(items[i], XmNvalueChangedCallback, propP_setting_chgCB, (XtPointer)changebar); } } int prop_checkbox_set_value( PropCheckboxSetting pcs, int itemkey, BOOL value, BOOL trip_changebar ) { int num_children = 0; WidgetList children = NULL; XtArgVal childkey; int i; XtVaGetValues(pcs->checkbox, XtNnumChildren, &num_children, XtNchildren, &children, NULL); for (i=0; i < num_children; i++) { XtVaGetValues(children[i], XmNuserData, &childkey, NULL); if (childkey == itemkey) /* Found it */ { XmToggleButtonSetState(children[i], value, trip_changebar? TRUE : FALSE); return OK; } } /* Item not found in checkbox */ util_dprintf(1,"prop_checkbox_set_value: invalid item key\n"); return ERROR; } BOOL prop_checkbox_get_value( PropCheckboxSetting pcs, int itemkey ) { int num_children = 0; WidgetList children = NULL; XtArgVal childkey; int i; XtVaGetValues(pcs->checkbox, XtNnumChildren, &num_children, XtNchildren, &children, NULL); for (i=0; i < num_children; i++) { XtVaGetValues(children[i], XmNuserData, &childkey, NULL); if (childkey == itemkey) /* Found it */ return((BOOL)XmToggleButtonGetState(children[i])); } /* itemkey was not found */ util_dprintf(1, "prop_checkbox_get_value: invalid item key\n"); return FALSE; } void prop_colorfield_init( PropColorSetting pcs, Widget menubutton, Widget none_item, Widget chooser_item, Widget swatch, Widget field, Widget changebar ) { Pixel contrast_pix, default_pix; char swatch_name[128]; /* Store Widget-IDs */ pcs->menubutton = menubutton; pcs->swatch = swatch; pcs->field = field; pcs->changebar = changebar; XtAddCallback(chooser_item, XmNactivateCallback, color_chooserCB, (XtPointer)pcs); XtAddCallback(none_item, XmNactivateCallback, color_noneCB, (XtPointer)pcs); /* Determine whether this is a foreground or background color field * and store the corresponding color-default in user-data. */ snprintf(swatch_name, sizeof(swatch_name), "%s", XtName(swatch)); if (strstr(swatch_name, "bg")) default_pix = WhitePixelOfScreen(XtScreen(swatch)); else default_pix = BlackPixelOfScreen(XtScreen(swatch)); /* Ensure Swatch's border is contrast to prop sheet */ XtVaGetValues(XtParent(changebar), XmNforeground, &contrast_pix, NULL); XtVaSetValues(swatch, XmNborderColor, (XtArgVal)contrast_pix, XmNborderWidth, (XtArgVal)1, XmNuserData, (XtArgVal)default_pix, XmNrecomputeSize, (XtArgVal)False, NULL); snprintf(swatch_name, sizeof(swatch_name), "%s", XtName(swatch)); /* Setup Prop Sheet changebar mechanism */ propP_changebar_init(changebar, menubutton); XtAddCallback(field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); } STRING prop_colorfield_get_value( PropColorSetting pcs ) { STRING value; value = ui_field_get_string(pcs->field); return value; } int prop_colorfield_set_value( PropColorSetting pcs, STRING colorname, BOOL trip_changebar ) { Pixel pixel; if (util_strempty(colorname)) /* no color - swatch is 'invisible' */ XtVaGetValues(XtParent(pcs->swatch), XmNbackground, &pixel, NULL); else if (objxm_name_to_pixel(AB_toplevel, colorname, &pixel) != OK) { if (objxm_color_exists(colorname)) /* color couldn't be allocated */ { /* Set swatch color to default black or white */ XtVaGetValues(pcs->swatch, XmNuserData, &pixel, NULL); } else /* Invalid color name - this should not happen */ { util_dprintf(1, "prop_colorfield_set_value: \"%s\" is not an existing color name.\n", colorname); return ERR; } } XtVaSetValues(pcs->swatch, XmNbackground, (XtArgVal)pixel, NULL); if (!trip_changebar) /* Set state so changebar is not triggered */ XtVaSetValues(pcs->field, XmNuserData, (XtArgVal)PROP_LOAD, NULL); /* Set field value */ ui_field_set_string(pcs->field, colorname); if (!trip_changebar) /* Reset state */ XtVaSetValues(pcs->field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); return OK; } void prop_obj_combobox_init( PropObjComboboxSetting pcs, Widget label, Widget combobox, Widget changebar, ABObj *current_obj_ptr ) { /* Store Widget-IDs */ pcs->label = label; pcs->combobox = combobox; pcs->changebar = changebar; pcs->list = ui_combobox_get_list_widget(combobox); pcs->current_obj_ptr = current_obj_ptr; /* Setup Prop Sheet changebar mechanism */ propP_changebar_init(changebar, combobox); /* Load "None" Item */ prop_obj_combobox_load(pcs, NULL, NULL); XtAddCallback(combobox, DtNselectionCallback, propP_combobox_chgCB, (XtPointer)pcs); } ABObj prop_obj_combobox_get_value( PropObjComboboxSetting pcs ) { ABObj obj; STRING name; XmStringTable selected; int select_count = 0; XtVaGetValues(pcs->list, XmNselectedItems, &selected, XmNselectedItemCount, &select_count, NULL); if (select_count == 0) { util_dprintf(1, "prop_obj_combobox_get_value: No items select in List\n"); return NULL; } name = objxm_xmstr_to_str(selected[0]); if (util_strcmp(name, NoneItem) != 0) obj = obj_find_by_name(obj_get_module(*pcs->current_obj_ptr), name); else obj = NULL; /* "None" was selected */ util_free(name); return obj; } int prop_obj_combobox_set_value( PropObjComboboxSetting pcs, ABObj obj, BOOL trip_changebar ) { ui_combobox_select_item(pcs->combobox, (STRING)(obj? obj_get_name(obj) : NoneItem)); prop_set_changebar(pcs->changebar, trip_changebar? PROP_CB_ON : PROP_CB_OFF); return 0; } void prop_obj_combobox_load( PropObjComboboxSetting pcs, ABObj root, ABObjTestFunc obj_test_func ) { AB_TRAVERSAL trav; ABObj obj; ui_combobox_clear(pcs->combobox); ui_combobox_add_item(pcs->combobox, (STRING)NoneItem, 0, False); if (root != NULL) { for (trav_open(&trav, root, AB_TRAV_SALIENT_UI); (obj= trav_next(&trav)) != NULL; ) if ((*obj_test_func)(obj) == True) ui_combobox_add_item(pcs->combobox, obj_get_name(obj), 0, False); trav_close(&trav); } } void prop_field_init( PropFieldSetting pfs, Widget label, Widget field, Widget changebar ) { /* Store Widget-IDs */ pfs->label = label; pfs->field = field; pfs->changebar = changebar; /* Setup Prop Sheet changebar mechanism */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); propP_changebar_init(changebar, field); XtAddCallback(field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); } STRING prop_field_get_value( PropFieldSetting pfs ) { STRING value; value = ui_field_get_string(pfs->field); return value; } int prop_field_set_value( PropFieldSetting pfs, STRING value, BOOL trip_changebar ) { return(propP_field_set_value(pfs->field, value, trip_changebar)); } int prop_field_get_numeric_value( PropFieldSetting pfs ) { STRING value; int num; value = ui_field_get_string(pfs->field); num = prop_str_to_int(value); util_free(value); return num; } int prop_field_set_numeric_value( PropFieldSetting pfs, int value, BOOL trip_changebar ) { char valstr[8]; if (!trip_changebar) /* Set state so changebar is not triggered */ XtVaSetValues(pfs->field, XmNuserData, (XtArgVal)PROP_LOAD, NULL); /* Convert int to string */ sprintf(valstr, "%d", value); ui_field_set_string(pfs->field, valstr); if (!trip_changebar) /* Reset state */ XtVaSetValues(pfs->field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); return OK; } void prop_footer_init( PropFooterSetting pfs, Widget label, Widget checkbox, int num_items, WidgetList items, XtArgVal *item_keys, Widget field, Widget changebar ) { int i; /* Store Widget-IDs */ pfs->label = label; pfs->checkbox = checkbox; pfs->field = field; pfs->changebar = changebar; /* Setup Prop Sheet changebar mechanism */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); propP_changebar_init(changebar, checkbox); XtAddCallback(field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); for (i=0; i < num_items; i++) { XtVaSetValues(items[i], XmNuserData, item_keys[i], NULL); XtAddCallback(items[i], XmNvalueChangedCallback, propP_setting_chgCB, (XtPointer)changebar); } } void prop_geomfield_init( PropGeometrySetting pgs, Widget label, Widget x_label, Widget x_field, Widget y_label, Widget y_field, Widget w_label, Widget w_field, Widget h_label, Widget h_field, Widget changebar ) { /* Store Widget-IDs */ pgs->label = label; pgs->x_label = x_label; pgs->x_field = x_field; pgs->y_label = y_label; pgs->y_field = y_field; pgs->w_label = w_label; pgs->w_field = w_field; pgs->h_label = h_label; pgs->h_field = h_field; pgs->changebar = changebar; /* Setup Prop Sheet changebar mechanism */ propP_changebar_init(changebar, x_field? x_field : (y_field? y_field : (w_field? w_field : h_field))); if (x_field != NULL) { XtVaSetValues(x_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); XtAddCallback(x_field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); } if (y_field != NULL) { XtVaSetValues(y_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); XtAddCallback(y_field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); } if (h_field != NULL) { XtVaSetValues(h_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); XtAddCallback(h_field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); } if (w_field != NULL) { XtVaSetValues(w_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); XtAddCallback(w_field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); } } int prop_geomfield_get_value( PropGeometrySetting pgs, GEOM_KEY gkey ) { Widget field; STRING value; int gvalue = 0; switch(gkey) { case GEOM_X: field = pgs->x_field; break; case GEOM_Y: field = pgs->y_field; break; case GEOM_WIDTH: field = pgs->w_field; break; case GEOM_HEIGHT: field = pgs->h_field; break; default: field = NULL; } if (field) { value = ui_field_get_string(field); gvalue = prop_str_to_int(value); util_free(value); } return gvalue; } int prop_geomfield_set_value( PropGeometrySetting pgs, GEOM_KEY gkey, int gvalue, BOOL trip_changebar ) { Widget field; switch(gkey) { case GEOM_X: field = pgs->x_field; break; case GEOM_Y: field = pgs->y_field; break; case GEOM_WIDTH: field = pgs->w_field; break; case GEOM_HEIGHT: field = pgs->h_field; break; default: field = NULL; } if (field) propP_field_set_numeric_value(field, gvalue, trip_changebar); return OK; } void prop_load_obj_position( ABObj obj, PropGeometrySetting pgs ) { BOOL movable = abobj_is_movable(obj); prop_geomfield_set_value(pgs, GEOM_X, abobj_get_comp_x(obj), False); prop_geomfield_set_value(pgs, GEOM_Y, abobj_get_comp_y(obj), False); ui_set_active(pgs->x_field, movable); ui_set_active(pgs->x_label, movable); ui_set_active(pgs->y_field, movable); ui_set_active(pgs->y_label, movable); } void prop_load_obj_size( ABObj obj, PropGeometrySetting pgs ) { BOOL resizable; if (pgs->w_field) { prop_geomfield_set_value(pgs, GEOM_WIDTH, abobj_get_comp_width(obj), False); resizable = abobj_width_resizable(obj); ui_set_active(pgs->w_field, resizable); ui_set_active(pgs->w_label, resizable); } if (pgs->h_field) { prop_geomfield_set_value(pgs, GEOM_HEIGHT, abobj_get_comp_height(obj), False); resizable = abobj_height_resizable(obj); ui_set_active(pgs->h_field, resizable); ui_set_active(pgs->h_label, resizable); } } void prop_size_policyCB( Widget w, XtPointer clientdata, XtPointer calldata ) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct*)calldata; PropGeometrySetting pgs = (PropGeometrySetting)clientdata; XtArgVal value; BOOL active = False; if (state->set) { XtVaGetValues(w, XmNuserData, &value, NULL); active = (value == SIZE_FIXED_KEY); if (pgs->w_label) ui_set_active(pgs->w_label, active); if (pgs->w_field) ui_set_active(pgs->w_field, active); if (pgs->h_label) ui_set_active(pgs->h_label, active); if (pgs->h_field) ui_set_active(pgs->h_field, active); } } #define NO_MENU 0 #define NEW_MENU 1 #define MENUS 2 #define EDIT_MENU 3 void prop_menuname_init( PropMenunameSetting pms, AB_PROP_TYPE ptype, Widget label, Widget menubutton, Widget field, Widget owner_name_field, Widget changebar, PropFieldSetting menu_title_pfs, ABObj *current_obj_ptr, BOOL new_item_ok ) { Widget submenu; Widget menu_items[4]; int i; pms->prop_type = ptype; pms->label = label; pms->menubutton = menubutton; pms->field = field; pms->owner_name_field = owner_name_field; pms->changebar = changebar; pms->menu_title_pfs = menu_title_pfs; pms->current_obj_ptr = current_obj_ptr; /* Setup Prop Sheet changebar mechanism */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); propP_changebar_init(changebar, field); XtAddCallback(field, XmNvalueChangedCallback, propP_field_chgCB, (XtPointer)changebar); /* Build Menu and Setup Callbacks */ XtVaGetValues(menubutton, XmNsubMenuId, &submenu, NULL); for (i=0; i < XtNumber(menu_items); i++) { menu_items[i] = XtVaCreateManagedWidget(menu_names[i], xmCascadeButtonWidgetClass, submenu, XtVaTypedArg, XmNlabelString, XtRString, menu_strs[i], strlen(menu_strs[i])+1, XmNuserData, pms, NULL); } XtAddCallback(menu_items[NO_MENU], XmNactivateCallback, menuname_clearCB, (XtPointer)pms); if (!new_item_ok) XtDestroyWidget(menu_items[NEW_MENU]); else XtAddCallback(menu_items[NEW_MENU], XmNactivateCallback, menu_newCB, (XtPointer)pms); /* Set up callback to dynamically build "Menus" submenu */ XtAddCallback(menubutton, XmNcascadingCallback, menulist_buildCB, (XtPointer)menu_items[MENUS]); XtVaGetValues(menubutton, XmNsubMenuId, &submenu, NULL); XtAddCallback(XtParent(submenu), XtNpopdownCallback, menulist_destroyCB, (XtPointer)submenu); /* Set up "Edit Current" menu item */ XtAddCallback(menubutton, XmNcascadingCallback, menu_edit_set_stateCB, (XtPointer)menu_items[EDIT_MENU]); XtAddCallback(menu_items[EDIT_MENU], XmNactivateCallback, menu_editCB, (XtPointer)pms); /* Menu Title field should not be active until a Menu is connected */ if (menu_title_pfs) { XtAddCallback(field, XmNvalueChangedCallback, menu_field_chgCB, (XtPointer)pms); ui_set_active(menu_title_pfs->label, False); ui_set_active(menu_title_pfs->field, False); } } STRING prop_menuname_get_value( PropMenunameSetting pms ) { STRING value; value = ui_field_get_string(pms->field); return value; } int prop_menuname_set_value( PropMenunameSetting pms, STRING value, BOOL trip_changebar ) { return(propP_field_set_value(pms->field, value, trip_changebar)); } void prop_options_init( PropOptionsSetting pos, Widget label, Widget optionbox, Widget menu, int num_items, WidgetList items, XtPointer *item_values, Widget changebar ) { int i; /* Store Widget-IDs */ pos->label = label; pos->optionbox = optionbox; pos->menu = menu; pos->changebar = changebar; /* Setup Prop Sheet changebar mechanism */ propP_changebar_init(changebar, optionbox); for (i=0; i < num_items; i++) { XtVaSetValues(items[i], XmNuserData, (XtArgVal)item_values[i], NULL); XtAddCallback(items[i], XmNactivateCallback, propP_setting_chgCB, (XtPointer)changebar); XtAddCallback(items[i], XmNactivateCallback, propP_options_itemCB, (XtPointer)menu); } /* Initialize Current-value to First Item in Option Menu */ if (num_items > 0) prop_options_set_value(pos, (XtPointer)item_values[0], False); } XtPointer prop_options_get_value(PropOptionsSetting pos) { XtArgVal value = -1; XtVaGetValues(pos->menu, XmNuserData, &value, NULL); return ((XtPointer)value); } int prop_options_set_value( PropOptionsSetting pos, XtPointer value, BOOL trip_changebar ) { int num_children; WidgetList children; XtArgVal child_val; int i; XtVaGetValues(pos->menu, XtNnumChildren, &num_children, XtNchildren, &children, NULL); for (i = 0; i < num_children; i++) { XtVaGetValues(children[i], XmNuserData, &child_val, NULL); if (child_val == (XtArgVal) value) { XtVaSetValues(pos->optionbox, XmNmenuHistory, children[i], NULL); XtVaSetValues(pos->menu, XmNuserData, (XtArgVal)child_val, NULL); if (trip_changebar) prop_set_changebar(pos->changebar, PROP_CB_ON); return OK; } } /* value doesn't exist as an option */ util_dprintf(1, "prop_optionmenu_set_value: invalid option\n"); return ERROR; } /* * prop_options_remove_value() * Unmanages item corresponding to 'value' */ int prop_options_remove_value( PropOptionsSetting pos, XtPointer value, BOOL trip_changebar ) { int num_children; WidgetList children; XtArgVal child_val, reset_val; int i; XtVaGetValues(pos->menu, XtNnumChildren, &num_children, XtNchildren, &children, NULL); for (i = 0; i < num_children; i++) { XtVaGetValues(children[i], XmNuserData, &child_val, NULL); if (child_val == (XtArgVal)value) { XtArgVal cur_val; cur_val = (XtArgVal)prop_options_get_value(pos); /* * Found value to remove. We need to do: * - if current setting value is the same as the one we are * deleting, set the setting value to be the previous item * (if that is not the deleted one) * - unmanage item widget */ if (cur_val == (XtArgVal)value) { if ((i == 0) && (num_children != 1)) { XtVaGetValues(children[1], XmNuserData, &reset_val, NULL); prop_options_set_value(pos, (XtPointer)reset_val, trip_changebar); } else if (i != 0) prop_options_set_value(pos, (XtPointer)reset_val, trip_changebar); } XtUnmanageChild(children[i]); if (trip_changebar) prop_set_changebar(pos->changebar, PROP_CB_ON); return OK; } else /* * Remember previous child value */ reset_val = child_val; } /* value doesn't exist as an option */ util_dprintf(1, "prop_optionmenu_set_value: invalid option\n"); return ERROR; } void prop_obj_options_init( PropObjOptionsSetting pos, Widget label, Widget optionbox, Widget menu, int num_items, WidgetList items, XtPointer *item_values, Widget changebar, BOOL display_module, ABObj *current_obj_ptr, ABObjTestFunc obj_test_func ) { Widget shell; prop_options_init(&(pos->options), label, optionbox, menu, num_items, items, item_values, changebar); pos->display_module = display_module; pos->current_obj_ptr = current_obj_ptr; pos->obj_test_func = obj_test_func; pos->search_root = NULL; /* Setup callback to dynamically build Object list when Menu is popped up */ shell = ui_get_ancestor_shell(menu); XtAddCallback(shell, XtNpopupCallback, obj_options_buildCB, (XtPointer)pos); } ABObj prop_obj_options_get_value( PropObjOptionsSetting pos ) { return((ABObj)prop_options_get_value(&(pos->options))); } int prop_obj_options_set_value( PropObjOptionsSetting pos, ABObj obj, BOOL trip_changebar ) { return(prop_options_set_value(&(pos->options), (XtPointer)obj, trip_changebar)); } void prop_obj_options_load( PropObjOptionsSetting pos, ABObj search_root ) { AB_TRAVERSAL trav; ABObj obj; int i, num_items; WidgetList items; /* Clear Object OptionMenu */ XtVaGetValues(pos->options.menu, XmNchildren, &items, XmNnumChildren, &num_items, NULL); /* Unmanage all but the First ("None") items */ if (num_items > 1) XtUnmanageChildren(&(items[1]), num_items - 1); i = 1; /* Load OptionMenu with objects passing "test" */ pos->search_root = search_root; if (pos->search_root != NULL) { for (trav_open(&trav, pos->search_root, AB_TRAV_SALIENT_UI); (obj= trav_next(&trav)) != NULL; ) if ((*(pos->obj_test_func))(obj) == True) { /* Either create new item or use existing one */ create_obj_option_item(pos, i < num_items? items[i] : NULL, obj); i++; } trav_close(&trav); } XtVaGetValues(pos->options.menu, XmNchildren, &items, NULL); /* Manage all eligible items */ if (i > 1) XtManageChildren(&(items[1]), i - 1); } void prop_radiobox_init( PropRadioSetting prs, Widget label, Widget radiobox, int num_items, WidgetList items, XtPointer *item_values, Widget changebar ) { int i; /* Store Widget-IDs */ prs->label = label; prs->radiobox = radiobox; prs->changebar = changebar; /* Setup Prop Sheet changebar mechanism */ propP_changebar_init(changebar, radiobox); for (i=0; i < num_items; i++) { XtVaSetValues(items[i], XmNuserData, (XtArgVal)item_values[i], NULL); XtAddCallback(items[i], XmNvalueChangedCallback, propP_setting_chgCB, (XtPointer*)changebar); XtAddCallback(items[i], XmNvalueChangedCallback, propP_radiobox_itemCB, (XtPointer)item_values[i]); /* Ensure Radiobox has a default Value set */ if (i == 0) { XtVaSetValues(items[i], XmNset, True, NULL); XtVaSetValues(radiobox, XmNuserData, (XtArgVal)item_values[i], NULL); } } } int prop_radiobox_get_value( PropRadioSetting prs ) { XtArgVal value; XtVaGetValues(prs->radiobox, XmNuserData, &value, NULL); return((int)value); } int prop_radiobox_set_value( PropRadioSetting prs, XtPointer value, BOOL trip_changebar ) { int num_children = 0; WidgetList children = NULL; XtArgVal childval = 0; Boolean found = FALSE; int i = 0; XtVaGetValues(prs->radiobox, XtNnumChildren, &num_children, XtNchildren, &children, NULL); for (i = 0; i < num_children; i++) { XtVaGetValues(children[i], XmNuserData, &childval, NULL); XmToggleButtonSetState(children[i], childval == (XtArgVal)value? TRUE : FALSE, FALSE); if (childval == (XtArgVal)value) { found = TRUE; XtVaSetValues(prs->radiobox, XmNuserData, (XtArgVal)value, NULL); if (trip_changebar) prop_set_changebar(prs->changebar, PROP_CB_ON); } } if (!found) { util_dprintf(1,"prop_radio_set_value: invalid value\n"); return ERROR; } return OK; } void prop_label_field_init( PropFieldSetting label_pfs, Widget graphic_hint, WidgetList labeltype_items, int num_items ) { int i; if (label_pfs->label != NULL && graphic_hint != NULL) XtVaSetValues(label_pfs->label, XmNuserData, (XtArgVal)graphic_hint, XmNrecomputeSize, False, NULL); for(i=0; i < num_items; i++) XtAddCallback(labeltype_items[i], XmNactivateCallback, (XtCallbackProc)propP_labeltypeCB, (XtPointer)label_pfs); } void prop_setup_label_field( PropFieldSetting label_pfs, PropOptionsSetting label_line_style_pos, AB_LABEL_TYPE ltype, STRING field_val, AB_LINE_TYPE line_style ) { Widget graphic_hint = NULL; XtVaGetValues(label_pfs->label, XmNuserData, &graphic_hint, NULL); switch(ltype) { case AB_LABEL_STRING: case AB_LABEL_GLYPH: ui_set_label_string(label_pfs->label, (STRING)(ltype == AB_LABEL_STRING? LabelForString : LabelForGraphic)); if (graphic_hint) ui_set_active(graphic_hint, (ltype == AB_LABEL_GLYPH)); ui_set_active(label_pfs->label, True); ui_field_set_editable(label_pfs->field, True); if (label_line_style_pos) { ui_set_active(label_line_style_pos->label, False); ui_set_active(label_line_style_pos->optionbox, False); } break; case AB_LABEL_SEPARATOR: ui_set_active(label_pfs->label, False); ui_field_set_string(label_pfs->field, ""); ui_field_set_editable(label_pfs->field, False); ui_set_active(label_line_style_pos->label, True); ui_set_active(label_line_style_pos->optionbox, True); if (graphic_hint) ui_set_active(graphic_hint, False); break; } if (field_val != NULL) { XtVaSetValues(label_pfs->field, XmNuserData, (XtArgVal)PROP_LOAD, NULL); ui_field_set_string(label_pfs->field, field_val); XtVaSetValues(label_pfs->field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); } if (line_style != AB_LINE_UNDEF) prop_options_set_value(label_line_style_pos, (XtPointer)line_style, False); /* WORKAROUND: for Motif bug */ XtVaSetValues(label_pfs->label, XmNalignment, XmALIGNMENT_END, NULL); } /* * return TRUE if changebar is "on" */ BOOL prop_changed( Widget changebar ) { XtArgVal cb_state; XtVaGetValues(changebar, XmNuserData, &cb_state, NULL); if (cb_state == PROP_CB_ON) return(TRUE); else return(FALSE); } /* * Get the running-count of changebars that are "ON" */ BOOL prop_changebars_pending( Widget prop_sheet ) { XtArgVal change_count; XtVaGetValues(prop_sheet, XmNuserData, &change_count, NULL); if (change_count > 0) return True; else return False; } /* * Set the running-count of changebars that are "ON" to 0 */ void prop_changebars_cleared( Widget prop_sheet ) { XtVaSetValues(prop_sheet, XmNuserData, (XtArgVal)0, NULL); } /* * Set changebar to desired state: on or off * Also keep a running count of the number of changebars * that are "ON" in the userData of the changebars' parent */ void prop_set_changebar( Widget changebar, int mode ) { Widget prop_sheet; Pixel bar_pixel; prop_sheet = XtParent(changebar); if (mode == PROP_CB_ON) { /* REMIND: aim - workaround for Motif problem with Prop textfield input being lost... if (!prop_changed(changebar)) { */ XtVaGetValues(XtParent(changebar), XmNforeground, &bar_pixel, NULL); XtVaSetValues(changebar, XmNbackground, bar_pixel, XmNforeground, bar_pixel, XmNuserData, (XtArgVal)PROP_CB_ON, NULL); /* Set dirty-bit */ XtVaSetValues(prop_sheet, XmNuserData, (XtArgVal)1, NULL); /* } */ } else /* PROP_CB_OFF */ { /* if (prop_changed(changebar)) { */ XtVaGetValues(XtParent(changebar), XmNbackground, &bar_pixel, NULL); XtVaSetValues(changebar, XmNbackground, bar_pixel, XmNforeground, bar_pixel, XmNuserData, (XtArgVal)PROP_CB_OFF, NULL); /* } */ } } /* * Verify that the colorname entered is valid */ BOOL prop_color_ok( Widget field ) { STRING colorname; BOOL valid = TRUE; colorname = ui_field_get_string(field); /* No color is OK */ if (util_strempty(colorname)) return valid; if (!objxm_color_exists(colorname)) { sprintf(Buf, CATGETS(Dtb_project_catd, 100, 112, "%s is not a valid color."), colorname); util_set_help_data(CATGETS(Dtb_project_catd, 100, 113, "The color that was specified is not recognized\nas a valid color name."), NULL, NULL); valid = FALSE; propP_popup_message(field, Buf, False); } util_free(colorname); return valid; } /* * Verify that the Glyph filename entered is valid */ BOOL prop_graphic_filename_ok( Widget field, BOOL empty_ok ) { char filebase[512]; STRING filename; STRING ext; Pixmap pixmap; int status; BOOL valid = False; filename = ui_field_get_string(field); if (util_strempty(filename)) { if (empty_ok) valid = True; /* No Filename is valid */ else { util_set_help_data(CATGETS(Dtb_project_catd, 100, 115, "If Graphic is specified as the Label Type for\nthe object whose properties are being modified,\nthen a pixmap (.pm, .xpm) or bitmap (.bm, .xbm)\nfile name must be specified in the Graphic Filename\nfield."), NULL, NULL); propP_popup_message(field, CATGETS(Dtb_project_catd, 100, 114, "The \"Graphic Filename\" field cannot be empty."), False); } } else { snprintf(filebase, sizeof(filebase), "%s", filename); /* Look to see if user typed in the full filename for the Graphic. * If so, strip off the extension and mark stripped to be True. */ if (util_file_name_has_extension(filename, "pm") || util_file_name_has_extension(filename, "xpm") || util_file_name_has_extension(filename, "bm") || util_file_name_has_extension(filename, "xbm")) { ext = strrchr(filebase, '.'); ext[0] = '\0'; /* strip off extension */ util_set_help_data(CATGETS(Dtb_project_catd, 100, 117, "The graphic file name extension should not be included\nwhen it is specified in the Graphic Filename field."), NULL, NULL); propP_popup_message(field, CATGETS(Dtb_project_catd, 100, 116, "\"Graphic Filename\" field expects the filename\nbase only (no extensions: .pm .xpm .bm .xbm).\nStripping off the extension."), True); ui_field_set_string(field, filebase); } status = objxm_filebase_to_pixmap(field, filebase, &pixmap); if (status == OK) { valid = TRUE; XmDestroyPixmap(XtScreen(field), pixmap); } else propP_popup_message(field, objxm_pixmap_conversion_error_msg(NULL, filebase, status), False); } util_free(filename); return valid; } BOOL prop_help_item_ok( Widget list, ABObj item_obj ) { int num_items; ABObj *iobj_list; BOOL exists = FALSE; int i; char Buf[256]; XtVaGetValues(list, XmNitemCount, &num_items, XmNuserData, &iobj_list, NULL); /* Search through cascades, looking for another configured * to be the "Help" cascade */ for (i = 0; i < num_items; i++) { if (obj_is_help_item(iobj_list[i]) == TRUE && item_obj != iobj_list[i]) { exists = TRUE; break; } } if (exists) { util_set_help_data(CATGETS(Dtb_project_catd, 100, 119, "Two Menubar items cannot both be specified as the\nHelp cascade. To specify a different Menubar item,\nyou must first clear the item that is currently set\nto be the Help cascade, then select the new Menubar\nitem to be the Help cascade."), NULL, NULL); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 118, "There can only be one Help cascade per Menubar.Item\n\"%s\" is already configured to be the Help cascade,\ntherefore Item \"%s\" cannot also be the Help cascade."), obj_get_label(iobj_list[i]), obj_get_label(item_obj)); propP_popup_message(list, Buf, False); return FALSE; } return TRUE; } /* * Verify that identifier string only contains valid chars */ BOOL prop_identifier_ok( Widget field ) { return(prop_string_ok(field, Name_ok_test, TRUE)); } /* * verify that the name entered is valid & unique */ BOOL prop_name_ok( ABObj obj, Widget field ) { ABObj module = obj_get_module(obj); ABObj other = NULL; char Buf[512]; BOOL valid = TRUE; STRING newname; STRING oldname; newname = ui_field_get_string(field); oldname = obj_get_name(obj); if (!newname || !*newname) { util_set_help_data(CATGETS(Dtb_project_catd, 100, 121, "A string must be entered in the Object Name field."), NULL, NULL); propP_popup_message( field, CATGETS(Dtb_project_catd, 100, 120, "A name is required."), False); valid = FALSE; } else if (!prop_identifier_ok(field)) valid = FALSE; else if (!oldname) oldname = ""; if (valid && ((other = obj_find_by_name(module, newname)) != NULL)) { if (other != obj) { util_set_help_data(CATGETS(Dtb_project_catd, 100, 123, "The name specified in the Object Name field is not\na unique name in the module. You must specify a unique\nname for the object."), NULL, NULL); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 122, "Another object in Module \"%s\"\nhas the name \"%s\".\nPlease enter a unique name."), util_strsafe(obj_get_name(module)),newname); propP_popup_message(field, Buf, False); valid = FALSE; } } util_free(newname); return valid; } BOOL prop_number_ok( Widget field, STRING field_name, int min_val, int max_val ) { BOOL valid = TRUE; char *p; STRING string; char *s; int value; string = ui_field_get_string(field); s = string; if ((s != NULL) && (*s != '\0')) { (void)strtol(s, &p, 10); if((s == p) || ((s + strlen(s)) != p)) { util_set_help_data(CATGETS(Dtb_project_catd, 100, 125, "The field only accepts integers. You must enter\nan integer value."), NULL, NULL); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 124, "\"%s\" must contain an integer."), field_name); propP_popup_message(field, Buf, False); valid = FALSE; } } if (valid) /* is an integer */ { value = prop_str_to_int(string); if (value < min_val || value > max_val) { util_set_help_data(CATGETS(Dtb_project_catd, 100, 127, "The numerical value entered into the field is not valid. Specify a value in the given range."), NULL, NULL); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 126, "\"%s\" value (%d) out of\nvalid range [%d - %d]."), field_name, value, min_val, max_val); propP_popup_message(field, Buf, False); valid = False; } } util_free(string); return(valid); } /* * Search the tree beginning at "root" for an object of the specified * type with the name currently stored in "field" * Return TRUE if found (or name is "") and FALSE otherwise */ BOOL prop_obj_name_ok( Widget field, ABObj root, AB_OBJECT_TYPE objtype, STRING objtype_name ) { ABObj target; STRING objname; BOOL valid = FALSE; char msgbuf[256]; objname = ui_field_get_string(field); /* ObjName can be blank OR the name of an existing obj */ if (util_strcmp(objname, "") == 0) valid = TRUE; else if ((target = obj_scoped_find_by_name(root, objname)) != NULL) { if (target->type == objtype) valid = TRUE; else { util_set_help_data(CATGETS(Dtb_project_catd, 100, 129, "The object specified is not of the correct type.\nFor example, it is an error to specify a button\nas the Popup Menu for a Control Pane."), NULL, NULL); sprintf(msgbuf, CATGETS(Dtb_project_catd, 100, 128, "\"%s\" is not an object of type %s."), objname, objtype_name); } } else { util_set_help_data(CATGETS(Dtb_project_catd, 100, 136, "The specified object does not exist or it is\nnot of the correct type."), NULL, NULL); sprintf(msgbuf, CATGETS(Dtb_project_catd, 100, 130, "\"%s\" is not the name of an existing %s."), objname, objtype_name); } if (valid == FALSE) propP_popup_message(field, msgbuf, False); util_free(objname); return valid; } BOOL prop_submenu_name_ok( Widget field, ABObj owner ) { BOOL valid = False; ABObj module = obj_get_module(owner); char msgbuf[256]; /* Check to see if Submenu exists first */ if (prop_obj_name_ok(field, module, AB_TYPE_MENU, "Menu")) { valid = True; /* Check that the submenu name specified will not cause a circular * menu (if the submenu is one that is in the owner's ancestory) */ if (obj_is_menu(owner)) { ABObj menu, *menus, *ineligible_menus; int menu_count = 0; int ineligible_count = 0; STRING menu_name; menu_name = ui_field_get_string(field); abobj_build_menus_array(module, &menus, &menu_count); /* Build list of any menus in the ancestory of "owner" menu * since these are not valid submenus */ ineligible_menus = (ABObj*)util_malloc(menu_count*sizeof(ABObj)); ineligible_menus[ineligible_count++] = owner; find_submenu_owners(owner, menus, menu_count, ineligible_menus, &ineligible_count); /* Check to see if the specified submenu is in the ineligible list */ menu = obj_scoped_find_by_name(module, menu_name); if (menu_in_list(ineligible_menus, ineligible_count, menu)) { STRING fmtStr = NULL; STRING help_buf = NULL; valid = False; fmtStr = XtNewString(CATGETS(Dtb_project_catd, 100, 132, "Menu \"%s\" is attached as a sub-menu\nto \"%s\". You cannot create a circular\nreference within menus.")); help_buf = (STRING) util_malloc(strlen(fmtStr) + strlen(obj_get_name(owner)) + strlen(menu_name) +1); sprintf(help_buf, fmtStr, obj_get_name(owner), menu_name); util_set_help_data(help_buf, NULL, NULL); sprintf(msgbuf, CATGETS(Dtb_project_catd, 100, 131, "Menu \"%s\" is an ancestor of \"%s\"\ntherefore it cannot be attached as a Sub-menu."), menu_name, obj_get_name(owner)); propP_popup_message(field, msgbuf, False); XtFree(fmtStr); util_free(help_buf); } util_free(menus); util_free(ineligible_menus); util_free(menu_name); } } return valid; } int prop_str_to_int( STRING str ) { int val; char *s = str; char *p; if ((s != NULL) && (*s != '\0')) { val = (int)strtol(s, &p, 10); if ((s == p) || ((s + strlen(s)) != p)) { return(ERR_ATOI); } return(val); } return(ERR_ATOI); } /* * verify that a string contains only valid characters */ BOOL prop_string_ok( Widget field, const char *chars, BOOL display_notice ) { STRING string; char *s; string = ui_field_get_string(field); s = string; while(s && *s != '\0') { if (!isalnum(*s) && (strchr(chars, *s) == NULL)) { if (display_notice) { util_set_help_data(CATGETS(Dtb_project_catd, 10, 69, "Object names are used by the code generator to\ncreate C identifier names. C identifiers must\nbe composed of letters, digits, or underscores.\nTherefore, object names in App Builder must also\nfollow that rule."), NULL, NULL); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 133, "Only letters, digits, and [%s] allowed."), chars); propP_popup_message(field, Buf, False); } util_free(string); return(FALSE); } s++; } util_free(string); return(TRUE); } /* ***************************************************************** * Module Private Functions ***************************************************************** */ /* * Set Changebar's geometry so that it is aligned with and equal in height to, * it's corresponding setting. This must be done dynamically because fonts * and localization could cause these metrics to change at dtbuilder invocation. */ static void set_changebar_size( Widget shell, XtPointer client_data, XEvent *event, Boolean *cont_dispatch ) { Widget setting, changebar; Widget setting_p, changebar_p; Position setting_y, delta_y; Dimension setting_h; Widget *wlist = (Widget*)client_data; if (event->type == MapNotify) { changebar = wlist[0]; setting = wlist[1]; XtVaGetValues(setting, XmNheight, &setting_h, XmNy, &setting_y, NULL); changebar_p = XtParent(changebar); setting_p = setting; /* Calculate the setting's overall y position relative to the * entire property sheet by walking up the setting's ancestry * and accumulating the relative y offsets. */ while (setting_p && XtParent(setting_p) != changebar_p) { setting_p = XtParent(setting_p); XtVaGetValues(setting_p, XmNy, &delta_y, NULL); setting_y += delta_y; } /* Align the changebar up with the setting */ XtVaSetValues(changebar, XmNheight, setting_h - 2, XmNy, setting_y + 1, XmNtopOffset, setting_y + 1, NULL); /* Only need to do this once per changebar! */ XtRemoveEventHandler(shell, StructureNotifyMask, False, set_changebar_size, (XtPointer)wlist); util_free(wlist); } } /* * Initialize the changebar */ void propP_changebar_init( Widget changebar, Widget setting ) { Widget shell = ui_get_ancestor_shell(changebar); Widget *wlist; unsigned char changebar_top_att; XtVaSetValues(changebar, XmNuserData, (XtArgVal)PROP_CB_ON, NULL); prop_set_changebar(changebar, PROP_CB_OFF); /* If changebar already has attachment, let's not mess with it */ XtVaGetValues(changebar, XmNtopAttachment, &changebar_top_att, NULL); if (changebar_top_att != XmATTACH_FORM) return; wlist = (Widget*)util_malloc(2*sizeof(Widget)); if (wlist == NULL) return; wlist[0] = changebar; wlist[1] = setting; /* Once the shell is mapped we'll need to calculate the appropriate * changebar size/position to match its corrsponding setting * (which could change dynamically due to fonts/localization) */ XtAddEventHandler(shell, StructureNotifyMask, False, set_changebar_size, (XtPointer)wlist); } /* * Callback: textfield value has changed...turnon changebar * if operation is not a "load" */ void propP_combobox_chgCB( Widget widget, XtPointer clientdata, XtPointer calldata ) { PropObjComboboxSetting pcs = (PropObjComboboxSetting)clientdata; prop_set_changebar(pcs->changebar, PROP_CB_ON); } void propP_field_chgCB( Widget widget, XtPointer clientdata, XtPointer calldata ) { Widget changebar = (Widget)clientdata; XtArgVal field_mode, cb_state; XtVaGetValues(widget, XmNuserData, &field_mode, NULL); /* REMIND: aim - workaround for Motif problem with Prop textfield input being lost... XtVaGetValues(changebar, XmNuserData, &cb_state, NULL); if (field_mode == PROP_EDIT && cb_state == PROP_CB_OFF) */ if (field_mode == PROP_EDIT) prop_set_changebar(changebar, PROP_CB_ON); } int propP_field_set_value( Widget field, STRING value, BOOL trip_changebar ) { if (!trip_changebar) /* Set state so changebar is not triggered */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_LOAD, NULL); /* Set field value */ ui_field_set_string(field, value); if (!trip_changebar) /* Reset state */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); return OK; } int propP_field_set_numeric_value( Widget field, int val, BOOL trip_changebar ) { char valstr[8]; if (!trip_changebar) /* Set state so changebar is not triggered */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_LOAD, NULL); /* Convert int to string */ sprintf(valstr, "%d", val); ui_field_set_string(field, valstr); if (!trip_changebar) /* Reset state */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL); return 0; } void propP_labeltypeCB( Widget item, XtPointer clientdata, XtPointer call_data ) { AB_LABEL_TYPE label_type = AB_LABEL_UNDEF; PropFieldSetting label_pfs = (PropFieldSetting)clientdata; XtVaGetValues(item, XmNuserData, &label_type, NULL); prop_setup_label_field(label_pfs, NULL, label_type, NULL, AB_LINE_UNDEF); ui_field_select_string(label_pfs->field, True); } void propP_options_itemCB( Widget item, XtPointer client_data, XtPointer call_data ) { Widget optionmenu = (Widget)client_data; XtArgVal value; XtVaGetValues(item, XmNuserData, &value, NULL); XtVaSetValues(optionmenu, XmNuserData, (XtArgVal)value, NULL); } /* * popup Error Dialog displaying passed in message */ void propP_popup_message( Widget parent, STRING msg, BOOL modal ) { DtbObjectHelpDataRec help_data; STRING help_text = NULL; STRING help_vol = NULL; STRING help_loc = NULL; XmString xm_buf = XmStringCreateLocalized(msg); dtb_revolv_wrn_msg_initialize(&dtb_revolv_wrn_msg); util_get_help_data(&help_text, &help_vol, &help_loc); if (!util_strempty(help_text)) { help_data.help_text = help_text ? (STRING) XtNewString(help_text) : NULL; help_data.help_volume = help_vol ? (STRING) XtNewString(help_vol) : NULL; help_data.help_locationID = help_loc ? (STRING) XtNewString(help_loc) : NULL; } else { /* If there is no help text to display, * then remove the Help button. */ dtb_revolv_wrn_msg.help_button = False; } if (!util_strempty(help_text)) { dtb_show_message(parent, &dtb_revolv_wrn_msg, xm_buf, &help_data); /* * Free help data strings */ if (help_data.help_text) XtFree(help_data.help_text); if (help_data.help_volume) XtFree(help_data.help_volume); if (help_data.help_locationID) XtFree(help_data.help_locationID); } else dtb_show_message(parent, &dtb_revolv_wrn_msg, xm_buf, NULL); XmStringFree(xm_buf); } /* * Callback: choice value has changed...turnon changebar */ void propP_setting_chgCB( Widget widget, XtPointer clientdata, XtPointer calldata ) { Widget changebar = (Widget)clientdata; XtArgVal cb_state; XtVaGetValues(changebar, XmNuserData, &cb_state, NULL); if (cb_state == PROP_CB_OFF) prop_set_changebar(changebar, PROP_CB_ON); } /* * Callback: item in exclusive choice has been set...store it's * value in the parent radiobox */ void propP_radiobox_itemCB( Widget item, XtPointer clientdata, XtPointer calldata ) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct*)calldata; XtArgVal value = (XtArgVal)clientdata; Widget excl_setting; if (state->set) { excl_setting = XtParent(item); XtVaSetValues(excl_setting, XmNuserData, value, NULL); } } /* ***************************************************************** * Private Functions ***************************************************************** */ static void revolv_dialog_init( Widget parent ) { DtbRevolvPropDialogInfo cgen = &dtb_revolv_prop_dialog; /* Codegen structure */ if (dtb_revolv_prop_dialog_initialize(cgen, parent) == 0) { AB_rev_prop_dialog = cgen->prop_dialog_shellform; XtVaSetValues(cgen->prop_dialog_form, XmNresizePolicy, XmRESIZE_ANY, XmNallowResize, True, XmNautoUnmanage, False, NULL); revolv_objectspane_init(cgen); revolv_basicframe_init(cgen); prop_activate_panel_init(AB_PROP_REVOLVING, NULL, cgen->ok_button, cgen->apply_button, cgen->reset_button, cgen->cancel_button, cgen->help_button); init_prop_state_info(AB_rev_prop_dialog, NULL, cgen->objlist, NULL); ab_register_window(AB_rev_prop_dialog, AB_WIN_DIALOG, WindowHidden, AB_toplevel, AB_WPOS_TILE_HORIZONTAL, close_propsCB, (XtPointer)AB_PROP_REVOLVING); } } /* * In order to get the automatically generated dtbuilder * resource file to work with our Revolving Props cloning * mechanism, we need to name each Revolving prop sheet * frame to be the SAME as the dialog shellform within * the Fixed version (to ensure the attribute settings * resources are picked up in the Revolving version). */ static String get_prop_frame_name( PalItemInfo *palitem ) { switch (palitem->type) { case AB_TYPE_BASE_WINDOW: return "dtb_mainwin_prop_dialog_shellform"; case AB_TYPE_DIALOG: return "dtb_custdlg_prop_dialog_shellform"; case AB_TYPE_FILE_CHOOSER: return "dtb_fchooser_prop_dialog_shellform"; case AB_TYPE_CONTAINER: if (util_streq(palitem->name, "Control Pane")) return "dtb_cpanel_prop_dialog_shellform"; else if (util_streq(palitem->name, "Group")) return "dtb_group_prop_dialog_shellform"; else if (util_streq(palitem->name, "Menubar")) return "dtb_menubar_prop_dialog_shellform"; else return "dtb_panedwin_ed_prop_dialog_shellform"; case AB_TYPE_DRAWING_AREA: return "dtb_drawp_prop_dialog_shellform"; case AB_TYPE_TEXT_PANE: return "dtb_textp_prop_dialog_shellform"; case AB_TYPE_TERM_PANE: return "dtb_termp_prop_dialog_shellform"; case AB_TYPE_BUTTON: return "dtb_button_prop_dialog_shellform"; case AB_TYPE_CHOICE: return "dtb_choice_prop_dialog_shellform"; case AB_TYPE_COMBO_BOX: return "dtb_combobox_prop_dialog_shellform"; case AB_TYPE_LABEL: return "dtb_label_prop_dialog_shellform"; case AB_TYPE_LIST: return "dtb_list_prop_dialog_shellform"; case AB_TYPE_MENU: return "dtb_menu_prop_dialog_shellform"; case AB_TYPE_SCALE: return "dtb_scale_prop_dialog_shellform"; case AB_TYPE_SEPARATOR: return "dtb_sep_prop_dialog_shellform"; case AB_TYPE_SPIN_BOX: return "dtb_spinbox_prop_dialog_shellform"; case AB_TYPE_TEXT_FIELD: return "dtb_textf_prop_dialog_shellform"; default: return "revolv_prop_frame"; } } static void revolv_basicframe_init( DtbRevolvPropDialogInfo cgen ) { int i; Widget rev_form; Widget rev_frame; /* Destroy dummy frame & controlpanel */ XtDestroyWidget(cgen->attrs_ctrlpanel_frame); /* Create Form to manage all revolving frames */ rev_form = XtVaCreateManagedWidget("revolving_dialog_form", xmFormWidgetClass, cgen->prop_dialog_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cgen->objlist_panel, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNresizePolicy, XmRESIZE_ANY, XmNheight, 600, NULL); /* * Create frame for each object on the palette... */ for (i = 0; i < palette_item_cnt; i++) { rev_frame = cgen->attrs_ctrlpanel_frame = XtVaCreateWidget(get_prop_frame_name(palette_item[i]), xmFrameWidgetClass, rev_form, XmNshadowType, XmSHADOW_IN, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); (*(palette_item[i]->prop_initialize))(rev_frame, AB_PROP_REVOLVING); palette_item[i]->rev_prop_frame = rev_frame; /* Make sure Frame is not initially managed */ XtUnmanageChild(rev_frame); } } static BOOL editable_obj_test( PalEditableObjInfo *ed_obj_info ) { return (ed_obj_info->palitem != NULL); } static void revolv_objectspane_init( DtbRevolvPropDialogInfo cgen ) { revolv_optionmenu = cgen->objtype_opmenu; /* Destroy dummy Option menu item */ XtDestroyWidget(cgen->objtype_opmenu_items.object_type_item); /* Build up Object Type Option Menu */ pal_add_editable_obj_menu_items(cgen->objtype_opmenu_menu, change_objecttypeCB, editable_obj_test); /* * Configure Revolving Behavior */ XtAddCallback(cgen->tearoff_button, XmNactivateCallback, tearoff_propsCB, NULL); XtAddCallback(cgen->objlist, XmNbrowseSelectionCallback, (XtCallbackProc)objlist_selectCB, (XtPointer)AB_PROP_REVOLVING); /* Setup Object List Label */ XtVaSetValues(cgen->objlist_label2, XmNalignment, XmALIGNMENT_END, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, cgen->objlist_scrolledwin, XmNrightOffset, 4, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNbottomAttachment, XmATTACH_NONE, NULL); } /* * Switch the Revolving-prop frame to display the pane * matching the specified Palette Item type. */ static void revolv_change_prop_frame( PalItemInfo *palitem ) { Widget newframe = NULL; PropStateInfo *pstate; if (palitem->rev_prop_frame != NULL) { newframe = palitem->rev_prop_frame; XtManageChild(newframe); } if (newframe != NULL) { if (revolv_current_frame != NULL) XtUnmanageChild(revolv_current_frame); revolv_current_frame = newframe; } pstate = get_prop_state_info(AB_rev_prop_dialog); pstate->palitem = palitem; objlist_load(AB_PROP_REVOLVING, pstate); } /* * Attempt to change the Type of Props being edited * in the Revolving Prop dialog to the specified * Palette Item type. IF there are currently un-applied * edits pending, handle "auto apply". */ static PalItemInfo * revolv_set_prop_type( PalItemInfo *new_palitem, ABObj load_obj ) { PalItemInfo *viz_palitem = new_palitem; PropStateInfo *pstate; if (revolv_current_frame != new_palitem->rev_prop_frame) { pstate = get_prop_state_info(AB_rev_prop_dialog); if (pstate->palitem && (*pstate->palitem->prop_pending)(AB_PROP_REVOLVING) == TRUE) handle_auto_apply(AB_PROP_REVOLVING, pstate, new_palitem, load_obj, &viz_palitem); else revolv_change_prop_frame(new_palitem); } /* Return current visible Palette Item type (might be different * than one requested if user canceled load operation during * auto-apply */ return(viz_palitem); } /* * Invoke Revolving Property Dialog (create if it doesn't exist) * and set it's revolving-type to the Palette Item type * corrsponding to the loadobj's type (if loadobj == NULL, then * no specific object is being loaded). */ static PalItemInfo * revolv_invoke_props( PalItemInfo *palitem, ABObj load_obj ) { PalItemInfo *viz_palitem; if (!AB_rev_prop_dialog) revolv_dialog_init(AB_toplevel); viz_palitem = revolv_set_prop_type(palitem, load_obj); ab_show_window(AB_rev_prop_dialog); ui_optionmenu_change_label(revolv_optionmenu, viz_palitem->name); return(viz_palitem); } static void fixed_invoke_props( PalItemInfo *palitem ) { Widget prop_dialog; PropStateInfo *pstate; char title[64]; static BOOL first_time = True; if (palitem->fix_prop_dialog == NULL) { prop_dialog = (*(palitem->prop_initialize))(AB_toplevel, AB_PROP_FIXED); if (prop_dialog != NULL) { palitem->fix_prop_dialog = prop_dialog; pstate = get_prop_state_info(palitem->fix_prop_dialog); /* Load all current objects of this type into the list */ objlist_load(AB_PROP_FIXED, pstate); } } else prop_dialog = palitem->fix_prop_dialog; if (prop_dialog != NULL) { if (first_time) { ab_position_window(prop_dialog, ab_window_is_open(AB_rev_prop_dialog)? AB_rev_prop_dialog : AB_toplevel, AB_WPOS_TILE_HORIZONTAL); first_time = False; } ab_show_window(prop_dialog); } else util_dprintf(1, "fixed_invoke_props: could not initialize Properties for %s\n", palitem->name); } static int apply_props( AB_PROP_TYPE type, Widget dialog ) { PropStateInfo *pstate; pstate = get_prop_state_info(dialog); if (pstate->loaded_obj == NULL) /* no object currently loaded */ return OK; return(apply_prop_changes(type, pstate->loaded_obj, pstate->palitem)); } /* * Apply Prop changes to an object */ static int apply_prop_changes( AB_PROP_TYPE type, ABObj obj, PalItemInfo *palitem ) { Widget alt_dialog = NULL; AB_PROP_TYPE alt_type; PropStateInfo *alt_pstate; int result; apply_in_progress = True; result = (*(palitem->prop_apply))(type); apply_in_progress = False; /* If same object is also loaded into alternate prop dialog, * propagate the changes to the alternate dialog. */ if (type == AB_PROP_REVOLVING && palitem->fix_prop_dialog != NULL) { alt_type = AB_PROP_FIXED; alt_dialog = palitem->fix_prop_dialog; } else if (type == AB_PROP_FIXED && palitem->rev_prop_frame == revolv_current_frame) { alt_type = AB_PROP_REVOLVING; alt_dialog = AB_rev_prop_dialog; } if (alt_dialog) { alt_pstate = get_prop_state_info(alt_dialog); if (alt_pstate->loaded_obj == obj) (*(palitem->prop_load))(obj, alt_type, LoadAll); } return result; } /* * Handle Auto-apply: * Another object is being loaded into a Prop dialog * however another object has edits pending; * Post a Modal Message asking the user to Apply the * changes or Cancel the Load operation. * Return the resulting Palette Item type which is * showing after the user makes a choice. */ static DTB_MODAL_ANSWER handle_auto_apply( AB_PROP_TYPE prop_type, PropStateInfo *pstate, PalItemInfo *new_palitem, ABObj new_obj, PalItemInfo **result ) { DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE; char Buf[256]; BOOL changing_types = FALSE; STRING modname; DtbObjectHelpData help_data = NULL; if (pstate->loaded_obj == NULL) /* something's wrong */ { util_dprintf(1,"handle_auto_apply: NULL previous obj!??\n"); *result = NULL; return answer; } if (new_palitem != pstate->palitem) changing_types = TRUE; help_data = (DtbObjectHelpData) util_malloc(sizeof(DtbObjectHelpDataRec)); help_data->help_volume = NULL; help_data->help_locationID = NULL; if (dtb_app_resource_rec.implied_apply == True) { answer = DTB_ANSWER_ACTION1; } else { XmString xm_buf = (XmString) NULL; STRING loadedObjName = obj_get_name(pstate->loaded_obj); if (new_obj == NULL) { if (changing_types) { sprintf(Buf, CATGETS(Dtb_project_catd, 100, 34, "Properties for \"%s\" have been modified but not Applied.\ \nApply Changes or Cancel Change-ObjectType operation."), loadedObjName); help_data->help_text = CATGETS(Dtb_project_catd, 100,95, "Click Apply Changes to apply the changes to the\ncurrent object and display the new object type.\n\nClick Cancel if you don't want to apply the\nchanges to the current object. You can then\nclick Reset to undo the changes before changing\nto a different object type."); } else { sprintf(Buf, CATGETS(Dtb_project_catd, 100, 35, "Properties for \"%s\" have been modified but not Applied.\ \nApply Changes or Cancel Close operation."), loadedObjName); help_data->help_text = CATGETS(Dtb_project_catd, 100,96, "Click Apply Changes to apply the changes to the\ncurrent object and close the Property Editor.\n\nClick Cancel if you don't want to apply the\nchanges to the current object and want the\nProperty Editor to remain displayed. You can\nthen click Reset to undo the changes before\nclosing the Property Editor."); } } else { STRING newObjName = obj_get_name(new_obj); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 36, "Properties for \"%s\" have been modified but not Applied.\ \nApply Changes or Cancel Load operation for \"%s\"."), loadedObjName, newObjName); help_data->help_text = CATGETS(Dtb_project_catd, 100,93, "Click Apply Changes to apply the changes to the\ncurrent object and load the selected object.\n\nClick Cancel if you don't want to apply the\nchanges to the current object. You can then\nclick Reset to undo the changes before loading\nthe selected object."); } /* Popup Modal Message and wait for answer */ xm_buf = XmStringCreateLocalized(Buf); dtb_revolv_prop_pend_msg_initialize(&dtb_revolv_prop_pend_msg); answer = dtb_show_modal_message(pstate->objlist, &dtb_revolv_prop_pend_msg, xm_buf, help_data, NULL); util_free(help_data); XmStringFree(xm_buf); } switch(answer) { case DTB_ANSWER_ACTION1: /* Apply Changes */ /* * If Apply was not successful (value verification failed), then * do not change to the new Prop sheet. */ if (apply_prop_changes(prop_type, pstate->loaded_obj, pstate->palitem) != OK) { *result = pstate->palitem; answer = DTB_ANSWER_CANCEL; } else { if (!changing_types) load_props(prop_type, pstate, new_obj); else revolv_change_prop_frame(new_palitem); *result = new_palitem; } break; case DTB_ANSWER_CANCEL: /* Cancel Load */ if (changing_types) ui_optionmenu_change_label(revolv_optionmenu, pstate->palitem->name); modname = abobj_get_moduled_name(pstate->loaded_obj); ui_list_select_item(pstate->objlist, modname, FALSE); util_free(modname); *result = pstate->palitem; } return answer; } static PropStateInfo * get_prop_state_info( Widget widget ) { Widget dialog; PropStateInfo *pstate; dialog = ui_get_ancestor_dialog(widget); XtVaGetValues(dialog, XmNuserData, &pstate, NULL); return pstate; } static void init_prop_state_info( Widget dialog, PalItemInfo *palitem, Widget objlist, ABObj loaded_obj ) { PropStateInfo *pstate; pstate = (PropStateInfo*)util_malloc(sizeof(PropStateInfo)); pstate->palitem = palitem; pstate->objlist = objlist; pstate->loaded_obj = loaded_obj; XtVaSetValues(dialog, XmNuserData, (XtArgVal)pstate, NULL); } /* * Load an object into the Revolving or Fixed Prop dialog */ static void load_props( AB_PROP_TYPE type, PropStateInfo *pstate, ABObj obj ) { pstate->loaded_obj = obj; /* Load obj's props */ (*(pstate->palitem->prop_load))(obj, type, LoadAll); } static int objlist_delete_obj( AB_PROP_TYPE type, PalItemInfo *palitem, ObjEvDestroyInfo info ) { Widget dialog; PropStateInfo *pstate; int num_items; int first_viz, last_viz; if (type == AB_PROP_REVOLVING) dialog = AB_rev_prop_dialog; else dialog = palitem->fix_prop_dialog; pstate = get_prop_state_info(dialog); cur_list_palitem = palitem; abobj_list_obj_destroyed(pstate->objlist, info->obj, objlist_test_func); ui_list_get_info(pstate->objlist, &num_items, &first_viz, &last_viz); if (num_items == 0) /* Deleted Last one...*/ { /* Clear Prop Sheet & Make it Inactive */ (*(palitem->prop_clear))(type); (*(palitem->prop_activate))(type, FALSE); pstate->loaded_obj = NULL; } else if (info->obj == pstate->loaded_obj) /* Deleted "Current" one...*/ { /* If there are pending edits on the deleted object, first clear * those edits via a reset before making another object "current" * in props. */ if ((*(palitem->prop_pending))(type) == True) (*(palitem->prop_load))(NULL, type, LoadAll); ui_list_select_pos(pstate->objlist, 1, TRUE); } return 0; } /* * Ensure an item is selected in the Prop dialog list */ static void objlist_ensure_selection( Widget objlist ) { int num_items = 0; int num_selected = 0; XtVaGetValues(objlist, XmNitemCount, &num_items, XmNselectedItemCount, &num_selected, NULL); if (num_selected == 0 && num_items > 0) ui_list_select_pos(objlist, 1, TRUE); } /* * Traverse the project and load all objects matching the * Palette Item type into the Prop dialog list */ static void objlist_load( AB_PROP_TYPE type, PropStateInfo *pstate ) { ABObj proj = proj_get_project(); int num_items = 0; if (proj == NULL || pstate->objlist == NULL) return; /* Reset Loaded-obj to NULL */ pstate->loaded_obj = NULL; cur_list_palitem = pstate->palitem; num_items = abobj_list_load(pstate->objlist, proj, objlist_test_func); /* If there are items in the list, activate the Props, * else de-activate them. */ ((*pstate->palitem->prop_activate)(type, num_items > 0? TRUE : FALSE)); } static int objlist_rename_obj( AB_PROP_TYPE type, PalItemInfo *palitem, ObjEvAttChangeInfo info ) { Widget dialog; PropStateInfo *pstate; if (type == AB_PROP_REVOLVING) dialog = AB_rev_prop_dialog; else dialog = palitem->fix_prop_dialog; pstate = get_prop_state_info(dialog); cur_list_palitem = palitem; abobj_list_obj_renamed(pstate->objlist, info->obj, istr_string(info->old_name), objlist_test_func); return 0; } static int objlist_show_or_hide_obj( AB_PROP_TYPE type, PalItemInfo *palitem, ObjEvUpdateInfo info ) { Widget dialog; PropStateInfo *pstate; int orig_num_items = 0; int num_items = 0; int first_vis, last_vis; if (type == AB_PROP_REVOLVING) dialog = AB_rev_prop_dialog; else dialog = palitem->fix_prop_dialog; pstate = get_prop_state_info(dialog); ui_list_get_info(pstate->objlist, &orig_num_items, &first_vis, &last_vis); cur_list_palitem = palitem; abobj_list_obj_updated(pstate->objlist, info, objlist_test_func); ui_list_get_info(pstate->objlist, &num_items, &first_vis, &last_vis); if (orig_num_items == 0 && num_items > 0) (*(palitem->prop_activate))(type, TRUE); if (num_items == 0) /* Hid Last one...*/ { /* Clear Prop Sheet & Make it Inactive */ (*(palitem->prop_clear))(type); (*(palitem->prop_activate))(type, FALSE); pstate->loaded_obj = NULL; } else if (!(pstate->loaded_obj != NULL && obj_has_flag(obj_get_module(pstate->loaded_obj), MappedFlag)) || num_items == 1) /* Make sure 1 is selected */ ui_list_select_pos(pstate->objlist, 1, True); return 0; } /* * Test whether an object should be loaded into the * Prop Dialog object list */ static BOOL objlist_test_func( ABObj test_obj ) { if ((obj_get_module(test_obj) != NULL) && obj_is_defined(test_obj) && obj_is_salient_ui(test_obj) && obj_has_flag(test_obj, MappedFlag)) { if (cur_list_palitem != NULL) return((*cur_list_palitem->is_a_test)(test_obj)); return(True); } return(False); } static void create_obj_option_item( PropObjOptionsSetting pos, Widget item, ABObj obj ) { Widget newitem; STRING modname = NULL; STRING name = NULL; XmString xmitem; if (obj == NULL) name = (String)NoneItem; else if (pos->display_module) modname = abobj_get_moduled_name(obj); else name = obj_get_name(obj); xmitem = XmStringCreateLocalized(modname? modname : name); if (item == NULL) { /* Create new item */ newitem = XtVaCreateWidget(modname? modname : name, xmPushButtonWidgetClass, pos->options.menu, XmNlabelString, xmitem, XmNuserData, (XtArgVal)obj, NULL); XtAddCallback(newitem, XmNactivateCallback, propP_setting_chgCB, (XtPointer)pos->options.changebar); XtAddCallback(newitem, XmNactivateCallback, propP_options_itemCB, (XtPointer)pos->options.menu); } else /* Use existing item */ XtVaSetValues(item, XmNlabelString, xmitem, XmNuserData, (XtArgVal)obj, NULL); XmStringFree(xmitem); util_free(modname); } /* ****************************************************************** * Object Callbacks ****************************************************************** */ /* * obj-callback: object name has changed - update Prop Dialog lists */ static int obj_renamedOCB( ObjEvAttChangeInfo info ) { PalItemInfo *palitem; int i; if (!obj_is_salient(info->obj) || obj_get_parent(info->obj) == NULL || obj_is_item(info->obj)) return 0; util_dprintf(3, "obj_renamedOCB: from %s to %s\n", istr_string_safe(info->old_name), obj_get_name(info->obj)); if (obj_is_module(info->obj)) /* Module name changed */ { /* Need to update ALL Prop Dialog object lists...*/ for (i = 0; i < palette_item_cnt; i++) { palitem = cur_list_palitem = palette_item[i]; if (palitem->rev_prop_frame == revolv_current_frame) objlist_rename_obj(AB_PROP_REVOLVING, palitem, info); if (palitem->fix_prop_dialog != NULL) objlist_rename_obj(AB_PROP_FIXED, palitem, info); } } else if ((palitem = pal_get_item_info(info->obj)) != NULL) /* Object name changed */ { /* If obj's type is currently loaded in Revolving props, update the list */ if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame) objlist_rename_obj(AB_PROP_REVOLVING, palitem, info); /* If Fixed Props for obj's type exists, update its list */ if (palitem->fix_prop_dialog != NULL) objlist_rename_obj(AB_PROP_FIXED, palitem, info); } return 0; } /* * obj-callback: object geometry has changed - update Prop sheet if necessary */ static int obj_geom_changedOCB( ObjEvAttChangeInfo info ) { PalItemInfo *palitem; PropStateInfo *pstate; unsigned long geomflag = 0; /* If "apply_in_progress" is True, then this update is being called * during the apply of geometry changes within a prop sheet, and we * DO not want to update prop fields in this case because it could * interfere with the apply. */ if (!obj_is_salient(info->obj) || obj_get_parent(info->obj) == NULL || obj_is_item(info->obj) || apply_in_progress) return 0; /* If a layers's position changes, then we need to update the * position attrs of any of its panes which are currently loaded * in props (since, in props, their x,y position is displayed as the * entire layers's position, even though the panes' *real* position * within the layers object is 0,0). */ if (info->atts & OBJEV_ATT_POSITION && obj_is_layers(info->obj)) { ABObj layers = info->obj; ABObj pane; int num_panes = obj_get_num_children(layers); int i; for (i=0; i < num_panes; i++) { /* Use recursion to call this geometry callback for each * pane in the layers object */ pane = obj_get_child(layers, i); info->obj = pane; obj_geom_changedOCB(info); } info->obj = layers; /* reset back to original obj */ } if ((palitem = pal_get_item_info(info->obj)) != NULL) { util_dprintf(3, "obj_geom_changedOCB: %s's geometry changed to %d,%d %dx%d\n", obj_get_name(info->obj), obj_get_x(info->obj), obj_get_y(info->obj), obj_get_width(info->obj), obj_get_height(info->obj)); if (info->atts & OBJEV_ATT_POSITION) geomflag |= LoadPosition; if (info->atts & OBJEV_ATT_SIZE) geomflag |= LoadSize; /* If modified obj is currently loaded in the Revolving prop editor, update * only its geometry attributes in the prop sheet */ if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame) { pstate = get_prop_state_info(AB_rev_prop_dialog); if (pstate->loaded_obj == info->obj) (*(palitem->prop_load))(NULL, AB_PROP_REVOLVING, geomflag); } /* If modified obj is currently loaded in its Fixed prop editor, update * only its geometry attributes in the prop sheet */ if (palitem->fix_prop_dialog != NULL) { pstate = get_prop_state_info(palitem->fix_prop_dialog); if (pstate->loaded_obj == info->obj) (*(palitem->prop_load))(NULL, AB_PROP_FIXED, geomflag); } } return 0; } /* * obj-callback: object is being destroyed - remove from Prop dialog lists */ static int obj_destroyedOCB( ObjEvDestroyInfo info ) { PalItemInfo *palitem; if (!obj_is_salient(info->obj) || obj_get_parent(info->obj) == NULL || obj_is_item(info->obj)) return 0; #ifdef DEBUG { char buf[1024]; util_dprintf(3, "obj_destroyedOCB: %s\n", obj_get_safe_name(info->obj, buf, 1024)); } #endif /* DEBUG */ if ((palitem = pal_get_item_info(info->obj)) != NULL) /* Object being destroyed */ { /* If obj's type is currently loaded in Revolving props, update the list */ if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame) objlist_delete_obj(AB_PROP_REVOLVING, palitem, info); /* If Fixed Props for obj's type exists, update its list */ if (palitem->fix_prop_dialog != NULL) objlist_delete_obj(AB_PROP_FIXED, palitem, info); } return 0; } /* * obj-callback: object being shown or hidden - modify Prop dialog lists */ static int obj_shown_or_hiddenOCB( ObjEvUpdateInfo info ) { PalItemInfo *palitem; int i; if (!obj_is_salient(info->obj) || obj_get_parent(info->obj) == NULL || obj_is_item(info->obj)) return 0; util_dprintf(3, "obj_shown_or_hiddenOCB: %s\n", obj_get_name(info->obj)); if (obj_is_module(info->obj)) { /* Need to update ALL Prop Dialog object lists...*/ for (i = 0; i < palette_item_cnt; i++) { palitem = palette_item[i]; if (palitem->rev_prop_frame == revolv_current_frame) objlist_show_or_hide_obj(AB_PROP_REVOLVING, palitem, info); if (palitem->fix_prop_dialog != NULL) objlist_show_or_hide_obj(AB_PROP_FIXED, palitem, info); } } else if ((palitem = pal_get_item_info(info->obj)) != NULL) /* Object being Updated */ { cur_list_palitem = palitem; /* If obj's type is currently loaded in Revolving props, update the list */ if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame) objlist_show_or_hide_obj(AB_PROP_REVOLVING, palitem, info); /* If Fixed Props for obj's type exists, update its list */ if (palitem->fix_prop_dialog != NULL) objlist_show_or_hide_obj(AB_PROP_FIXED, palitem, info); } return 0; } /* ****************************************************************** * Xt Callbacks ****************************************************************** */ /* * Callback: apply properties for current object */ static void apply_propsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; Widget dialog; if (type == AB_PROP_REVOLVING) dialog = AB_rev_prop_dialog; else /* AB_PROP_FIXED */ { pstate = get_prop_state_info(widget); dialog = pstate->palitem->fix_prop_dialog; } apply_props(type, dialog); } /* * Callback: */ static void cancel_propsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; Widget dialog; pstate = get_prop_state_info(widget); if (type == AB_PROP_REVOLVING) dialog = AB_rev_prop_dialog; else /* AB_PROP_FIXED */ dialog = pstate->palitem->fix_prop_dialog; (*(pstate->palitem->prop_load))(NULL,type,LoadAll); ui_win_show(dialog, False, XtGrabNone); } /* * Callback: a new object has been selected off object menu */ static void change_objecttypeCB( Widget widget, XtPointer client_data, XtPointer calldata ) { PalEditableObjInfo *ed_obj_info = (PalEditableObjInfo*)client_data; PalItemInfo *viz_palitem; PropStateInfo *pstate; viz_palitem = revolv_set_prop_type(ed_obj_info->palitem, NULL); if (viz_palitem == ed_obj_info->palitem) { /* Object-type change was successful */ pstate = get_prop_state_info(AB_rev_prop_dialog); objlist_ensure_selection(pstate->objlist); } else /* Object-type change rejected; reset object-type */ ui_optionmenu_change_label(revolv_optionmenu, viz_palitem->name); } /* * Callback: Prop dialog has been closed -- check for pending changes */ static void close_propsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE; PalItemInfo *palitem = NULL; PropStateInfo *pstate; WidgetList shell_child; Widget dialog; /* Get Immediate child of Shell */ XtVaGetValues(widget, XmNchildren, &shell_child, NULL); dialog = shell_child[0]; pstate = get_prop_state_info(dialog); if ((*(pstate->palitem->prop_pending))(type) == TRUE) /* An Object is loaded with pending changes...*/ answer = handle_auto_apply(type, pstate, pstate->palitem, NULL, &palitem); if (answer != DTB_ANSWER_CANCEL) XtPopdown(widget); } /* * Callback: popup Attachment Editor */ static void invoke_attach_editorCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; pstate = get_prop_state_info(widget); if (pstate->loaded_obj == NULL) return; attch_ed_show_dialog(pstate->loaded_obj); } /* * Callback: popup Connections Editor */ static void invoke_connectionsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; pstate = get_prop_state_info(widget); if (pstate->loaded_obj == NULL) return; conn_set_source(pstate->loaded_obj); conn_set_target(NULL); conn_popup_dialog(widget, (XtPointer)0, NULL); } /* * Callback: popup Help Editor Dialog */ static void invoke_help_editorCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; pstate = get_prop_state_info(widget); if (pstate->loaded_obj == NULL) return; ab_set_help_obj(pstate->loaded_obj); ab_popup_help(widget,(XtPointer)0,NULL); } static void objlist_selectCB( Widget widget, XtPointer client_data, XmListCallbackStruct *listdata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; PalItemInfo *palitem = NULL; ABObj module; ABObj selected_obj; STRING name; pstate = get_prop_state_info(widget); name = objxm_xmstr_to_str(listdata->item); if (name) { abobj_moduled_name_extract(name, &module, &selected_obj); util_free(name); /* If the object selected in the list is the one already * loaded, then don't do anything. */ if (selected_obj && selected_obj != pstate->loaded_obj) { if ((*(pstate->palitem->prop_pending))(type) == TRUE) /* An Object is loaded with pending changes...*/ handle_auto_apply(type, pstate, pstate->palitem, selected_obj, &palitem); else load_props(type, pstate, selected_obj); return; } } } /* * Callback: apply properties for current object & take down dialog */ static void ok_propsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; Widget dialog; if (type == AB_PROP_REVOLVING) dialog = AB_rev_prop_dialog; else /* AB_PROP_FIXED */ { pstate = get_prop_state_info(widget); dialog = pstate->palitem->fix_prop_dialog; } if (apply_props(type, dialog) == OK) ui_win_show(dialog, False, XtGrabNone); } /* * Callback: reset properties for current object */ static void reset_propsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { AB_PROP_TYPE type = (AB_PROP_TYPE)client_data; PropStateInfo *pstate; pstate = get_prop_state_info(widget); (*(pstate->palitem->prop_load))(NULL,type,LoadAll); } /* * Callback: */ static void tearoff_propsCB( Widget widget, XtPointer client_data, XtPointer calldata ) { PropStateInfo *pstate; pstate = get_prop_state_info(AB_rev_prop_dialog); if (pstate->loaded_obj != NULL) prop_load_obj(pstate->loaded_obj, AB_PROP_FIXED); else fixed_invoke_props(pstate->palitem); } static void color_chooserCB( Widget w, XtPointer clientdata, XtPointer calldata ) { PropColorSetting pcs = (PropColorSetting)clientdata; String color_choice; Pixel c; int status; color_choice = display_color_chooser(); if (color_choice[0] != 0) { /* This should never error since the chooser enforces choosing * a valid & available color, but check just to be sure. */ if ((status = objxm_name_to_pixel(w, color_choice, &c)) == OK) { XtVaSetValues(pcs->swatch, XmNbackground, c, NULL); XmTextSetString(pcs->field, color_choice); } } } static void color_noneCB( Widget w, XtPointer clientdata, XtPointer calldata ) { PropColorSetting pcs = (PropColorSetting)clientdata; /* Reset Swatch to appear transparent */ prop_colorfield_set_value(pcs, "", True); } static void menu_newCB( Widget w, XtPointer client_data, XtPointer call_data ) { PropMenunameSetting pms = (PropMenunameSetting)client_data; PropStateInfo *pstate; AB_PROP_TYPE alt_prop_type = AB_PROP_FIXED; ABObj module; Widget prop_dialog = NULL; STRING base = NULL; STRING unique_name; STRING menu_name; STRING name; /* Build a menu-name based on the menu-owner's name or label */ if (pms->owner_name_field != NULL) { /* Use owner's name as prefix */ base = ui_field_get_string(pms->owner_name_field); } module = obj_get_module(*(pms->current_obj_ptr)); name = (base? ab_ident_from_name_and_label(base, "menu") : "menu"); menu_name = strdup(name); unique_name = obj_alloc_unique_name_for_child(module, menu_name, -1); /* We want to create/load the new menu in a separate editor if * possible so that the user can view both the new menu AND the * object which owns it simultaneously. However, if we are currently * in the Fixed Menu Props dialog and there is an object loaded in * the Revolving Prop dialog which has *pending* edits, don't try * to use it (suddently changing it's type & object will probably * confuse the user!). */ if (pms->prop_type == AB_PROP_FIXED) { prop_dialog = ui_get_ancestor_dialog(pms->owner_name_field); /* Try using the Revolving Prop Editor if either we are currently * in the Menu Fixed Props, or if the Menu Fixed Props has * edits pending... */ if (prop_dialog == ab_menu_palitem->fix_prop_dialog || (ab_menu_palitem->fix_prop_dialog && (*ab_menu_palitem->prop_pending)(AB_PROP_FIXED) == True)) { pstate = get_prop_state_info(AB_rev_prop_dialog); if (pstate->palitem && (*pstate->palitem->prop_pending)(AB_PROP_REVOLVING) == False) { alt_prop_type = AB_PROP_REVOLVING; revolv_invoke_props(ab_menu_palitem, NULL); } } } if (alt_prop_type == AB_PROP_FIXED) prop_show_fixed(ab_menu_palitem); /* Insert the new menu name into the owner's field, UNLESS we * happen to be inside the Fixed Menu Prop dialog AND are also * creating the new menu in the Fixed Menu Prop dialog. */ if (pal_create_menu(alt_prop_type, module, unique_name, NULL) == 0 && !(prop_dialog == ab_menu_palitem->fix_prop_dialog && alt_prop_type == AB_PROP_FIXED)) ui_field_set_string(pms->field, unique_name); util_free(base); util_free(menu_name); util_free(unique_name); } static BOOL is_submenu_of( STRING submenu_name, ABObj menu ) { ABObj item; AB_TRAVERSAL trav; BOOL is_sub = False; for(trav_open(&trav, menu, AB_TRAV_ITEMS); (item = trav_next(&trav)) != NULL; ) { if (util_strcmp(obj_get_menu_name(item), submenu_name) == 0) { is_sub = True; break; } } trav_close(&trav); return is_sub; } static void find_submenu_owners( ABObj submenu, ABObj *menulist, int menu_count, ABObj *i_menulist, int *i_count_ptr ) { STRING submenu_name; int i; submenu_name = obj_get_name(submenu); for(i = 0; i < menu_count; i++) { if (submenu != menulist[i] && is_submenu_of(submenu_name, menulist[i])) { i_menulist[(*i_count_ptr)++] = menulist[i]; find_submenu_owners(menulist[i], menulist, menu_count, i_menulist, i_count_ptr); } } } static BOOL menu_in_list( ABObj *menulist, int menu_count, ABObj target_menu ) { int i; for(i = 0; i < menu_count; i++) if (menulist[i] == target_menu) return True; return False; } static void menulist_buildCB( Widget widget, XtPointer client_data, XtPointer call_data ) { PropMenunameSetting pms; ABObj current_obj; ABObj *menus; ABObj *ineligible_menus = NULL; int num_menus = 0; int ineligible_count = 0; Widget submenu; Widget menus_item = (Widget)client_data; Widget menus_menu = NULL; Widget menus_menuitem; Widget menu_field; STRING menu_name; int num_children; int i, j; XtVaGetValues(widget, XmNsubMenuId, &submenu, NULL); XtVaGetValues(menus_item, XmNuserData, &pms, NULL); current_obj = *(pms->current_obj_ptr); abobj_build_menus_array(obj_get_module(current_obj), &menus, &num_menus); if (num_menus > 0) { if (obj_is_menu(current_obj)) /* Need to prevent circular menus */ { /* Build up a list of menus that belong to the current menu's * ancestory (if it's a submenu) - these menus will not be eligible * for selection as a submenu off the current menu. */ ineligible_menus = (ABObj*)util_malloc(num_menus*sizeof(ABObj)); ineligible_menus[ineligible_count++] = current_obj; find_submenu_owners(current_obj, menus, num_menus, ineligible_menus, &ineligible_count); } for (j = 0; j < num_menus; j++) { if (menus_menu == NULL) menus_menu = XmCreatePulldownMenu(submenu, "menus_menu", NULL, 0); menu_name = obj_get_name(menus[j]); menus_menuitem = XtVaCreateManagedWidget("menus_menuitem", xmCascadeButtonWidgetClass, menus_menu, XtVaTypedArg, XmNlabelString, XtRString, menu_name, strlen(menu_name)+1, NULL); /* If Menu is ineligible to be a Submenu, make it inactive */ if (menu_in_list(ineligible_menus, ineligible_count, menus[j])) ui_set_active(menus_menuitem, False); XtAddCallback(menus_menuitem, XmNactivateCallback, menuname_setCB, (XtPointer)pms->field); } ui_set_active(menus_item, TRUE); XtVaSetValues(menus_item, XmNsubMenuId, menus_menu, NULL); XtVaSetValues(submenu, XmNuserData, (XtArgVal)menus_menu, NULL); util_free(menus); util_free(ineligible_menus); } else /* No Menus - inactivate the item */ { ui_set_active(menus_item, FALSE); XtVaSetValues(submenu, XmNuserData, (XtArgVal)NULL, NULL); } } /* * Callback: destroy the Menu->Names submenu after it pops down */ static void menulist_destroyCB( Widget w, XtPointer client_data, XtPointer calldata ) { Widget submenu = (Widget)client_data; Widget menus_menu; XtVaGetValues(submenu, XmNuserData, &menus_menu, NULL); if (menus_menu != NULL) XtDestroyWidget(menus_menu); } static void menu_edit_set_stateCB( Widget widget, XtPointer client_data, XtPointer call_data ) { PropMenunameSetting pms; Widget edit_item = (Widget)client_data; STRING current_menuname = NULL; /* Set the "Edit Current" item to be active ONLY if there is a * menu name in the field */ XtVaGetValues(edit_item, XmNuserData, &pms, NULL); current_menuname = ui_field_get_string(pms->field); ui_set_active(edit_item, !util_strempty(current_menuname)); util_free(current_menuname); } /* * Callback: Clear Menu Name field */ static void menuname_clearCB( Widget w, XtPointer client_data, XtPointer calldata ) { PropMenunameSetting pms = (PropMenunameSetting)client_data; ui_field_set_string(pms->field, ""); } /* * Callback: an item off the Menu->Names submenu was selected: * Set the value of the menu textfield to its label */ static void menuname_setCB( Widget w, XtPointer client_data, XtPointer calldata ) { Widget menu_field = (Widget)client_data; XmString xm_menuname; STRING menu_name; XtVaGetValues(w, XmNlabelString, &xm_menuname, NULL); menu_name = objxm_xmstr_to_str(xm_menuname); ui_field_set_string(menu_field, menu_name); util_free(menu_name); } static void menu_editCB( Widget w, XtPointer client_data, XtPointer call_data ) { PropMenunameSetting pms = (PropMenunameSetting)client_data; STRING current_menuname = NULL; ABObj module; ABObj menu; current_menuname = ui_field_get_string(pms->field); module = obj_get_module(*(pms->current_obj_ptr)); if (!util_strempty(current_menuname)) { if ((menu = obj_find_by_name(module, current_menuname)) != NULL) prop_load_obj(menu, pms->prop_type == AB_PROP_FIXED? AB_PROP_REVOLVING : AB_PROP_FIXED); else { STRING fmtStr = NULL; STRING help_buf = NULL; char Buf[256]; fmtStr = XtNewString(CATGETS(Dtb_project_catd, 100, 135, "The menu with the name \"%s\" does not exist in\nthe module \"%s\". Specify a valid menu name.")); help_buf = (STRING) util_malloc(strlen(fmtStr) + strlen(current_menuname) + strlen(obj_get_name(module)) +1); sprintf(help_buf, fmtStr, current_menuname, obj_get_name(module)); util_set_help_data(help_buf, NULL, NULL); sprintf(Buf, CATGETS(Dtb_project_catd, 100, 134, "Could not find menu \"%s\" in module \"%s\"."), current_menuname, obj_get_name(module)); propP_popup_message(pms->field, Buf, False); XtFree(fmtStr); util_free(help_buf); } } util_free(current_menuname); } static void menu_field_chgCB( Widget w, XtPointer client_data, XtPointer call_data ) { PropMenunameSetting pms = (PropMenunameSetting)client_data; STRING value; BOOL menu_there = False; if (pms->menu_title_pfs) { /* If a non-empty string in in Menu field, make Title active */ value = ui_field_get_string(pms->field); menu_there = (!util_strempty(value)); ui_set_active(pms->menu_title_pfs->label, menu_there); ui_set_active(pms->menu_title_pfs->field, menu_there); util_free(value); } } int prop_geomfield_clear( PropGeometrySetting pgs, GEOM_KEY gkey ) { Widget field = NULL; switch(gkey) { case GEOM_X: field = pgs->x_field; break; case GEOM_Y: field = pgs->y_field; break; case GEOM_WIDTH: field = pgs->w_field; break; case GEOM_HEIGHT: field = pgs->h_field; break; default: field = NULL; } if (field) { /* Set state so changebar is not triggered */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_LOAD,NULL); /* Convert int to string */ ui_field_set_string(field, NULL); /* Reset state */ XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT,NULL); } return OK; } static void obj_options_buildCB( Widget widget, XtPointer client_data, XtPointer call_data ) { PropObjOptionsSetting pos = (PropObjOptionsSetting)client_data; prop_obj_options_load(pos, pos->search_root); } void strings_init(void) { LabelForString = XtNewString(CATGETS(Dtb_project_catd, 100, 215, "Label:")); LabelForGraphic = XtNewString(CATGETS(Dtb_project_catd, 100, 216, "Graphic Filename:")); NoneItem = XtNewString(CATGETS(Dtb_project_catd, 100, 217, "None")); XFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 218, "X Field")); YFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 219, "Y Field")); WFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 220, "Width Field")); HFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 221, "Height Field")); OffsetFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 222, "Offset Field")); PercentageFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 223, "Percentage Field")); menu_strs[0] = XtNewString(CATGETS(Dtb_project_catd, 100, 224, "None")); menu_strs[1] = XtNewString(CATGETS(Dtb_project_catd, 100, 225, "Create New Menu...")); menu_strs[2] = XtNewString(CATGETS(Dtb_project_catd, 100, 226, "Menus")); menu_strs[3] = XtNewString(CATGETS(Dtb_project_catd, 100, 227, "Edit Current...")); RowColFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 250, "Rows/Columns Field")); VertSpacingFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 251, "Vertical Spacing Field")); HorizSpacingFieldStr = XtNewString(CATGETS(Dtb_project_catd, 100, 252, "Horizontal Spacing Field")); }