Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / prop.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *      $XConsortium: prop.c /main/5 1996/08/08 17:57:58 mustafa $
25  *
26  *      @(#)prop.c      1.89 26 Feb 1994
27  *
28  *      RESTRICTED CONFIDENTIAL INFORMATION:
29  *
30  *      The information in this document is subject to special
31  *      restrictions in a confidential disclosure agreement between
32  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
33  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
34  *      Sun's specific written approval.  This document and all copies
35  *      and derivative works thereof must be returned or destroyed at
36  *      Sun's request.
37  *
38  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  *
40  */
41
42
43 /*
44  *****************************************************************
45  * prop.c - Implements all common property sheet functionality
46  *
47  *****************************************************************
48  */
49 #ifndef _POSIX_SOURCE
50 #define _POSIX_SOURCE 1
51 #endif
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <ctype.h>
56 #include <Dt/ComboBox.h>
57 #include <Xm/BulletinB.h>
58 #include <Xm/CascadeB.h>
59 #include <Xm/Form.h>
60 #include <Xm/Frame.h>
61 #include <Xm/Label.h>
62 #include <Xm/List.h>
63 #include <Xm/MessageB.h>
64 #include <Xm/PushB.h>
65 #include <Xm/RowColumn.h>
66 #include <Xm/Separator.h>
67 #include <Xm/Text.h>
68 #include <Xm/TextF.h>
69 #include <Xm/ToggleB.h>
70 #include <ab_private/trav.h>
71 #include <ab_private/obj_notify.h>
72 #include <ab_private/objxm.h>
73 #include <ab_private/ab.h>
74 #include <ab_private/prop.h>
75 #include <ab_private/propP.h>
76 #include <ab_private/proj.h>
77 #include <ab_private/abobj.h>
78 #include <ab_private/abobj_set.h>
79 #include <ab_private/abobj_list.h>
80 #include <ab_private/ui_util.h>
81 #include <ab_private/x_util.h>
82 #include <ab_private/conn.h>
83 #include <ab_private/help.h>
84 #include <ab_private/color_chooser.h>
85 #include <ab_private/attch_ed.h>
86 #include "dtbuilder.h"
87 #include "revolv_ui.h"
88
89 char            *LabelForString = NULL;
90 char            *LabelForGraphic = NULL;
91 char            *NoneItem = NULL;
92
93 char            *XFieldStr = NULL;
94 char            *YFieldStr = NULL;
95 char            *WFieldStr = NULL;
96 char            *HFieldStr = NULL;
97 char            *OffsetFieldStr = NULL;
98 char            *PercentageFieldStr = NULL;
99 char            *RowColFieldStr = NULL;
100 char            *VertSpacingFieldStr = NULL;
101 char            *HorizSpacingFieldStr = NULL;
102
103 static char     *menu_strs[4];
104 static char     *menu_names[] = {"none_item", "new_menu_item", "menus_item", "edit_item"};
105
106 static const char       *Name_ok_test="_";
107
108 typedef struct _PROP_STATE_INFO {
109     PalItemInfo *palitem;
110     Widget      objlist;
111     ABObj       loaded_obj;
112 } PropStateInfo;
113
114
115
116 /*************************************************************************
117 **                                                                      **
118 **       Private Function Declarations                                  **
119 **                                                                      **
120 *************************************************************************/
121                 /* Revolving Dialog Functions
122                  */
123 static void     revolv_dialog_init(
124                     Widget      parent
125                 );
126 static void     revolv_objectspane_init(
127                     DtbRevolvPropDialogInfo     cgen
128                 );
129 static void     revolv_basicframe_init(
130                     DtbRevolvPropDialogInfo     cgen
131                 );
132 static PalItemInfo *
133                 revolv_set_prop_type(
134                     PalItemInfo*        palitem,
135                     ABObj               loadobj
136                 );
137 static void     revolv_change_prop_frame(
138                     PalItemInfo         *palitem
139                 );
140 static PalItemInfo *
141                 revolv_invoke_props(
142                     PalItemInfo         *palitem,
143                     ABObj               loadobj
144                 );
145
146
147                 /* Fixed Dialog Functions
148                  */
149 static void
150                 fixed_invoke_props(
151                     PalItemInfo         *palitem
152                 );
153
154                 /* General Prop Manipulation Functions
155                  */
156 static int      apply_props(
157                     AB_PROP_TYPE        ptype,
158                     Widget              dialog
159                 );
160 static int      apply_prop_changes(
161                     AB_PROP_TYPE        ptype,
162                     ABObj               obj,
163                     PalItemInfo         *palitem
164                 );
165 static DTB_MODAL_ANSWER
166                 handle_auto_apply(
167                     AB_PROP_TYPE        ptype,
168                     PropStateInfo       *pstate,
169                     PalItemInfo         *new_palitem,
170                     ABObj               new_obj,
171                     PalItemInfo         **result
172                 );
173 static PropStateInfo *
174                 get_prop_state_info(
175                     Widget              widget
176                 );
177 static void     init_prop_state_info(
178                     Widget              dialog,
179                     PalItemInfo         *palitem,
180                     Widget              objlist,
181                     ABObj               loaded_obj
182                 );
183 static void     load_props(
184                     AB_PROP_TYPE        ptype,
185                     PropStateInfo       *pstate,
186                     ABObj               obj
187                 );
188 static void     create_obj_option_item(
189                     PropObjOptionsSetting       pos,
190                     Widget                      item,
191                     ABObj                       obj
192                 );
193
194                 /* Object List Manipulation Functions
195                  */
196 static int      objlist_delete_obj(
197                     AB_PROP_TYPE        type,
198                     PalItemInfo         *palitem,
199                     ObjEvDestroyInfo    info
200                 );
201 static void     objlist_ensure_selection(
202                     Widget              objlist
203                 );
204 static void     objlist_load(
205                     AB_PROP_TYPE        type,
206                     PropStateInfo       *pstate
207                 );
208 static int      objlist_rename_obj(
209                     AB_PROP_TYPE        type,
210                     PalItemInfo         *palitem,
211                     ObjEvAttChangeInfo  info
212                 );
213 static int      objlist_show_or_hide_obj(
214                     AB_PROP_TYPE        type,
215                     PalItemInfo         *palitem,
216                     ObjEvUpdateInfo     info
217                 );
218 static BOOL     objlist_test_func(
219                     ABObj       test_obj
220                 );
221
222
223 /*
224  * Object-Callbacks
225  */
226 static int      obj_renamedOCB(
227                     ObjEvAttChangeInfo  info
228                 );
229 static int      obj_shown_or_hiddenOCB(
230                     ObjEvUpdateInfo     info
231                 );
232 static int      obj_geom_changedOCB(
233                     ObjEvAttChangeInfo  info
234                 );
235 static int      obj_destroyedOCB(
236                     ObjEvDestroyInfo    info
237                 );
238
239 /*
240  * Xt-Callbacks
241  */
242                 /* General Prop Callbacks
243                  */
244 static void     apply_propsCB(
245                     Widget      w,
246                     XtPointer   clientdata,
247                     XtPointer   calldata
248                 );
249 static void     cancel_propsCB(
250                     Widget      w,
251                     XtPointer   clientdata,
252                     XtPointer   calldata
253                 );
254 static void     change_objecttypeCB(
255                     Widget      w,
256                     XtPointer   clientdata,
257                     XtPointer   calldata
258                 );
259 static void     close_propsCB(
260                     Widget      w,
261                     XtPointer   clientdata,
262                     XtPointer   calldata
263                 );
264 static void     invoke_attach_editorCB(
265                     Widget      w,
266                     XtPointer   cldata,
267                     XtPointer   calldata
268                 );
269 static void     invoke_connectionsCB(
270                     Widget      w,
271                     XtPointer   cldata,
272                     XtPointer   calldata
273                 );
274 static void     invoke_help_editorCB(
275                     Widget      w,
276                     XtPointer   cldata,
277                     XtPointer   calldata
278                 );
279 static void     objlist_selectCB(
280                     Widget      widget,
281                     XtPointer   client_data,
282                     XmListCallbackStruct *listdata
283                 );
284 static void     ok_propsCB(
285                     Widget      w,
286                     XtPointer   clientdata,
287                     XtPointer   calldata
288                 );
289 static void     reset_propsCB(
290                     Widget      w,
291                     XtPointer   clientdata,
292                     XtPointer   calldata
293                 );
294 static void     tearoff_propsCB(
295                     Widget      w,
296                     XtPointer   clientdata,
297                     XtPointer   calldata
298                 );
299
300                 /* Color Field Callbacks
301                  */
302 static void     color_chooserCB(
303                     Widget   widget,
304                     XtPointer clientdata,
305                     XtPointer calldata
306                 );
307 static void     color_noneCB(
308                     Widget   widget,
309                     XtPointer clientdata,
310                     XtPointer calldata
311                 );
312
313                 /* Menu Name Setting Callbacks
314                  */
315 static void     menu_newCB(
316                     Widget      widget,
317                     XtPointer   client_data,
318                     XtPointer   call_data
319                 );
320 static void     menu_editCB(
321                     Widget      widget,
322                     XtPointer   client_data,
323                     XtPointer   call_data
324                 );
325 static void     menu_edit_set_stateCB(
326                     Widget      widget,
327                     XtPointer   client_data,
328                     XtPointer   call_data
329                 );
330 static void     menulist_buildCB(
331                     Widget      widget,
332                     XtPointer   client_data,
333                     XtPointer   call_data
334                 );
335 static void     menulist_destroyCB(
336                     Widget      widget,
337                     XtPointer   client_data,
338                     XtPointer   call_data
339                 );
340 static void     menuname_clearCB(
341                     Widget   widget,
342                     XtPointer clientdata,
343                     XtPointer calldata
344                 );
345 static void     menuname_setCB(
346                     Widget      widget,
347                     XtPointer   client_data,
348                     XtPointer   call_data
349                 );
350 static void     menu_field_chgCB(
351                     Widget      widget,
352                     XtPointer   client_data,
353                     XtPointer   call_data
354                 );
355
356 static void     obj_options_buildCB(
357                     Widget      widget,
358                     XtPointer   client_data,
359                     XtPointer   call_data
360                 );
361
362 /*
363  * Misc Functions
364  */
365 static void     find_submenu_owners(
366                     ABObj       submenu,
367                     ABObj       *menulist,
368                     int         menu_count,
369                     ABObj       *i_menulist,
370                     int         *i_count_ptr
371                 );
372 static BOOL     is_submenu_of(
373                     STRING      submenu_name,
374                     ABObj       menu
375                 );
376 static BOOL     menu_in_list(
377                     ABObj        *menulist,
378                     int          menu_count,
379                     ABObj        target_menu
380                 );
381
382 static void strings_init(
383                 );
384
385
386 /*************************************************************************
387 **                                                                      **
388 **       Data Declarations                                              **
389 **                                                                      **
390 *************************************************************************/
391 extern PalItemInfo*     palette_item[];
392 extern int              palette_item_cnt;
393 extern PalItemInfo      *ab_menu_palitem;
394 extern PalItemInfo      *ab_group_palitem;
395
396 static PalItemInfo      *cur_list_palitem = NULL;
397 static Widget           revolv_current_frame = NULL;
398 static Widget           revolv_optionmenu   = NULL;
399 static BOOL             apply_in_progress = False;
400
401 static char      Buf[512];
402
403 /*************************************************************************
404 **                                                                      **
405 **       Function Definitions                                           **
406 **                                                                      **
407 *************************************************************************/
408
409 /*
410  * Initialize Props:
411  *      Create Revolving Prop dialog
412  *      Add callbacks for object rename & destroy
413  */
414 void
415 prop_init(
416     Widget      toplevel
417 )
418 {
419     strings_init();
420
421     revolv_dialog_init(toplevel);
422
423     obj_add_rename_callback(obj_renamedOCB, "PROPS");
424     obj_add_update_callback(obj_shown_or_hiddenOCB, "PROPS");
425     obj_add_geometry_change_callback(obj_geom_changedOCB, "PROPS");
426     obj_add_destroy_callback(obj_destroyedOCB, "PROPS");
427 }
428
429 /*
430  * Popup the Revolving Prop dialog.
431  * If an object is currently selected,  Set the
432  * corresponding revolving prop-type and Load the object
433  */
434 void
435 prop_show_dialog(
436     Widget      widget,
437     XtPointer   client_data,
438     XtPointer   call_data
439 )
440 {
441     ABSelectedRec sel;
442     PalItemInfo   *palitem = NULL;
443     PropStateInfo *pstate;
444
445     ab_set_busy_cursor(TRUE);
446
447     abobj_get_selected(proj_get_project(), FALSE, FALSE, &sel);
448     if (sel.count > 0)
449     {
450         palitem = pal_get_item_info(sel.list[0]);
451         util_free(sel.list);
452     }
453     /* If no objects selected, set to First type */
454     if (palitem == NULL)
455         palitem = palette_item[0];
456
457     revolv_invoke_props(palitem, NULL);
458     pstate = get_prop_state_info(AB_rev_prop_dialog);
459     objlist_ensure_selection(pstate->objlist);
460
461     ab_set_busy_cursor(FALSE);
462 }
463
464 /*
465  * Popup the Fixed Prop dialog for the specified
466  * Palette Item type.
467  */
468 void
469 prop_show_fixed(
470     PalItemInfo *palitem
471 )
472 {
473     PropStateInfo *pstate;
474
475     ab_set_busy_cursor(TRUE);
476
477     fixed_invoke_props(palitem);
478     pstate = get_prop_state_info(palitem->fix_prop_dialog);
479     objlist_ensure_selection(pstate->objlist);
480
481     ab_set_busy_cursor(FALSE);
482 }
483
484 /*
485  * Popup the Fixed Prop dialog for Menus
486  */
487 void
488 prop_show_menu_props(
489     Widget      w,
490     XtPointer   client_data,
491     XtPointer   calldata
492 )
493 {
494     prop_show_fixed(ab_menu_palitem);
495 }
496
497 /*
498  * Popup the Fixed Group dialog for menus.
499  */
500 void
501 prop_show_group_props(
502     Widget      w,
503     XtPointer   client_data,
504     XtPointer   calldata
505 )
506 {
507
508     prop_show_fixed(ab_group_palitem);
509
510 }
511
512 /*
513  * Load an object into the Prop dialog of the
514  * specified prop type (Revolving or Fixed).
515  */
516 void
517 prop_load_obj(
518     ABObj       obj,
519     AB_PROP_TYPE ptype
520 )
521 {
522     PalItemInfo *palitem;
523     PalItemInfo *viz_palitem;
524     Widget      dialog;
525     PropStateInfo *pstate;
526     STRING      modname = NULL;
527
528     if (obj_is_module(obj) || obj_is_project(obj))
529         return;
530
531     ab_set_busy_cursor(TRUE);
532
533     if (obj_is_item(obj))
534         obj = obj_get_parent(obj);
535
536     obj = obj_get_root(obj);
537
538     if ((viz_palitem = palitem = pal_get_item_info(obj)) != NULL)
539     {
540         if (ptype == AB_PROP_REVOLVING)
541         {
542             viz_palitem = revolv_invoke_props(palitem, obj);
543             dialog = AB_rev_prop_dialog;
544         }
545         else /* AB_PROP_FIXED */
546         {
547             fixed_invoke_props(palitem);
548             dialog = palitem->fix_prop_dialog;
549         }
550
551         pstate = get_prop_state_info(dialog);
552         modname = abobj_get_moduled_name(obj);
553     }
554     else
555         util_dprintf(1,"prop_load_obj: %s : could not get Palette info\n",
556                 util_strsafe(obj_get_name(obj)));
557
558     ab_set_busy_cursor(FALSE);
559
560     if (dialog != NULL && modname != NULL && viz_palitem == palitem)
561     {
562         ui_list_select_item(pstate->objlist, modname, TRUE);
563         util_free(modname);
564     }
565
566 }
567 void
568 prop_fixed_dialog_init(
569     PalItemInfo *palitem,
570     Widget      dialog,
571     Widget      objlist
572 )
573 {
574     Widget      shell = XtParent(dialog);
575
576     init_prop_state_info(dialog, palitem, objlist, NULL);
577
578     /* The initial position of a Fixed Prop dialog is dependent on
579      * how it is invoked and whether the Revolving Prop editor is up,
580      * so don't specify an initial position relative to the palette.
581      */
582     ab_register_window(dialog, AB_WIN_DIALOG, WindowHidden,
583                 NULL, AB_WPOS_UNSPECIFIED,
584                 close_propsCB, (XtPointer)AB_PROP_FIXED);
585
586     /* Store current-object in List (init to NULL)  */
587     XtVaSetValues(objlist,
588                 XmNselectionPolicy,     XmBROWSE_SELECT,
589                 XmNuserData,            NULL,
590                 NULL);
591
592     XtAddCallback(objlist, XmNbrowseSelectionCallback,
593             (XtCallbackProc)objlist_selectCB, (XtPointer)AB_PROP_FIXED);
594
595 }
596
597 void
598 prop_activate_panel_init(
599     AB_PROP_TYPE type,
600     PalItemInfo *palitem,
601     Widget      ok_button,
602     Widget      apply_button,
603     Widget      reset_button,
604     Widget      cancel_button,
605     Widget      help_button
606 )
607 {
608     Widget      dialog;
609
610     /* Ensure "Apply" is default button */
611     dialog = ui_get_ancestor_dialog(apply_button);
612     XtVaSetValues(dialog, XmNdefaultButton, apply_button, NULL);
613
614     XtVaSetValues(apply_button,
615                 XmNshowAsDefault, True,
616                 XmNdefaultButtonShadowThickness, 1,
617                 NULL);
618     XtVaSetValues(ok_button,
619                 XmNdefaultButtonShadowThickness, 1,
620                 NULL);
621     XtVaSetValues(reset_button,
622                 XmNdefaultButtonShadowThickness, 1,
623                 NULL);
624     XtVaSetValues(cancel_button,
625                 XmNdefaultButtonShadowThickness, 1,
626                 NULL);
627     if (help_button != NULL)
628         XtVaSetValues(help_button,
629                 XmNdefaultButtonShadowThickness, 1,
630                 NULL);
631
632     XtAddCallback(apply_button, XmNactivateCallback, apply_propsCB, (XtPointer)type);
633     XtAddCallback(reset_button, XmNactivateCallback, reset_propsCB, (XtPointer)type);
634     XtAddCallback(ok_button,    XmNactivateCallback, ok_propsCB,    (XtPointer)type);
635     XtAddCallback(cancel_button,XmNactivateCallback, cancel_propsCB,(XtPointer)type);
636
637 }
638
639 void
640 prop_editors_panel_init(
641     AB_PROP_TYPE type,
642     PalItemInfo *palitem,
643     Widget      attach_ed_button,
644     Widget      conn_ed_button,
645     Widget      help_ed_button
646 )
647 {
648     if (attach_ed_button)
649     {
650         XtAddCallback(attach_ed_button, XmNactivateCallback,
651                         invoke_attach_editorCB, (XtPointer)type);
652
653     }
654     if (conn_ed_button)
655     {
656         XtAddCallback(conn_ed_button, XmNactivateCallback,
657                         invoke_connectionsCB, (XtPointer)type);
658
659     }
660     if (help_ed_button)
661     {
662         XtAddCallback(help_ed_button, XmNactivateCallback,
663                         invoke_help_editorCB, (XtPointer)type);
664
665     }
666
667 }
668
669
670 void
671 prop_checkbox_init(
672     PropCheckboxSetting pcs,
673     Widget              label,
674     Widget              checkbox,
675     int                 num_items,
676     WidgetList          items,
677     int                 *item_keys,
678     Widget              changebar
679 )
680 {
681     int i;
682
683     /* Store Widget-IDs */
684     pcs->label = label;
685     pcs->checkbox = checkbox;
686     pcs->changebar = changebar;
687
688     propP_changebar_init(changebar, checkbox);
689
690     for (i=0; i < num_items; i++)
691     {
692         XtVaSetValues(items[i], XmNuserData, (XtArgVal)item_keys[i], NULL);
693         XtAddCallback(items[i], XmNvalueChangedCallback,
694                         propP_setting_chgCB, (XtPointer)changebar);
695     }
696 }
697
698 int
699 prop_checkbox_set_value(
700     PropCheckboxSetting pcs,
701     int                 itemkey,
702     BOOL                value,
703     BOOL                trip_changebar
704 )
705 {
706     int         num_children = 0;
707     WidgetList  children = NULL;
708     XtArgVal    childkey;
709     int         i;
710
711     XtVaGetValues(pcs->checkbox,
712         XtNnumChildren, &num_children,
713         XtNchildren,    &children,
714         NULL);
715
716     for (i=0; i < num_children; i++)
717     {
718         XtVaGetValues(children[i], XmNuserData, &childkey, NULL);
719         if (childkey == itemkey) /* Found it */
720         {
721             XmToggleButtonSetState(children[i], value, trip_changebar? TRUE : FALSE);
722             return OK;
723         }
724     }
725     /* Item not found in checkbox */
726     util_dprintf(1,"prop_checkbox_set_value: invalid item key\n");
727     return ERROR;
728 }
729
730 BOOL
731 prop_checkbox_get_value(
732     PropCheckboxSetting pcs,
733     int                 itemkey
734 )
735 {
736     int         num_children = 0;
737     WidgetList  children = NULL;
738     XtArgVal    childkey;
739     int         i;
740
741     XtVaGetValues(pcs->checkbox,
742         XtNnumChildren, &num_children,
743         XtNchildren,    &children,
744         NULL);
745
746     for (i=0; i < num_children; i++)
747     {
748         XtVaGetValues(children[i], XmNuserData, &childkey, NULL);
749         if (childkey == itemkey) /* Found it */
750             return((BOOL)XmToggleButtonGetState(children[i]));
751     }
752
753     /* itemkey was not found */
754     util_dprintf(1, "prop_checkbox_get_value: invalid item key\n");
755     return FALSE;
756 }
757
758 void
759 prop_colorfield_init(
760     PropColorSetting    pcs,
761     Widget              menubutton,
762     Widget              none_item,
763     Widget              chooser_item,
764     Widget              swatch,
765     Widget              field,
766     Widget              changebar
767 )
768 {
769     Pixel       contrast_pix, default_pix;
770     char        swatch_name[128];
771
772     /* Store Widget-IDs */
773     pcs->menubutton = menubutton;
774     pcs->swatch = swatch;
775     pcs->field = field;
776     pcs->changebar = changebar;
777
778     XtAddCallback(chooser_item, XmNactivateCallback,
779         color_chooserCB, (XtPointer)pcs);
780
781     XtAddCallback(none_item, XmNactivateCallback,
782         color_noneCB, (XtPointer)pcs);
783
784     /* Determine whether this is a foreground or background color field
785      * and store the corresponding color-default in user-data.
786      */
787     strcpy(swatch_name, XtName(swatch));
788     if (strstr(swatch_name, "bg"))
789         default_pix = WhitePixelOfScreen(XtScreen(swatch));
790     else
791         default_pix = BlackPixelOfScreen(XtScreen(swatch));
792
793     /* Ensure Swatch's border is contrast to prop sheet */
794     XtVaGetValues(XtParent(changebar),
795                         XmNforeground,  &contrast_pix,
796                         NULL);
797     XtVaSetValues(swatch,
798                 XmNborderColor,   (XtArgVal)contrast_pix,
799                 XmNborderWidth,   (XtArgVal)1,
800                 XmNuserData,      (XtArgVal)default_pix,
801                 XmNrecomputeSize, (XtArgVal)False,
802                 NULL);
803
804     strcpy(swatch_name, XtName(swatch));
805
806     /* Setup Prop Sheet changebar mechanism */
807     propP_changebar_init(changebar, menubutton);
808
809     XtAddCallback(field, XmNvalueChangedCallback,
810                 propP_field_chgCB, (XtPointer)changebar);
811
812 }
813
814 STRING
815 prop_colorfield_get_value(
816     PropColorSetting    pcs
817 )
818 {
819     STRING      value;
820
821     value = ui_field_get_string(pcs->field);
822
823     return value;
824 }
825
826 int
827 prop_colorfield_set_value(
828     PropColorSetting    pcs,
829     STRING              colorname,
830     BOOL                trip_changebar
831 )
832 {
833     Pixel               pixel;
834
835     if (util_strempty(colorname)) /* no color - swatch is 'invisible' */
836         XtVaGetValues(XtParent(pcs->swatch), XmNbackground, &pixel, NULL);
837
838     else if (objxm_name_to_pixel(AB_toplevel, colorname, &pixel) != OK)
839     {
840         if (objxm_color_exists(colorname)) /* color couldn't be allocated */
841         {
842             /* Set swatch color to default black or white */
843             XtVaGetValues(pcs->swatch, XmNuserData, &pixel, NULL);
844         }
845         else /* Invalid color name - this should not happen */
846         {
847             util_dprintf(1, "prop_colorfield_set_value: \"%s\" is not an existing color name.\n",
848                 colorname);
849             return ERR;
850         }
851     }
852     XtVaSetValues(pcs->swatch,
853         XmNbackground,  (XtArgVal)pixel,
854         NULL);
855
856     if (!trip_changebar)
857         /* Set state so changebar is not triggered */
858         XtVaSetValues(pcs->field, XmNuserData, (XtArgVal)PROP_LOAD, NULL);
859
860     /* Set field value */
861     ui_field_set_string(pcs->field, colorname);
862
863     if (!trip_changebar)
864         /* Reset state */
865         XtVaSetValues(pcs->field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
866
867     return OK;
868
869 }
870
871 void
872 prop_obj_combobox_init(
873     PropObjComboboxSetting pcs,
874     Widget              label,
875     Widget              combobox,
876     Widget              changebar,
877     ABObj               *current_obj_ptr
878 )
879 {
880
881     /* Store Widget-IDs */
882     pcs->label = label;
883     pcs->combobox = combobox;
884     pcs->changebar = changebar;
885     pcs->list = ui_combobox_get_list_widget(combobox);
886     pcs->current_obj_ptr = current_obj_ptr;
887
888     /* Setup Prop Sheet changebar mechanism */
889     propP_changebar_init(changebar, combobox);
890
891     /* Load "None" Item */
892     prop_obj_combobox_load(pcs, NULL, NULL);
893
894     XtAddCallback(combobox, DtNselectionCallback, propP_combobox_chgCB,
895                 (XtPointer)pcs);
896
897 }
898
899 ABObj
900 prop_obj_combobox_get_value(
901     PropObjComboboxSetting pcs
902 )
903 {
904     ABObj               obj;
905     STRING              name;
906     XmStringTable       selected;
907     int                 select_count = 0;
908
909     XtVaGetValues(pcs->list,
910         XmNselectedItems, &selected,
911         XmNselectedItemCount, &select_count,
912         NULL);
913
914     if (select_count == 0)
915     {
916         util_dprintf(1, "prop_obj_combobox_get_value: No items select in List\n");
917         return NULL;
918     }
919     name = objxm_xmstr_to_str(selected[0]);
920
921     if (util_strcmp(name, NoneItem) != 0)
922         obj = obj_find_by_name(obj_get_module(*pcs->current_obj_ptr), name);
923     else
924         obj = NULL; /* "None" was selected */
925
926     util_free(name);
927
928     return obj;
929 }
930
931 int
932 prop_obj_combobox_set_value(
933     PropObjComboboxSetting pcs,
934     ABObj                  obj,
935     BOOL                   trip_changebar
936 )
937 {
938     ui_combobox_select_item(pcs->combobox,
939                 (STRING)(obj? obj_get_name(obj) : NoneItem));
940     prop_set_changebar(pcs->changebar, trip_changebar? PROP_CB_ON : PROP_CB_OFF);
941
942     return 0;
943 }
944
945 void
946 prop_obj_combobox_load(
947     PropObjComboboxSetting pcs,
948     ABObj                  root,
949     ABObjTestFunc          obj_test_func
950 )
951 {
952     AB_TRAVERSAL        trav;
953     ABObj               obj;
954
955     ui_combobox_clear(pcs->combobox);
956     ui_combobox_add_item(pcs->combobox, (STRING)NoneItem, 0, False);
957
958     if (root != NULL)
959     {
960         for (trav_open(&trav, root, AB_TRAV_SALIENT_UI);
961             (obj= trav_next(&trav)) != NULL; )
962             if ((*obj_test_func)(obj) == True)
963                 ui_combobox_add_item(pcs->combobox, obj_get_name(obj), 0, False);
964
965         trav_close(&trav);
966     }
967 }
968
969 void
970 prop_field_init(
971     PropFieldSetting    pfs,
972     Widget              label,
973     Widget              field,
974     Widget              changebar
975 )
976 {
977     /* Store Widget-IDs */
978     pfs->label = label;
979     pfs->field = field;
980     pfs->changebar = changebar;
981
982     /* Setup Prop Sheet changebar mechanism */
983     XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
984     propP_changebar_init(changebar, field);
985
986     XtAddCallback(field, XmNvalueChangedCallback,
987                 propP_field_chgCB, (XtPointer)changebar);
988
989 }
990
991 STRING
992 prop_field_get_value(
993     PropFieldSetting    pfs
994 )
995 {
996     STRING      value;
997
998     value = ui_field_get_string(pfs->field);
999
1000     return value;
1001 }
1002
1003 int
1004 prop_field_set_value(
1005     PropFieldSetting    pfs,
1006     STRING              value,
1007     BOOL                trip_changebar
1008 )
1009 {
1010     return(propP_field_set_value(pfs->field, value, trip_changebar));
1011 }
1012
1013 int
1014 prop_field_get_numeric_value(
1015     PropFieldSetting    pfs
1016 )
1017 {
1018     STRING      value;
1019     int         num;
1020
1021     value = ui_field_get_string(pfs->field);
1022     num = prop_str_to_int(value);
1023     util_free(value);
1024
1025     return num;
1026 }
1027
1028 int
1029 prop_field_set_numeric_value(
1030     PropFieldSetting    pfs,
1031     int                 value,
1032     BOOL                trip_changebar
1033 )
1034 {
1035     char valstr[8];
1036
1037     if (!trip_changebar)
1038         /* Set state so changebar is not triggered */
1039         XtVaSetValues(pfs->field, XmNuserData, (XtArgVal)PROP_LOAD, NULL);
1040
1041     /* Convert int to string */
1042     sprintf(valstr, "%d", value);
1043     ui_field_set_string(pfs->field, valstr);
1044
1045     if (!trip_changebar)
1046         /* Reset state */
1047         XtVaSetValues(pfs->field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1048
1049     return OK;
1050 }
1051
1052 void
1053 prop_footer_init(
1054     PropFooterSetting    pfs,
1055     Widget              label,
1056     Widget              checkbox,
1057     int                 num_items,
1058     WidgetList          items,
1059     int                 *item_keys,
1060     Widget              field,
1061     Widget              changebar
1062 )
1063 {
1064     int i;
1065
1066     /* Store Widget-IDs */
1067     pfs->label = label;
1068     pfs->checkbox = checkbox;
1069     pfs->field = field;
1070     pfs->changebar = changebar;
1071
1072     /* Setup Prop Sheet changebar mechanism */
1073     XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1074     propP_changebar_init(changebar, checkbox);
1075
1076     XtAddCallback(field, XmNvalueChangedCallback,
1077                 propP_field_chgCB, (XtPointer)changebar);
1078
1079     for (i=0; i < num_items; i++)
1080     {
1081         XtVaSetValues(items[i], XmNuserData, (XtArgVal)item_keys[i], NULL);
1082         XtAddCallback(items[i], XmNvalueChangedCallback,
1083                         propP_setting_chgCB, (XtPointer)changebar);
1084     }
1085
1086 }
1087
1088 void
1089 prop_geomfield_init(
1090     PropGeometrySetting pgs,
1091     Widget              label,
1092     Widget              x_label,
1093     Widget              x_field,
1094     Widget              y_label,
1095     Widget              y_field,
1096     Widget              w_label,
1097     Widget              w_field,
1098     Widget              h_label,
1099     Widget              h_field,
1100     Widget              changebar
1101 )
1102 {
1103     /* Store Widget-IDs */
1104     pgs->label = label;
1105     pgs->x_label = x_label;
1106     pgs->x_field = x_field;
1107     pgs->y_label = y_label;
1108     pgs->y_field = y_field;
1109     pgs->w_label = w_label;
1110     pgs->w_field = w_field;
1111     pgs->h_label = h_label;
1112     pgs->h_field = h_field;
1113     pgs->changebar = changebar;
1114
1115     /* Setup Prop Sheet changebar mechanism */
1116     propP_changebar_init(changebar,
1117         x_field? x_field : (y_field? y_field : (w_field? w_field : h_field)));
1118
1119     if (x_field != NULL)
1120     {
1121         XtVaSetValues(x_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1122         XtAddCallback(x_field, XmNvalueChangedCallback,
1123                         propP_field_chgCB, (XtPointer)changebar);
1124     }
1125     if (y_field != NULL)
1126     {
1127         XtVaSetValues(y_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1128         XtAddCallback(y_field, XmNvalueChangedCallback,
1129                         propP_field_chgCB, (XtPointer)changebar);
1130     }
1131     if (h_field != NULL)
1132     {
1133         XtVaSetValues(h_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1134         XtAddCallback(h_field, XmNvalueChangedCallback,
1135                         propP_field_chgCB, (XtPointer)changebar);
1136     }
1137     if (w_field != NULL)
1138     {
1139         XtVaSetValues(w_field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1140         XtAddCallback(w_field, XmNvalueChangedCallback,
1141                         propP_field_chgCB, (XtPointer)changebar);
1142     }
1143
1144 }
1145
1146 int
1147 prop_geomfield_get_value(
1148     PropGeometrySetting pgs,
1149     GEOM_KEY            gkey
1150 )
1151 {
1152     Widget      field;
1153     STRING      value;
1154     int         gvalue = 0;
1155
1156     switch(gkey)
1157     {
1158         case GEOM_X:
1159             field = pgs->x_field;
1160             break;
1161         case GEOM_Y:
1162             field = pgs->y_field;
1163             break;
1164         case GEOM_WIDTH:
1165             field = pgs->w_field;
1166             break;
1167         case GEOM_HEIGHT:
1168             field = pgs->h_field;
1169             break;
1170         default:
1171             field = NULL;
1172     }
1173     if (field)
1174     {
1175         value = ui_field_get_string(field);
1176         gvalue = prop_str_to_int(value);
1177         util_free(value);
1178     }
1179     return gvalue;
1180 }
1181
1182 int
1183 prop_geomfield_set_value(
1184     PropGeometrySetting pgs,
1185     GEOM_KEY            gkey,
1186     int                 gvalue,
1187     BOOL                trip_changebar
1188 )
1189 {
1190     Widget      field;
1191
1192     switch(gkey)
1193     {
1194         case GEOM_X:
1195             field = pgs->x_field;
1196             break;
1197         case GEOM_Y:
1198             field = pgs->y_field;
1199             break;
1200         case GEOM_WIDTH:
1201             field = pgs->w_field;
1202             break;
1203         case GEOM_HEIGHT:
1204             field = pgs->h_field;
1205             break;
1206         default:
1207             field = NULL;
1208     }
1209     if (field)
1210         propP_field_set_numeric_value(field, gvalue, trip_changebar);
1211
1212     return OK;
1213 }
1214
1215 void
1216 prop_load_obj_position(
1217     ABObj               obj,
1218     PropGeometrySetting pgs
1219 )
1220 {
1221     BOOL        movable = abobj_is_movable(obj);
1222
1223     prop_geomfield_set_value(pgs, GEOM_X, abobj_get_comp_x(obj), False);
1224     prop_geomfield_set_value(pgs, GEOM_Y, abobj_get_comp_y(obj), False);
1225
1226     ui_set_active(pgs->x_field, movable);
1227     ui_set_active(pgs->x_label, movable);
1228     ui_set_active(pgs->y_field, movable);
1229     ui_set_active(pgs->y_label, movable);
1230 }
1231
1232 void
1233 prop_load_obj_size(
1234     ABObj               obj,
1235     PropGeometrySetting pgs
1236 )
1237 {
1238     BOOL resizable;
1239
1240     if (pgs->w_field)
1241     {
1242         prop_geomfield_set_value(pgs, GEOM_WIDTH, abobj_get_comp_width(obj), False);
1243         resizable =  abobj_width_resizable(obj);
1244         ui_set_active(pgs->w_field, resizable);
1245         ui_set_active(pgs->w_label, resizable);
1246     }
1247     if (pgs->h_field)
1248     {
1249         prop_geomfield_set_value(pgs, GEOM_HEIGHT, abobj_get_comp_height(obj), False);
1250         resizable =  abobj_height_resizable(obj);
1251         ui_set_active(pgs->h_field, resizable);
1252         ui_set_active(pgs->h_label, resizable);
1253     }
1254 }
1255
1256 void
1257 prop_size_policyCB(
1258     Widget      w,
1259     XtPointer   clientdata,
1260     XtPointer   calldata
1261 )
1262 {
1263     XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct*)calldata;
1264     PropGeometrySetting         pgs = (PropGeometrySetting)clientdata;
1265     XtArgVal                    value;
1266     BOOL                        active = False;
1267
1268     if (state->set)
1269     {
1270         XtVaGetValues(w, XmNuserData, &value, NULL);
1271         active = (value == SIZE_FIXED_KEY);
1272         if (pgs->w_label)
1273             ui_set_active(pgs->w_label, active);
1274         if (pgs->w_field)
1275             ui_set_active(pgs->w_field, active);
1276         if (pgs->h_label)
1277             ui_set_active(pgs->h_label, active);
1278         if (pgs->h_field)
1279             ui_set_active(pgs->h_field, active);
1280     }
1281 }
1282
1283 #define NO_MENU         0
1284 #define NEW_MENU        1
1285 #define MENUS           2
1286 #define EDIT_MENU       3
1287
1288 void
1289 prop_menuname_init(
1290     PropMenunameSetting pms,
1291     AB_PROP_TYPE        ptype,
1292     Widget              label,
1293     Widget              menubutton,
1294     Widget              field,
1295     Widget              owner_name_field,
1296     Widget              changebar,
1297     PropFieldSetting    menu_title_pfs,
1298     ABObj               *current_obj_ptr,
1299     BOOL                new_item_ok
1300 )
1301 {
1302     Widget      submenu;
1303     Widget      menu_items[4];
1304     int         i;
1305
1306     pms->prop_type = ptype;
1307     pms->label = label;
1308     pms->menubutton = menubutton;
1309     pms->field = field;
1310     pms->owner_name_field = owner_name_field;
1311     pms->changebar = changebar;
1312     pms->menu_title_pfs = menu_title_pfs;
1313     pms->current_obj_ptr = current_obj_ptr;
1314
1315     /* Setup Prop Sheet changebar mechanism */
1316     XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1317     propP_changebar_init(changebar, field);
1318
1319     XtAddCallback(field, XmNvalueChangedCallback,
1320                 propP_field_chgCB, (XtPointer)changebar);
1321
1322     /* Build Menu and Setup Callbacks */
1323     XtVaGetValues(menubutton, XmNsubMenuId, &submenu, NULL);
1324
1325     for (i=0; i < XtNumber(menu_items); i++)
1326     {
1327         menu_items[i] = XtVaCreateManagedWidget(menu_names[i],
1328                         xmCascadeButtonWidgetClass,
1329                         submenu,
1330                         XtVaTypedArg, XmNlabelString, XtRString,
1331                                 menu_strs[i], strlen(menu_strs[i])+1,
1332                         XmNuserData,    pms,
1333                         NULL);
1334     }
1335
1336     XtAddCallback(menu_items[NO_MENU], XmNactivateCallback, menuname_clearCB,
1337                         (XtPointer)pms);
1338
1339     if (!new_item_ok)
1340         XtDestroyWidget(menu_items[NEW_MENU]);
1341     else
1342         XtAddCallback(menu_items[NEW_MENU], XmNactivateCallback, menu_newCB,
1343                         (XtPointer)pms);
1344
1345     /* Set up callback to dynamically build "Menus" submenu */
1346     XtAddCallback(menubutton, XmNcascadingCallback, menulist_buildCB,
1347                         (XtPointer)menu_items[MENUS]);
1348     XtVaGetValues(menubutton, XmNsubMenuId, &submenu, NULL);
1349     XtAddCallback(XtParent(submenu), XtNpopdownCallback, menulist_destroyCB,
1350                         (XtPointer)submenu);
1351
1352     /* Set up "Edit Current" menu item */
1353     XtAddCallback(menubutton, XmNcascadingCallback, menu_edit_set_stateCB,
1354                         (XtPointer)menu_items[EDIT_MENU]);
1355     XtAddCallback(menu_items[EDIT_MENU], XmNactivateCallback, menu_editCB,
1356                         (XtPointer)pms);
1357
1358     /* Menu Title field should not be active until a Menu is connected */
1359     if (menu_title_pfs)
1360     {
1361         XtAddCallback(field, XmNvalueChangedCallback,
1362                 menu_field_chgCB, (XtPointer)pms);
1363         ui_set_active(menu_title_pfs->label, False);
1364         ui_set_active(menu_title_pfs->field, False);
1365     }
1366
1367 }
1368
1369 STRING
1370 prop_menuname_get_value(
1371     PropMenunameSetting    pms
1372 )
1373 {
1374     STRING      value;
1375
1376     value = ui_field_get_string(pms->field);
1377
1378     return value;
1379 }
1380
1381 int
1382 prop_menuname_set_value(
1383     PropMenunameSetting pms,
1384     STRING              value,
1385     BOOL                trip_changebar
1386 )
1387 {
1388     return(propP_field_set_value(pms->field, value, trip_changebar));
1389 }
1390
1391 void
1392 prop_options_init(
1393     PropOptionsSetting  pos,
1394     Widget              label,
1395     Widget              optionbox,
1396     Widget              menu,
1397     int                 num_items,
1398     WidgetList          items,
1399     XtPointer           *item_values,
1400     Widget              changebar
1401 )
1402 {
1403     int i;
1404
1405     /* Store Widget-IDs */
1406     pos->label = label;
1407     pos->optionbox = optionbox;
1408     pos->menu = menu;
1409     pos->changebar = changebar;
1410
1411     /* Setup Prop Sheet changebar mechanism */
1412     propP_changebar_init(changebar, optionbox);
1413
1414     for (i=0; i < num_items; i++)
1415     {
1416         XtVaSetValues(items[i], XmNuserData, (XtArgVal)item_values[i], NULL);
1417         XtAddCallback(items[i], XmNactivateCallback,
1418                         propP_setting_chgCB, (XtPointer)changebar);
1419         XtAddCallback(items[i], XmNactivateCallback,
1420                         propP_options_itemCB, (XtPointer)menu);
1421
1422     }
1423     /* Initialize Current-value to First Item in Option Menu */
1424     if (num_items > 0)
1425         prop_options_set_value(pos, (XtPointer)item_values[0], False);
1426 }
1427
1428 XtPointer
1429 prop_options_get_value(PropOptionsSetting pos)
1430 {
1431     XtArgVal value = -1;
1432
1433     XtVaGetValues(pos->menu, XmNuserData, &value, NULL);
1434
1435     return ((XtPointer)value);
1436 }
1437
1438 int
1439 prop_options_set_value(
1440     PropOptionsSetting  pos,
1441     XtPointer           value,
1442     BOOL                trip_changebar
1443 )
1444 {
1445     int            num_children;
1446     WidgetList     children;
1447     XtArgVal       child_val;
1448     int            i;
1449
1450     XtVaGetValues(pos->menu,
1451         XtNnumChildren,    &num_children,
1452         XtNchildren,       &children,
1453         NULL);
1454
1455     for (i = 0; i < num_children; i++)
1456     {
1457         XtVaGetValues(children[i],
1458                 XmNuserData,     &child_val,
1459                 NULL);
1460
1461         if (child_val == (XtArgVal) value)
1462         {
1463             XtVaSetValues(pos->optionbox, XmNmenuHistory, children[i], NULL);
1464             XtVaSetValues(pos->menu, XmNuserData, (XtArgVal)child_val, NULL);
1465
1466             if (trip_changebar)
1467                 prop_set_changebar(pos->changebar, PROP_CB_ON);
1468
1469             return OK;
1470         }
1471     }
1472     /* value doesn't exist as an option */
1473     util_dprintf(1, "prop_optionmenu_set_value: invalid option\n");
1474     return ERROR;
1475 }
1476
1477 /*
1478  * prop_options_remove_value()
1479  * Unmanages item corresponding to 'value'
1480  */
1481 int
1482 prop_options_remove_value(
1483     PropOptionsSetting  pos,
1484     XtPointer           value,
1485     BOOL                trip_changebar
1486 )
1487 {
1488     int            num_children;
1489     WidgetList     children;
1490     XtArgVal       child_val,
1491                    reset_val;
1492     int            i;
1493
1494     XtVaGetValues(pos->menu,
1495         XtNnumChildren,    &num_children,
1496         XtNchildren,       &children,
1497         NULL);
1498
1499     for (i = 0; i < num_children; i++)
1500     {
1501         XtVaGetValues(children[i],
1502                 XmNuserData,     &child_val,
1503                 NULL);
1504
1505         if (child_val == (XtArgVal)value)
1506         {
1507             XtArgVal    cur_val;
1508
1509             cur_val = (XtArgVal)prop_options_get_value(pos);
1510
1511             /*
1512              * Found value to remove. We need to do:
1513              *  - if current setting value is the same as the one we are
1514              *    deleting, set the setting value to be the previous item
1515              *    (if that is not the deleted one)
1516              *  - unmanage item widget
1517              */
1518
1519             if (cur_val == (XtArgVal)value)
1520             {
1521                 if ((i == 0) && (num_children != 1))
1522                 {
1523                     XtVaGetValues(children[1],
1524                         XmNuserData,     &reset_val,
1525                         NULL);
1526                     prop_options_set_value(pos, (XtPointer)reset_val, trip_changebar);
1527                 }
1528                 else
1529                     if (i != 0)
1530                         prop_options_set_value(pos, (XtPointer)reset_val, trip_changebar);
1531             }
1532
1533             XtUnmanageChild(children[i]);
1534
1535             if (trip_changebar)
1536                 prop_set_changebar(pos->changebar, PROP_CB_ON);
1537
1538             return OK;
1539         }
1540         else
1541             /*
1542              * Remember previous child value
1543              */
1544             reset_val = child_val;
1545     }
1546
1547     /* value doesn't exist as an option */
1548     util_dprintf(1, "prop_optionmenu_set_value: invalid option\n");
1549     return ERROR;
1550 }
1551
1552 void
1553 prop_obj_options_init(
1554     PropObjOptionsSetting  pos,
1555     Widget              label,
1556     Widget              optionbox,
1557     Widget              menu,
1558     int                 num_items,
1559     WidgetList          items,
1560     XtPointer          *item_values,
1561     Widget              changebar,
1562     BOOL                display_module,
1563     ABObj               *current_obj_ptr,
1564     ABObjTestFunc       obj_test_func
1565 )
1566 {
1567     Widget      shell;
1568
1569     prop_options_init(&(pos->options), label, optionbox, menu,
1570                 num_items, items, item_values, changebar);
1571     pos->display_module = display_module;
1572     pos->current_obj_ptr = current_obj_ptr;
1573     pos->obj_test_func = obj_test_func;
1574     pos->search_root = NULL;
1575
1576     /* Setup callback to dynamically build Object list when Menu is popped up */
1577     shell = ui_get_ancestor_shell(menu);
1578     XtAddCallback(shell, XtNpopupCallback, obj_options_buildCB, (XtPointer)pos);
1579
1580 }
1581
1582 ABObj
1583 prop_obj_options_get_value(
1584     PropObjOptionsSetting  pos
1585 )
1586 {
1587     return((ABObj)prop_options_get_value(&(pos->options)));
1588 }
1589
1590 int
1591 prop_obj_options_set_value(
1592     PropObjOptionsSetting       pos,
1593     ABObj                       obj,
1594     BOOL                        trip_changebar
1595 )
1596 {
1597     return(prop_options_set_value(&(pos->options), (XtPointer)obj, trip_changebar));
1598 }
1599
1600 void
1601 prop_obj_options_load(
1602     PropObjOptionsSetting  pos,
1603     ABObj                  search_root
1604 )
1605 {
1606     AB_TRAVERSAL        trav;
1607     ABObj               obj;
1608     int                 i, num_items;
1609     WidgetList          items;
1610
1611     /* Clear Object OptionMenu */
1612     XtVaGetValues(pos->options.menu,
1613                 XmNchildren,    &items,
1614                 XmNnumChildren, &num_items,
1615                 NULL);
1616
1617     /* Unmanage all but the First ("None") items */
1618     if (num_items > 1)
1619         XtUnmanageChildren(&(items[1]), num_items - 1);
1620
1621     i = 1;
1622
1623     /* Load OptionMenu with objects passing "test" */
1624     pos->search_root = search_root;
1625     if (pos->search_root != NULL)
1626     {
1627         for (trav_open(&trav, pos->search_root, AB_TRAV_SALIENT_UI);
1628             (obj= trav_next(&trav)) != NULL; )
1629             if ((*(pos->obj_test_func))(obj) == True)
1630             {
1631                 /* Either create new item or use existing one */
1632                 create_obj_option_item(pos, i < num_items? items[i] : NULL, obj);
1633                 i++;
1634             }
1635         trav_close(&trav);
1636     }
1637     XtVaGetValues(pos->options.menu,
1638                 XmNchildren,    &items,
1639                 NULL);
1640
1641     /* Manage all eligible items */
1642     if (i > 1)
1643         XtManageChildren(&(items[1]), i - 1);
1644 }
1645
1646 void
1647 prop_radiobox_init(
1648     PropRadioSetting    prs,
1649     Widget              label,
1650     Widget              radiobox,
1651     int                 num_items,
1652     WidgetList          items,
1653     XtPointer           *item_values,
1654     Widget              changebar
1655 )
1656 {
1657     int i;
1658
1659     /* Store Widget-IDs */
1660     prs->label = label;
1661     prs->radiobox = radiobox;
1662     prs->changebar = changebar;
1663
1664     /* Setup Prop Sheet changebar mechanism */
1665     propP_changebar_init(changebar, radiobox);
1666
1667     for (i=0; i < num_items; i++)
1668     {
1669         XtVaSetValues(items[i], XmNuserData, (XtArgVal)item_values[i], NULL);
1670         XtAddCallback(items[i], XmNvalueChangedCallback,
1671                         propP_setting_chgCB, (XtPointer*)changebar);
1672         XtAddCallback(items[i], XmNvalueChangedCallback,
1673                         propP_radiobox_itemCB, (XtPointer)item_values[i]);
1674
1675         /* Ensure Radiobox has a default Value set */
1676         if (i == 0)
1677         {
1678             XtVaSetValues(items[i], XmNset, True, NULL);
1679             XtVaSetValues(radiobox, XmNuserData, (XtArgVal)item_values[i], NULL);
1680         }
1681     }
1682
1683 }
1684
1685 int
1686 prop_radiobox_get_value(
1687     PropRadioSetting    prs
1688 )
1689 {
1690     XtArgVal value;
1691
1692     XtVaGetValues(prs->radiobox, XmNuserData, &value, NULL);
1693
1694     return((int)value);
1695 }
1696
1697 int
1698 prop_radiobox_set_value(
1699     PropRadioSetting prs,
1700     XtPointer        value,
1701     BOOL             trip_changebar
1702 )
1703 {
1704     int         num_children = 0;
1705     WidgetList  children = NULL;
1706     XtArgVal    childval = 0;
1707     Boolean     found = FALSE;
1708     int         i = 0;
1709
1710     XtVaGetValues(prs->radiobox,
1711         XtNnumChildren,    &num_children,
1712         XtNchildren,       &children,
1713         NULL);
1714
1715     for (i = 0; i < num_children; i++)
1716     {
1717         XtVaGetValues(children[i], XmNuserData, &childval, NULL);
1718         XmToggleButtonSetState(children[i], childval == (XtArgVal)value? TRUE : FALSE, FALSE);
1719         if (childval == (XtArgVal)value)
1720         {
1721             found = TRUE;
1722             XtVaSetValues(prs->radiobox, XmNuserData, (XtArgVal)value, NULL);
1723             if (trip_changebar)
1724                 prop_set_changebar(prs->changebar, PROP_CB_ON);
1725         }
1726     }
1727     if (!found)
1728     {
1729         util_dprintf(1,"prop_radio_set_value: invalid value\n");
1730         return ERROR;
1731     }
1732     return OK;
1733 }
1734
1735 void
1736 prop_label_field_init(
1737     PropFieldSetting    label_pfs,
1738     Widget              graphic_hint,
1739     WidgetList          labeltype_items,
1740     int                 num_items
1741 )
1742 {
1743     int         i;
1744
1745     if (label_pfs->label != NULL && graphic_hint != NULL)
1746         XtVaSetValues(label_pfs->label,
1747                 XmNuserData, (XtArgVal)graphic_hint,
1748                 XmNrecomputeSize, False,
1749                 NULL);
1750
1751     for(i=0; i < num_items; i++)
1752         XtAddCallback(labeltype_items[i], XmNactivateCallback,
1753                 (XtCallbackProc)propP_labeltypeCB, (XtPointer)label_pfs);
1754
1755 }
1756
1757 void
1758 prop_setup_label_field(
1759     PropFieldSetting    label_pfs,
1760     PropOptionsSetting  label_line_style_pos,
1761     AB_LABEL_TYPE       ltype,
1762     STRING              field_val,
1763     AB_LINE_TYPE        line_style
1764 )
1765 {
1766     Widget      graphic_hint = NULL;
1767
1768     XtVaGetValues(label_pfs->label, XmNuserData, &graphic_hint, NULL);
1769
1770     switch(ltype)
1771     {
1772         case AB_LABEL_STRING:
1773         case AB_LABEL_GLYPH:
1774            ui_set_label_string(label_pfs->label,
1775                 (STRING)(ltype == AB_LABEL_STRING? LabelForString : LabelForGraphic));
1776            if (graphic_hint)
1777                 ui_set_active(graphic_hint, (ltype == AB_LABEL_GLYPH));
1778            ui_set_active(label_pfs->label, True);
1779            ui_field_set_editable(label_pfs->field, True);
1780
1781            if (label_line_style_pos)
1782            {
1783                 ui_set_active(label_line_style_pos->label, False);
1784                 ui_set_active(label_line_style_pos->optionbox, False);
1785            }
1786            break;
1787         case AB_LABEL_SEPARATOR:
1788             ui_set_active(label_pfs->label, False);
1789             ui_field_set_string(label_pfs->field, "");
1790             ui_field_set_editable(label_pfs->field, False);
1791             ui_set_active(label_line_style_pos->label, True);
1792             ui_set_active(label_line_style_pos->optionbox, True);
1793             if (graphic_hint)
1794                 ui_set_active(graphic_hint, False);
1795             break;
1796     }
1797     if (field_val != NULL)
1798     {
1799         XtVaSetValues(label_pfs->field, XmNuserData, (XtArgVal)PROP_LOAD, NULL);
1800         ui_field_set_string(label_pfs->field, field_val);
1801         XtVaSetValues(label_pfs->field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
1802     }
1803     if (line_style != AB_LINE_UNDEF)
1804         prop_options_set_value(label_line_style_pos, (XtPointer)line_style, False);
1805
1806     /* WORKAROUND: for Motif bug */
1807     XtVaSetValues(label_pfs->label, XmNalignment, XmALIGNMENT_END, NULL);
1808
1809 }
1810
1811 /*
1812  * return TRUE if changebar is "on"
1813  */
1814 BOOL
1815 prop_changed(
1816     Widget changebar
1817 )
1818 {
1819     XtArgVal     cb_state;
1820
1821     XtVaGetValues(changebar, XmNuserData, &cb_state, NULL);
1822
1823     if (cb_state == PROP_CB_ON)
1824         return(TRUE);
1825     else
1826         return(FALSE);
1827
1828 }
1829
1830 /*
1831  * Get the running-count of changebars that are "ON"
1832  */
1833 BOOL
1834 prop_changebars_pending(
1835     Widget      prop_sheet
1836 )
1837 {
1838     XtArgVal       change_count;
1839
1840     XtVaGetValues(prop_sheet, XmNuserData, &change_count, NULL);
1841
1842     if (change_count > 0)
1843         return True;
1844     else
1845         return False;
1846
1847 }
1848
1849 /*
1850  * Set the running-count of changebars that are "ON" to 0
1851  */
1852 void
1853 prop_changebars_cleared(
1854     Widget      prop_sheet
1855 )
1856 {
1857      XtVaSetValues(prop_sheet, XmNuserData, (XtArgVal)0, NULL);
1858 }
1859
1860 /*
1861  * Set changebar to desired state: on or off
1862  * Also keep a running count of the number of changebars
1863  * that are "ON" in the userData of the changebars' parent
1864  */
1865 void
1866 prop_set_changebar(
1867     Widget    changebar,
1868     int        mode
1869 )
1870 {
1871     Widget prop_sheet;
1872     Pixel  bar_pixel;
1873
1874     prop_sheet = XtParent(changebar);
1875
1876     if (mode == PROP_CB_ON)
1877     {
1878 /*
1879  REMIND: aim - workaround for Motif problem with Prop textfield
1880          input being lost...
1881
1882         if (!prop_changed(changebar))
1883         {
1884 */
1885             XtVaGetValues(XtParent(changebar),
1886                         XmNforeground,  &bar_pixel,
1887                         NULL);
1888
1889             XtVaSetValues(changebar,
1890                         XmNbackground,  bar_pixel,
1891                         XmNforeground,  bar_pixel,
1892                         XmNuserData,    (XtArgVal)PROP_CB_ON,
1893                         NULL);
1894
1895             /* Set dirty-bit */
1896             XtVaSetValues(prop_sheet, XmNuserData, (XtArgVal)1, NULL);
1897 /*
1898         }
1899 */
1900     }
1901     else /* PROP_CB_OFF */
1902     {
1903 /*
1904         if (prop_changed(changebar))
1905         {
1906 */
1907             XtVaGetValues(XtParent(changebar), XmNbackground, &bar_pixel, NULL);
1908             XtVaSetValues(changebar,
1909                         XmNbackground,  bar_pixel,
1910                         XmNforeground,  bar_pixel,
1911                         XmNuserData,    (XtArgVal)PROP_CB_OFF,
1912                         NULL);
1913 /*
1914         }
1915 */
1916     }
1917 }
1918
1919 /*
1920  * Verify that the colorname entered is valid
1921  */
1922 BOOL
1923 prop_color_ok(
1924     Widget    field
1925 )
1926 {
1927     STRING colorname;
1928     BOOL   valid = TRUE;
1929
1930     colorname = ui_field_get_string(field);
1931
1932     /* No color is OK */
1933     if (util_strempty(colorname))
1934         return valid;
1935
1936     if (!objxm_color_exists(colorname))
1937     {
1938         sprintf(Buf,
1939             catgets(Dtb_project_catd, 100, 112, "%s is not a valid color."),
1940                         colorname);
1941         util_set_help_data(catgets(Dtb_project_catd, 100, 113,
1942                     "The color that was specified is not recognized\nas a valid color name."), NULL, NULL);
1943         valid = FALSE;
1944
1945         propP_popup_message(field, Buf, False);
1946     }
1947     util_free(colorname);
1948     return valid;
1949
1950 }
1951
1952 /*
1953  * Verify that the Glyph filename entered is valid
1954  */
1955 BOOL
1956 prop_graphic_filename_ok(
1957     Widget      field,
1958     BOOL        empty_ok
1959 )
1960 {
1961     char   filebase[512];
1962     STRING filename;
1963     STRING ext;
1964     Pixmap pixmap;
1965     int    status;
1966     BOOL   valid = False;
1967
1968     filename = ui_field_get_string(field);
1969
1970     if (util_strempty(filename))
1971     {
1972         if (empty_ok)
1973             valid = True; /* No Filename is valid */
1974         else
1975         {
1976             util_set_help_data(catgets(Dtb_project_catd, 100, 115,
1977                 "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);
1978
1979             propP_popup_message(field,
1980                 catgets(Dtb_project_catd, 100, 114,
1981                    "The \"Graphic Filename\" field cannot be empty."), False);
1982         }
1983     }
1984     else
1985     {
1986         strcpy(filebase, filename);
1987         /* Look to see if user typed in the full filename for the Graphic.
1988          * If so, strip off the extension and mark stripped to be True.
1989          */
1990         if (util_file_name_has_extension(filename, "pm") ||
1991             util_file_name_has_extension(filename, "xpm") ||
1992             util_file_name_has_extension(filename, "bm") ||
1993             util_file_name_has_extension(filename, "xbm"))
1994         {
1995             ext = strrchr(filebase, '.');
1996             ext[0] = '\0'; /* strip off extenstion */
1997
1998             util_set_help_data(catgets(Dtb_project_catd, 100, 117,
1999                 "The graphic file name extension should not be included\nwhen it is specified in the Graphic Filename field."), NULL, NULL);
2000
2001             propP_popup_message(field,
2002                 catgets(Dtb_project_catd, 100, 116,
2003                     "\"Graphic Filename\" field expects the filename\nbase only (no extensions: .pm .xpm .bm .xbm).\nStripping off the extension."), True);
2004             ui_field_set_string(field, filebase);
2005         }
2006         status = objxm_filebase_to_pixmap(field, filebase, &pixmap);
2007         if (status == OK)
2008         {
2009             valid = TRUE;
2010             XmDestroyPixmap(XtScreen(field), pixmap);
2011         }
2012         else
2013             propP_popup_message(field,
2014                 objxm_pixmap_conversion_error_msg(NULL, filebase, status), False);
2015
2016     }
2017     util_free(filename);
2018
2019     return valid;
2020 }
2021
2022 BOOL
2023 prop_help_item_ok(
2024     Widget      list,
2025     ABObj       item_obj
2026 )
2027 {
2028     int         num_items;
2029     ABObj       *iobj_list;
2030     BOOL        exists = FALSE;
2031     int         i;
2032     char        Buf[256];
2033
2034
2035     XtVaGetValues(list,
2036                 XmNitemCount, &num_items,
2037                 XmNuserData,  &iobj_list,
2038                 NULL);
2039
2040     /* Search through cascades, looking for another configured
2041      * to be the "Help" cascade
2042      */
2043     for (i = 0; i < num_items; i++)
2044     {
2045         if (obj_is_help_item(iobj_list[i]) == TRUE &&
2046             item_obj != iobj_list[i])
2047         {
2048             exists = TRUE;
2049             break;
2050         }
2051     }
2052     if (exists)
2053     {
2054         util_set_help_data(catgets(Dtb_project_catd, 100, 119,
2055             "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);
2056
2057         sprintf(Buf, catgets(Dtb_project_catd, 100, 118,
2058                 "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."),
2059                 obj_get_label(iobj_list[i]), obj_get_label(item_obj));
2060
2061         propP_popup_message(list, Buf, False);
2062         return FALSE;
2063     }
2064
2065     return TRUE;
2066
2067 }
2068
2069 /*
2070  * Verify that identifier string only contains valid chars
2071  */
2072 BOOL
2073 prop_identifier_ok(
2074     Widget    field
2075 )
2076 {
2077     return(prop_string_ok(field, Name_ok_test, TRUE));
2078 }
2079
2080
2081
2082 /*
2083  * verify that the name entered is valid & unique
2084  */
2085 BOOL
2086 prop_name_ok(
2087     ABObj    obj,
2088     Widget    field
2089 )
2090 {
2091     ABObj  module = obj_get_module(obj);
2092     ABObj  other = NULL;
2093     char   Buf[512];
2094     BOOL   valid = TRUE;
2095     STRING newname;
2096     STRING oldname;
2097
2098     newname = ui_field_get_string(field);
2099     oldname = obj_get_name(obj);
2100
2101     if (!newname || !*newname)
2102     {
2103         util_set_help_data(catgets(Dtb_project_catd, 100, 121,
2104             "A string must be entered in the Object Name field."),
2105             NULL, NULL);
2106         propP_popup_message( field, catgets(Dtb_project_catd, 100, 120,
2107                 "A name is required."), False);
2108         valid = FALSE;
2109     }
2110     else if (!prop_identifier_ok(field))
2111         valid = FALSE;
2112     else if (!oldname)
2113         oldname = "";
2114
2115     if (valid &&
2116         ((other = obj_find_by_name(module, newname)) != NULL))
2117     {
2118         if (other != obj)
2119         {
2120             util_set_help_data(catgets(Dtb_project_catd, 100, 123,
2121                 "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."),
2122                 NULL, NULL);
2123
2124             sprintf(Buf, catgets(Dtb_project_catd, 100, 122,
2125                 "Another object in Module \"%s\"\nhas the name \"%s\".\nPlease enter a unique name."), util_strsafe(obj_get_name(module)),newname);
2126             propP_popup_message(field, Buf, False);
2127             valid = FALSE;
2128         }
2129     }
2130     util_free(newname);
2131
2132     return valid;
2133
2134 }
2135
2136 BOOL
2137 prop_number_ok(
2138     Widget      field,
2139     STRING      field_name,
2140     int         min_val,
2141     int         max_val
2142 )
2143 {
2144     BOOL        valid = TRUE;
2145     char        *p;
2146     STRING      string;
2147     char        *s;
2148     int         value;
2149
2150     string = ui_field_get_string(field);
2151     s = string;
2152
2153     if ((s  != NULL) && (*s != '\0'))
2154     {
2155         (void)strtol(s, &p, 10);
2156
2157         if((s == p) || ((s + strlen(s)) != p))
2158         {
2159             util_set_help_data(catgets(Dtb_project_catd, 100, 125,
2160                 "The field only accepts integers. You must enter\nan integer value."), NULL, NULL);
2161             sprintf(Buf, catgets(Dtb_project_catd, 100, 124,
2162                 "\"%s\" must contain an integer."),
2163                 field_name);
2164             propP_popup_message(field, Buf, False);
2165             valid = FALSE;
2166         }
2167     }
2168     if (valid) /* is an integer */
2169     {
2170         value = prop_str_to_int(string);
2171         if (value < min_val || value > max_val)
2172         {
2173             util_set_help_data(catgets(Dtb_project_catd, 100, 127,
2174                 "The numerical value entered into the field is not valid. Specify a value in the given range."), NULL, NULL);
2175             sprintf(Buf, catgets(Dtb_project_catd, 100, 126,
2176                 "\"%s\" value (%d) out of\nvalid range [%d - %d]."),
2177                 field_name, value, min_val, max_val);
2178             propP_popup_message(field, Buf, False);
2179             valid = False;
2180         }
2181     }
2182     util_free(string);
2183
2184     return(valid);
2185 }
2186
2187 /*
2188  * Search the tree beginning at "root" for an object of the specified
2189  * type with the name currently stored in "field"
2190  * Return TRUE if found (or name is "") and FALSE otherwise
2191  */
2192 BOOL
2193 prop_obj_name_ok(
2194     Widget      field,
2195     ABObj       root,
2196     AB_OBJECT_TYPE objtype,
2197     STRING      objtype_name
2198 )
2199 {
2200     ABObj       target;
2201     STRING      objname;
2202     BOOL        valid = FALSE;
2203     char        msgbuf[256];
2204
2205     objname = ui_field_get_string(field);
2206
2207     /* ObjName can be blank OR the name of an existing obj */
2208     if (util_strcmp(objname, "") == 0)
2209         valid = TRUE;
2210     else if ((target = obj_scoped_find_by_name(root, objname)) != NULL)
2211     {
2212         if (target->type == objtype)
2213             valid = TRUE;
2214         else
2215         {
2216             util_set_help_data(catgets(Dtb_project_catd, 100, 129,
2217                 "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."),
2218                 NULL, NULL);
2219             sprintf(msgbuf, catgets(Dtb_project_catd, 100, 128,
2220                 "\"%s\" is not an object of type %s."),
2221                 objname, objtype_name);
2222         }
2223     }
2224     else
2225     {
2226         util_set_help_data(catgets(Dtb_project_catd, 100, 136,
2227             "The specified object does not exist or it is\nnot of the correct type."), NULL, NULL);
2228
2229         sprintf(msgbuf, catgets(Dtb_project_catd, 100, 130,
2230                 "\"%s\" is not the name of an existing %s."),
2231                 objname, objtype_name);
2232     }
2233
2234     if (valid == FALSE)
2235         propP_popup_message(field, msgbuf, False);
2236
2237     util_free(objname);
2238
2239     return valid;
2240
2241 }
2242
2243 BOOL
2244 prop_submenu_name_ok(
2245     Widget      field,
2246     ABObj       owner
2247 )
2248 {
2249     BOOL        valid = False;
2250     ABObj       module = obj_get_module(owner);
2251     char        msgbuf[256];
2252
2253     /* Check to see if Submenu exists first */
2254     if (prop_obj_name_ok(field, module, AB_TYPE_MENU, "Menu"))
2255     {
2256         valid = True;
2257
2258         /* Check that the submenu name specified will not cause a circular
2259          * menu (if the submenu is one that is in the owner's ancestory)
2260          */
2261         if (obj_is_menu(owner))
2262         {
2263             ABObj       menu, *menus, *ineligible_menus;
2264             int         menu_count = 0;
2265             int         ineligible_count = 0;
2266             STRING      menu_name;
2267
2268             menu_name = ui_field_get_string(field);
2269             abobj_build_menus_array(module, &menus, &menu_count);
2270
2271             /* Build list of any menus in the ancestory of "owner" menu
2272              * since these are not valid submenus
2273              */
2274             ineligible_menus = (ABObj*)util_malloc(menu_count*sizeof(ABObj));
2275             ineligible_menus[ineligible_count++] = owner;
2276             find_submenu_owners(owner, menus, menu_count,
2277                         ineligible_menus, &ineligible_count);
2278
2279             /* Check to see if the specified submenu is in the ineligible list */
2280             menu = obj_scoped_find_by_name(module, menu_name);
2281             if (menu_in_list(ineligible_menus, ineligible_count, menu))
2282             {
2283                 STRING  fmtStr = NULL;
2284                 STRING  help_buf = NULL;
2285
2286                 valid = False;
2287
2288                 fmtStr = XtNewString(catgets(Dtb_project_catd,
2289                         100, 132, "Menu \"%s\" is attached as a sub-menu\nto \"%s\". You cannot create a circular\nreference within menus."));
2290
2291                 help_buf = (STRING) util_malloc(strlen(fmtStr) +
2292                     strlen(obj_get_name(owner)) + strlen(menu_name) +1);
2293                 sprintf(help_buf, fmtStr, obj_get_name(owner), menu_name);
2294
2295                 util_set_help_data(help_buf, NULL, NULL);
2296                 sprintf(msgbuf, catgets(Dtb_project_catd, 100, 131,
2297                     "Menu \"%s\" is an ancestor of \"%s\"\ntherefore it cannot be attached as a Sub-menu."), menu_name, obj_get_name(owner));
2298                 propP_popup_message(field, msgbuf, False);
2299
2300                 XtFree(fmtStr);
2301                 util_free(help_buf);
2302             }
2303             util_free(menus);
2304             util_free(ineligible_menus);
2305             util_free(menu_name);
2306         }
2307     }
2308     return valid;
2309 }
2310
2311
2312 int
2313 prop_str_to_int(
2314     STRING      str
2315 )
2316 {
2317     int    val;
2318     char   *s = str;
2319     char   *p;
2320
2321     if ((s != NULL) && (*s != '\0'))
2322     {
2323         val = (int)strtol(s, &p, 10);
2324
2325         if ((s == p) || ((s + strlen(s)) != p))
2326         {
2327             return(ERR_ATOI);
2328         }
2329         return(val);
2330     }
2331     return(ERR_ATOI);
2332 }
2333
2334 /*
2335  * verify that a string contains only valid characters
2336  */
2337 BOOL
2338 prop_string_ok(
2339     Widget    field,
2340     const char    *chars,
2341     BOOL    display_notice
2342 )
2343 {
2344     STRING string;
2345     char   *s;
2346
2347     string = ui_field_get_string(field);
2348     s = string;
2349
2350     while(s && *s != '\0')
2351     {
2352         if (!isalnum(*s) && (strchr(chars, *s) == NULL))
2353         {
2354             if (display_notice)
2355             {
2356                 util_set_help_data(catgets(Dtb_project_catd, 10, 69,
2357                     "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."),
2358                      NULL, NULL);
2359                 sprintf(Buf, catgets(Dtb_project_catd, 100, 133,
2360                     "Only letters, digits, and [%s] allowed."), chars);
2361                 propP_popup_message(field, Buf, False);
2362             }
2363             util_free(string);
2364             return(FALSE);
2365         }
2366         s++;
2367     }
2368     util_free(string);
2369     return(TRUE);
2370 }
2371
2372
2373 /*
2374  *****************************************************************
2375  * Module Private Functions
2376  *****************************************************************
2377  */
2378
2379 /*
2380  * Set Changebar's geometry so that it is aligned with and equal in height to,
2381  * it's corresponding setting.  This must be done dynamically because fonts
2382  * and localization could cause these metrics to change at dtbuilder invocation.
2383  */
2384 static void
2385 set_changebar_size(
2386     Widget      shell,
2387     XtPointer   client_data,
2388     XEvent      *event,
2389     Boolean     *cont_dispatch
2390 )
2391 {
2392     Widget      setting, changebar;
2393     Widget      setting_p, changebar_p;
2394     Position    setting_y, delta_y;
2395     Dimension   setting_h;
2396     Widget      *wlist = (Widget*)client_data;
2397
2398     if (event->type == MapNotify)
2399     {
2400         changebar = wlist[0];
2401         setting = wlist[1];
2402
2403         XtVaGetValues(setting,
2404                 XmNheight, &setting_h,
2405                 XmNy,      &setting_y,
2406                 NULL);
2407
2408         changebar_p = XtParent(changebar);
2409         setting_p = setting;
2410
2411         /* Calculate the setting's overall y position relative to the
2412          * entire property sheet by walking up the setting's ancestry
2413          * and accumulating the relative y offsets.
2414          */
2415         while (setting_p && XtParent(setting_p) != changebar_p)
2416         {
2417             setting_p = XtParent(setting_p);
2418             XtVaGetValues(setting_p, XmNy, &delta_y, NULL);
2419             setting_y += delta_y;
2420         }
2421
2422         /* Align the changebar up with the setting */
2423         XtVaSetValues(changebar,
2424                 XmNheight,      setting_h - 2,
2425                 XmNy,           setting_y + 1,
2426                 XmNtopOffset,   setting_y + 1,
2427                 NULL);
2428
2429         /* Only need to do this once per changebar! */
2430         XtRemoveEventHandler(shell, StructureNotifyMask, False,
2431                 set_changebar_size, (XtPointer)wlist);
2432
2433         util_free(wlist);
2434     }
2435 }
2436
2437 /*
2438  * Initialize the changebar
2439  */
2440 void
2441 propP_changebar_init(
2442     Widget      changebar,
2443     Widget      setting
2444 )
2445 {
2446     Widget      shell = ui_get_ancestor_shell(changebar);
2447     Widget      *wlist;
2448     unsigned char changebar_top_att;
2449
2450     XtVaSetValues(changebar, XmNuserData, (XtArgVal)PROP_CB_ON, NULL);
2451     prop_set_changebar(changebar, PROP_CB_OFF);
2452
2453     /* If changebar already has attachment, let's not mess with it */
2454     XtVaGetValues(changebar, XmNtopAttachment, &changebar_top_att, NULL);
2455     if (changebar_top_att != XmATTACH_FORM)
2456         return;
2457
2458     wlist = (Widget*)util_malloc(2*sizeof(Widget));
2459     if (wlist == NULL)
2460         return;
2461
2462     wlist[0] = changebar;
2463     wlist[1] = setting;
2464
2465     /* Once the shell is mapped we'll need to calculate the appropriate
2466      * changebar size/position to match its corrsponding setting
2467      * (which could change dynamically due to fonts/localization)
2468      */
2469     XtAddEventHandler(shell, StructureNotifyMask, False,
2470         set_changebar_size, (XtPointer)wlist);
2471 }
2472
2473 /*
2474  * Callback: textfield value has changed...turnon changebar
2475  *           if operation is not a "load"
2476  */
2477
2478 void
2479 propP_combobox_chgCB(
2480     Widget widget,
2481      XtPointer clientdata,
2482      XtPointer calldata
2483 )
2484 {
2485     PropObjComboboxSetting pcs = (PropObjComboboxSetting)clientdata;
2486
2487     prop_set_changebar(pcs->changebar, PROP_CB_ON);
2488 }
2489
2490 void
2491 propP_field_chgCB(
2492      Widget widget,
2493      XtPointer clientdata,
2494      XtPointer calldata
2495 )
2496 {
2497      Widget      changebar = (Widget)clientdata;
2498      XtArgVal    field_mode, cb_state;
2499
2500      XtVaGetValues(widget, XmNuserData, &field_mode, NULL);
2501 /*
2502  REMIND: aim - workaround for Motif problem with Prop textfield
2503          input being lost...
2504
2505      XtVaGetValues(changebar, XmNuserData, &cb_state,  NULL);
2506
2507      if (field_mode == PROP_EDIT && cb_state == PROP_CB_OFF)
2508 */
2509      if (field_mode == PROP_EDIT)
2510         prop_set_changebar(changebar, PROP_CB_ON);
2511
2512 }
2513
2514 int
2515 propP_field_set_value(
2516     Widget      field,
2517     STRING      value,
2518     BOOL        trip_changebar
2519 )
2520 {
2521     if (!trip_changebar)
2522         /* Set state so changebar is not triggered */
2523         XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_LOAD, NULL);
2524
2525     /* Set field value */
2526     ui_field_set_string(field, value);
2527
2528     if (!trip_changebar)
2529         /* Reset state */
2530         XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
2531
2532     return OK;
2533 }
2534
2535 int
2536 propP_field_set_numeric_value(
2537     Widget      field,
2538     int         val,
2539     BOOL        trip_changebar
2540 )
2541 {
2542     char valstr[8];
2543
2544     if (!trip_changebar)
2545         /* Set state so changebar is not triggered */
2546         XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_LOAD, NULL);
2547
2548     /* Convert int to string */
2549     sprintf(valstr, "%d", val);
2550     ui_field_set_string(field, valstr);
2551
2552     if (!trip_changebar)
2553         /* Reset state */
2554         XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT, NULL);
2555
2556     return 0;
2557
2558 }
2559
2560 void
2561 propP_labeltypeCB(
2562     Widget    item,
2563     XtPointer clientdata,
2564     XtPointer call_data
2565 )
2566 {
2567     AB_LABEL_TYPE       label_type = AB_LABEL_UNDEF;
2568     PropFieldSetting    label_pfs = (PropFieldSetting)clientdata;
2569
2570     XtVaGetValues(item, XmNuserData, &label_type, NULL);
2571     prop_setup_label_field(label_pfs, NULL, label_type, NULL, AB_LINE_UNDEF);
2572     ui_field_select_string(label_pfs->field, True);
2573 }
2574
2575 void
2576 propP_options_itemCB(
2577     Widget      item,
2578     XtPointer   client_data,
2579     XtPointer   call_data
2580 )
2581 {
2582     Widget      optionmenu = (Widget)client_data;
2583     XtArgVal    value;
2584
2585     XtVaGetValues(item, XmNuserData, &value, NULL);
2586
2587     XtVaSetValues(optionmenu, XmNuserData, (XtArgVal)value, NULL);
2588
2589 }
2590
2591 /*
2592  * popup Error Dialog displaying passed in message
2593  */
2594 void
2595 propP_popup_message(
2596     Widget      parent,
2597     STRING      msg,
2598     BOOL        modal
2599 )
2600 {
2601     DtbObjectHelpDataRec    help_data;
2602     STRING                  help_text = NULL;
2603     STRING                  help_vol = NULL;
2604     STRING                  help_loc = NULL;
2605     XmString    xm_buf = XmStringCreateLocalized(msg);
2606
2607     dtb_revolv_wrn_msg_initialize(&dtb_revolv_wrn_msg);
2608
2609     util_get_help_data(&help_text, &help_vol, &help_loc);
2610     if (!util_strempty(help_text))
2611     {
2612         help_data.help_text = help_text ? (STRING) XtNewString(help_text) : NULL;
2613         help_data.help_volume = help_vol ? (STRING) XtNewString(help_vol) : NULL;
2614         help_data.help_locationID = help_loc ? (STRING) XtNewString(help_loc) : NULL;
2615     }
2616     else
2617     {
2618             /* If there is no help text to display,
2619              * then remove the Help button.
2620              */
2621             dtb_revolv_wrn_msg.help_button = False;
2622     }
2623
2624     if (!util_strempty(help_text))
2625     {
2626         dtb_show_message(parent,
2627                 &dtb_revolv_wrn_msg, xm_buf, &help_data);
2628
2629         /*
2630          * Free help data strings
2631          */
2632         if (help_data.help_text);
2633             XtFree(help_data.help_text);
2634         if (help_data.help_volume);
2635             XtFree(help_data.help_volume);
2636         if (help_data.help_locationID);
2637             XtFree(help_data.help_locationID);
2638     }
2639     else
2640         dtb_show_message(parent,
2641                 &dtb_revolv_wrn_msg, xm_buf, NULL);
2642
2643     XmStringFree(xm_buf);
2644 }
2645
2646 /*
2647  * Callback: choice value has changed...turnon changebar
2648  */
2649 void
2650 propP_setting_chgCB(
2651      Widget widget,
2652      XtPointer clientdata,
2653      XtPointer calldata
2654 )
2655 {
2656      Widget changebar = (Widget)clientdata;
2657      XtArgVal   cb_state;
2658
2659      XtVaGetValues(changebar, XmNuserData, &cb_state,  NULL);
2660
2661      if (cb_state == PROP_CB_OFF)
2662         prop_set_changebar(changebar, PROP_CB_ON);
2663
2664 }
2665
2666 /*
2667  * Callback: item in exclusive choice has been set...store it's
2668  *           value in the parent radiobox
2669  */
2670 void
2671 propP_radiobox_itemCB(
2672     Widget item,
2673     XtPointer clientdata,
2674     XtPointer calldata
2675 )
2676 {
2677     XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct*)calldata;
2678     XtArgVal  value = (XtArgVal)clientdata;
2679     Widget excl_setting;
2680
2681     if (state->set)
2682     {
2683         excl_setting = XtParent(item);
2684         XtVaSetValues(excl_setting, XmNuserData, value, NULL);
2685     }
2686 }
2687
2688
2689 /*
2690  *****************************************************************
2691  * Private Functions
2692  *****************************************************************
2693  */
2694
2695 static void
2696 revolv_dialog_init(
2697     Widget      parent
2698 )
2699 {
2700     DtbRevolvPropDialogInfo     cgen = &dtb_revolv_prop_dialog; /* Codegen structure */
2701
2702     if (dtb_revolv_prop_dialog_initialize(cgen, parent) == 0)
2703     {
2704         AB_rev_prop_dialog = cgen->prop_dialog_shellform;
2705
2706         XtVaSetValues(cgen->prop_dialog_form,
2707                 XmNresizePolicy,        XmRESIZE_ANY,
2708                 XmNallowResize,         True,
2709                 XmNautoUnmanage,        False,
2710                 NULL);
2711
2712         revolv_objectspane_init(cgen);
2713         revolv_basicframe_init(cgen);
2714         prop_activate_panel_init(AB_PROP_REVOLVING, NULL,
2715                 cgen->ok_button, cgen->apply_button,
2716                 cgen->reset_button, cgen->cancel_button,
2717                 cgen->help_button);
2718
2719         init_prop_state_info(AB_rev_prop_dialog, NULL, cgen->objlist, NULL);
2720
2721         ab_register_window(AB_rev_prop_dialog, AB_WIN_DIALOG,
2722                 WindowHidden, AB_toplevel, AB_WPOS_TILE_HORIZONTAL,
2723                 close_propsCB, (XtPointer)AB_PROP_REVOLVING);
2724     }
2725 }
2726
2727 /*
2728  * In order to get the automatically generated dtbuilder
2729  * resource file to work with our Revolving Props cloning
2730  * mechanism, we need to name each Revolving prop sheet
2731  * frame to be the SAME as the dialog shellform within
2732  * the Fixed version (to ensure the attribute settings
2733  * resources are picked up in the Revolving version).
2734  */
2735 static String
2736 get_prop_frame_name(
2737     PalItemInfo *palitem
2738 )
2739 {
2740     switch (palitem->type)
2741     {
2742         case AB_TYPE_BASE_WINDOW:
2743             return "dtb_mainwin_prop_dialog_shellform";
2744         case AB_TYPE_DIALOG:
2745             return "dtb_custdlg_prop_dialog_shellform";
2746         case AB_TYPE_FILE_CHOOSER:
2747             return "dtb_fchooser_prop_dialog_shellform";
2748         case AB_TYPE_CONTAINER:
2749             if (util_streq(palitem->name, "Control Pane"))
2750                 return "dtb_cpanel_prop_dialog_shellform";
2751             else if (util_streq(palitem->name, "Group"))
2752                 return "dtb_group_prop_dialog_shellform";
2753             else if (util_streq(palitem->name, "Menubar"))
2754                 return "dtb_menubar_prop_dialog_shellform";
2755             else
2756                 return "dtb_panedwin_ed_prop_dialog_shellform";
2757         case AB_TYPE_DRAWING_AREA:
2758             return "dtb_drawp_prop_dialog_shellform";
2759         case AB_TYPE_TEXT_PANE:
2760             return "dtb_textp_prop_dialog_shellform";
2761         case AB_TYPE_TERM_PANE:
2762             return "dtb_termp_prop_dialog_shellform";
2763         case AB_TYPE_BUTTON:
2764             return "dtb_button_prop_dialog_shellform";
2765         case AB_TYPE_CHOICE:
2766             return "dtb_choice_prop_dialog_shellform";
2767         case AB_TYPE_COMBO_BOX:
2768             return "dtb_combobox_prop_dialog_shellform";
2769         case AB_TYPE_LABEL:
2770             return "dtb_label_prop_dialog_shellform";
2771         case AB_TYPE_LIST:
2772             return "dtb_list_prop_dialog_shellform";
2773         case AB_TYPE_MENU:
2774             return "dtb_menu_prop_dialog_shellform";
2775         case AB_TYPE_SCALE:
2776             return "dtb_scale_prop_dialog_shellform";
2777         case AB_TYPE_SEPARATOR:
2778             return "dtb_sep_prop_dialog_shellform";
2779         case AB_TYPE_SPIN_BOX:
2780             return "dtb_spinbox_prop_dialog_shellform";
2781         case AB_TYPE_TEXT_FIELD:
2782             return "dtb_textf_prop_dialog_shellform";
2783         default:
2784             return "revolv_prop_frame";
2785     }
2786 }
2787
2788 static void
2789 revolv_basicframe_init(
2790     DtbRevolvPropDialogInfo     cgen
2791 )
2792 {
2793     int         i;
2794     Widget      rev_form;
2795     Widget      rev_frame;
2796
2797     /* Destroy dummy frame & controlpanel */
2798     XtDestroyWidget(cgen->attrs_ctrlpanel_frame);
2799
2800     /* Create Form to manage all revolving frames */
2801     rev_form = XtVaCreateManagedWidget("revolving_dialog_form",
2802                 xmFormWidgetClass,
2803                 cgen->prop_dialog_form,
2804                 XmNtopAttachment,       XmATTACH_WIDGET,
2805                 XmNtopWidget,           cgen->objlist_panel,
2806                 XmNrightAttachment,     XmATTACH_FORM,
2807                 XmNleftAttachment,      XmATTACH_FORM,
2808                 XmNbottomAttachment,    XmATTACH_FORM,
2809                 XmNresizePolicy,        XmRESIZE_ANY,
2810                 XmNheight,              600,
2811                 NULL);
2812
2813     /*
2814      * Create frame for each object on the palette...
2815      */
2816     for (i = 0; i < palette_item_cnt; i++)
2817     {
2818         rev_frame = cgen->attrs_ctrlpanel_frame =
2819                 XtVaCreateWidget(get_prop_frame_name(palette_item[i]),
2820                 xmFrameWidgetClass,
2821                 rev_form,
2822                 XmNshadowType,          XmSHADOW_IN,
2823                 XmNtopAttachment,       XmATTACH_FORM,
2824                 XmNrightAttachment,     XmATTACH_FORM,
2825                 XmNleftAttachment,      XmATTACH_FORM,
2826                 XmNbottomAttachment,    XmATTACH_FORM,
2827                 NULL);
2828
2829         (*(palette_item[i]->prop_initialize))(rev_frame, AB_PROP_REVOLVING);
2830         palette_item[i]->rev_prop_frame = rev_frame;
2831
2832         /* Make sure Frame is not initially managed */
2833         XtUnmanageChild(rev_frame);
2834     }
2835 }
2836
2837 static BOOL
2838 editable_obj_test(
2839     PalEditableObjInfo *ed_obj_info
2840 )
2841 {
2842     return (ed_obj_info->palitem != NULL);
2843 }
2844
2845 static void
2846 revolv_objectspane_init(
2847    DtbRevolvPropDialogInfo      cgen
2848 )
2849 {
2850
2851     revolv_optionmenu = cgen->objtype_opmenu;
2852
2853     /* Destroy dummy Option menu item */
2854     XtDestroyWidget(cgen->objtype_opmenu_items.object_type_item);
2855
2856     /* Build up Object Type Option Menu */
2857     pal_add_editable_obj_menu_items(cgen->objtype_opmenu_menu,
2858         change_objecttypeCB, editable_obj_test);
2859
2860     /*
2861      * Configure Revolving Behavior
2862      */
2863     XtAddCallback(cgen->tearoff_button, XmNactivateCallback,
2864                 tearoff_propsCB, NULL);
2865
2866     XtAddCallback(cgen->objlist, XmNbrowseSelectionCallback,
2867             (XtCallbackProc)objlist_selectCB,
2868                 (XtPointer)AB_PROP_REVOLVING);
2869
2870     /* Setup Object List Label */
2871     XtVaSetValues(cgen->objlist_label2,
2872             XmNalignment,        XmALIGNMENT_END,
2873             XmNrightAttachment,  XmATTACH_WIDGET,
2874             XmNrightWidget,      cgen->objlist_scrolledwin,
2875             XmNrightOffset,      4,
2876             XmNleftAttachment,   XmATTACH_POSITION,
2877             XmNleftPosition,     0,
2878             XmNbottomAttachment, XmATTACH_NONE,
2879             NULL);
2880
2881 }
2882
2883 /*
2884  * Switch the Revolving-prop frame to display the pane
2885  * matching the specified Palette Item type.
2886  */
2887 static void
2888 revolv_change_prop_frame(
2889     PalItemInfo *palitem
2890 )
2891 {
2892     Widget              newframe = NULL;
2893     PropStateInfo       *pstate;
2894
2895     if (palitem->rev_prop_frame != NULL)
2896     {
2897         newframe = palitem->rev_prop_frame;
2898         XtManageChild(newframe);
2899     }
2900     if (newframe != NULL)
2901     {
2902         if (revolv_current_frame != NULL)
2903             XtUnmanageChild(revolv_current_frame);
2904         revolv_current_frame = newframe;
2905     }
2906     pstate = get_prop_state_info(AB_rev_prop_dialog);
2907     pstate->palitem = palitem;
2908     objlist_load(AB_PROP_REVOLVING, pstate);
2909
2910 }
2911
2912 /*
2913  * Attempt to change the Type of Props being edited
2914  * in the Revolving Prop dialog to the specified
2915  * Palette Item type.  IF there are currently un-applied
2916  * edits pending, handle "auto apply".
2917  */
2918 static PalItemInfo *
2919 revolv_set_prop_type(
2920     PalItemInfo *new_palitem,
2921     ABObj       load_obj
2922 )
2923 {
2924     PalItemInfo         *viz_palitem = new_palitem;
2925     PropStateInfo       *pstate;
2926
2927     if (revolv_current_frame != new_palitem->rev_prop_frame)
2928     {
2929         pstate = get_prop_state_info(AB_rev_prop_dialog);
2930
2931         if (pstate->palitem &&
2932             (*pstate->palitem->prop_pending)(AB_PROP_REVOLVING) == TRUE)
2933             handle_auto_apply(AB_PROP_REVOLVING, pstate,
2934                                 new_palitem, load_obj, &viz_palitem);
2935         else
2936             revolv_change_prop_frame(new_palitem);
2937     }
2938
2939     /* Return current visible Palette Item type (might be different
2940      * than one requested if user canceled load operation during
2941      * auto-apply
2942      */
2943     return(viz_palitem);
2944
2945 }
2946
2947 /*
2948  * Invoke Revolving Property Dialog (create if it doesn't exist)
2949  * and set it's revolving-type to the Palette Item type
2950  * corrsponding to the loadobj's type (if loadobj == NULL, then
2951  * no specific object is being loaded).
2952  */
2953 static PalItemInfo *
2954 revolv_invoke_props(
2955    PalItemInfo   *palitem,
2956    ABObj         load_obj
2957 )
2958 {
2959     PalItemInfo *viz_palitem;
2960
2961     if (!AB_rev_prop_dialog)
2962         revolv_dialog_init(AB_toplevel);
2963
2964     viz_palitem = revolv_set_prop_type(palitem, load_obj);
2965
2966     ab_show_window(AB_rev_prop_dialog);
2967
2968     ui_optionmenu_change_label(revolv_optionmenu, viz_palitem->name);
2969
2970     return(viz_palitem);
2971
2972 }
2973
2974 static void
2975 fixed_invoke_props(
2976     PalItemInfo   *palitem
2977 )
2978 {
2979     Widget              prop_dialog;
2980     PropStateInfo       *pstate;
2981     char                title[64];
2982     static BOOL         first_time = True;
2983
2984     if (palitem->fix_prop_dialog == NULL)
2985     {
2986         prop_dialog = (*(palitem->prop_initialize))(AB_toplevel, AB_PROP_FIXED);
2987
2988         if (prop_dialog != NULL)
2989         {
2990             palitem->fix_prop_dialog = prop_dialog;
2991             pstate = get_prop_state_info(palitem->fix_prop_dialog);
2992
2993             /* Load all current objects of this type into the list */
2994             objlist_load(AB_PROP_FIXED, pstate);
2995         }
2996     }
2997     else
2998         prop_dialog = palitem->fix_prop_dialog;
2999
3000     if (prop_dialog != NULL)
3001     {
3002         if (first_time)
3003         {
3004             ab_position_window(prop_dialog,
3005                         ab_window_is_open(AB_rev_prop_dialog)?
3006                                 AB_rev_prop_dialog : AB_toplevel,
3007                                 AB_WPOS_TILE_HORIZONTAL);
3008             first_time = False;
3009         }
3010
3011         ab_show_window(prop_dialog);
3012     }
3013     else
3014        util_dprintf(1, "fixed_invoke_props: could not initialize Properties for %s\n",
3015                 palitem->name);
3016
3017 }
3018
3019 static int
3020 apply_props(
3021     AB_PROP_TYPE        type,
3022     Widget              dialog
3023 )
3024 {
3025     PropStateInfo       *pstate;
3026
3027     pstate = get_prop_state_info(dialog);
3028
3029     if (pstate->loaded_obj == NULL) /* no object currently loaded */
3030         return OK;
3031
3032     return(apply_prop_changes(type, pstate->loaded_obj, pstate->palitem));
3033
3034 }
3035
3036 /*
3037  * Apply Prop changes to an object
3038  */
3039 static int
3040 apply_prop_changes(
3041     AB_PROP_TYPE type,
3042     ABObj       obj,
3043     PalItemInfo *palitem
3044 )
3045 {
3046     Widget              alt_dialog = NULL;
3047     AB_PROP_TYPE        alt_type;
3048     PropStateInfo       *alt_pstate;
3049     int                 result;
3050
3051     apply_in_progress = True;
3052     result = (*(palitem->prop_apply))(type);
3053     apply_in_progress = False;
3054
3055     /* If same object is also loaded into alternate prop dialog,
3056      * propagate the changes to the alternate dialog.
3057      */
3058     if (type == AB_PROP_REVOLVING && palitem->fix_prop_dialog != NULL)
3059     {
3060         alt_type   = AB_PROP_FIXED;
3061         alt_dialog = palitem->fix_prop_dialog;
3062     }
3063     else if (type == AB_PROP_FIXED &&
3064                 palitem->rev_prop_frame == revolv_current_frame)
3065     {
3066         alt_type   = AB_PROP_REVOLVING;
3067         alt_dialog = AB_rev_prop_dialog;
3068     }
3069
3070     if (alt_dialog)
3071     {
3072         alt_pstate = get_prop_state_info(alt_dialog);
3073         if (alt_pstate->loaded_obj == obj)
3074             (*(palitem->prop_load))(obj, alt_type, LoadAll);
3075     }
3076
3077     return result;
3078 }
3079
3080 /*
3081  * Handle Auto-apply:
3082  * Another object is being loaded into a Prop dialog
3083  * however another object has edits pending;
3084  * Post a Modal Message asking the user to Apply the
3085  * changes or Cancel the Load operation.
3086  * Return the resulting Palette Item type which is
3087  * showing after the user makes a choice.
3088  */
3089 static DTB_MODAL_ANSWER
3090 handle_auto_apply(
3091     AB_PROP_TYPE        prop_type,
3092     PropStateInfo       *pstate,
3093     PalItemInfo         *new_palitem,
3094     ABObj               new_obj,
3095     PalItemInfo         **result
3096 )
3097 {
3098     DTB_MODAL_ANSWER    answer = DTB_ANSWER_NONE;
3099     char                Buf[256];
3100     BOOL                changing_types = FALSE;
3101     STRING              modname;
3102     DtbObjectHelpData   help_data = NULL;
3103
3104     if (pstate->loaded_obj == NULL) /* something's wrong */
3105     {
3106         util_dprintf(1,"handle_auto_apply: NULL previous obj!??\n");
3107         *result = NULL;
3108         return answer;
3109     }
3110
3111     if (new_palitem != pstate->palitem)
3112         changing_types = TRUE;
3113
3114
3115     help_data = (DtbObjectHelpData) util_malloc(sizeof(DtbObjectHelpDataRec));
3116     help_data->help_volume = NULL;
3117     help_data->help_locationID = NULL;
3118
3119     if (dtb_app_resource_rec.implied_apply == True)
3120     {
3121         answer = DTB_ANSWER_ACTION1;
3122     }
3123     else
3124     {
3125         XmString xm_buf = (XmString) NULL;
3126         STRING   loadedObjName = obj_get_name(pstate->loaded_obj);
3127
3128         if (new_obj == NULL)
3129         {
3130             if (changing_types)
3131             {
3132                 sprintf(Buf, catgets(Dtb_project_catd, 100, 34,
3133                 "Properties for \"%s\" have been modified but not Applied.\
3134                 \nApply Changes or Cancel Change-ObjectType operation."),
3135                 loadedObjName);
3136
3137                 help_data->help_text = catgets(Dtb_project_catd, 100,95,
3138                     "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.");
3139             }
3140             else
3141             {
3142                 sprintf(Buf, catgets(Dtb_project_catd, 100, 35,
3143                 "Properties for \"%s\" have been modified but not Applied.\
3144                 \nApply Changes or Cancel Close operation."),
3145                 loadedObjName);
3146
3147                 help_data->help_text = catgets(Dtb_project_catd, 100,96,
3148                     "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.");
3149             }
3150         }
3151         else
3152         {
3153                 STRING   newObjName = obj_get_name(new_obj);
3154
3155                 sprintf(Buf, catgets(Dtb_project_catd, 100, 36,
3156                 "Properties for \"%s\" have been modified but not Applied.\
3157                 \nApply Changes or Cancel Load operation for \"%s\"."),
3158                  loadedObjName, newObjName);
3159
3160                 help_data->help_text = catgets(Dtb_project_catd, 100,93,
3161                     "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.");
3162         }
3163
3164         /* Popup Modal Message and wait for answer */
3165         xm_buf = XmStringCreateLocalized(Buf);
3166         dtb_revolv_prop_pend_msg_initialize(&dtb_revolv_prop_pend_msg);
3167         answer = dtb_show_modal_message(pstate->objlist,
3168                 &dtb_revolv_prop_pend_msg, xm_buf, help_data, NULL);
3169
3170         util_free(help_data);
3171         XmStringFree(xm_buf);
3172     }
3173
3174     switch(answer)
3175     {
3176         case DTB_ANSWER_ACTION1: /* Apply Changes */
3177                 /*
3178                  * If Apply was not successful (value verification failed), then
3179                  * do not change to the new Prop sheet.
3180                  */
3181                 if (apply_prop_changes(prop_type, pstate->loaded_obj, pstate->palitem) != OK)
3182                 {
3183                     *result = pstate->palitem;
3184                     answer = DTB_ANSWER_CANCEL;
3185                 }
3186                 else
3187                 {
3188                     if (!changing_types)
3189                         load_props(prop_type, pstate, new_obj);
3190                     else
3191                         revolv_change_prop_frame(new_palitem);
3192
3193                     *result = new_palitem;
3194                 }
3195                 break;
3196
3197         case DTB_ANSWER_CANCEL: /* Cancel Load */
3198                 if (changing_types)
3199                     ui_optionmenu_change_label(revolv_optionmenu, pstate->palitem->name);
3200                 modname = abobj_get_moduled_name(pstate->loaded_obj);
3201                 ui_list_select_item(pstate->objlist, modname, FALSE);
3202                 util_free(modname);
3203                 *result = pstate->palitem;
3204     }
3205
3206     return answer;
3207 }
3208
3209 static PropStateInfo *
3210 get_prop_state_info(
3211     Widget      widget
3212 )
3213 {
3214     Widget        dialog;
3215     PropStateInfo *pstate;
3216
3217     dialog = ui_get_ancestor_dialog(widget);
3218
3219     XtVaGetValues(dialog, XmNuserData, &pstate, NULL);
3220
3221     return pstate;
3222
3223 }
3224
3225
3226 static void
3227 init_prop_state_info(
3228     Widget              dialog,
3229     PalItemInfo         *palitem,
3230     Widget              objlist,
3231     ABObj               loaded_obj
3232 )
3233 {
3234     PropStateInfo *pstate;
3235
3236     pstate = (PropStateInfo*)util_malloc(sizeof(PropStateInfo));
3237
3238     pstate->palitem = palitem;
3239     pstate->objlist = objlist;
3240     pstate->loaded_obj = loaded_obj;
3241
3242     XtVaSetValues(dialog, XmNuserData, (XtArgVal)pstate, NULL);
3243
3244 }
3245
3246
3247 /*
3248  * Load an object into the Revolving or Fixed Prop dialog
3249  */
3250 static void
3251 load_props(
3252     AB_PROP_TYPE        type,
3253     PropStateInfo       *pstate,
3254     ABObj               obj
3255 )
3256 {
3257     pstate->loaded_obj = obj;
3258
3259     /* Load obj's props */
3260     (*(pstate->palitem->prop_load))(obj, type, LoadAll);
3261 }
3262
3263 static int
3264 objlist_delete_obj(
3265     AB_PROP_TYPE        type,
3266     PalItemInfo         *palitem,
3267     ObjEvDestroyInfo    info
3268 )
3269 {
3270     Widget              dialog;
3271     PropStateInfo       *pstate;
3272     int                 num_items;
3273     int                 first_viz, last_viz;
3274
3275     if (type == AB_PROP_REVOLVING)
3276         dialog = AB_rev_prop_dialog;
3277     else
3278         dialog = palitem->fix_prop_dialog;
3279
3280     pstate = get_prop_state_info(dialog);
3281
3282     cur_list_palitem = palitem;
3283     abobj_list_obj_destroyed(pstate->objlist, info->obj, objlist_test_func);
3284
3285     ui_list_get_info(pstate->objlist, &num_items, &first_viz, &last_viz);
3286
3287     if (num_items == 0) /* Deleted Last one...*/
3288     {
3289          /* Clear Prop Sheet & Make it Inactive */
3290         (*(palitem->prop_clear))(type);
3291         (*(palitem->prop_activate))(type, FALSE);
3292         pstate->loaded_obj = NULL;
3293     }
3294     else if (info->obj == pstate->loaded_obj) /* Deleted "Current" one...*/
3295     {
3296         /* If there are pending edits on the deleted object, first clear
3297          * those edits via a reset before making another object "current"
3298          * in props.
3299          */
3300         if ((*(palitem->prop_pending))(type) == True)
3301             (*(palitem->prop_load))(NULL, type, LoadAll);
3302
3303         ui_list_select_pos(pstate->objlist, 1, TRUE);
3304     }
3305     return 0;
3306 }
3307
3308 /*
3309  * Ensure an item is selected in the Prop dialog list
3310  */
3311 static void
3312 objlist_ensure_selection(
3313     Widget      objlist
3314 )
3315 {
3316     int         num_items = 0;
3317     int         num_selected = 0;
3318
3319     XtVaGetValues(objlist,
3320                 XmNitemCount,         &num_items,
3321                 XmNselectedItemCount, &num_selected,
3322                 NULL);
3323
3324     if (num_selected == 0 && num_items > 0)
3325         ui_list_select_pos(objlist, 1, TRUE);
3326
3327 }
3328
3329 /*
3330  * Traverse the project and load all objects matching the
3331  * Palette Item type into the Prop dialog list
3332  */
3333 static void
3334 objlist_load(
3335     AB_PROP_TYPE        type,
3336     PropStateInfo       *pstate
3337 )
3338 {
3339     ABObj           proj = proj_get_project();
3340     int             num_items = 0;
3341
3342     if (proj == NULL || pstate->objlist == NULL)
3343         return;
3344
3345     /* Reset Loaded-obj to NULL */
3346     pstate->loaded_obj = NULL;
3347
3348     cur_list_palitem = pstate->palitem;
3349     num_items = abobj_list_load(pstate->objlist, proj, objlist_test_func);
3350
3351     /* If there are items in the list, activate the Props,
3352      * else de-activate them.
3353      */
3354     ((*pstate->palitem->prop_activate)(type, num_items > 0? TRUE : FALSE));
3355
3356 }
3357
3358 static int
3359 objlist_rename_obj(
3360     AB_PROP_TYPE        type,
3361     PalItemInfo         *palitem,
3362     ObjEvAttChangeInfo    info
3363 )
3364 {
3365     Widget              dialog;
3366     PropStateInfo       *pstate;
3367
3368     if (type == AB_PROP_REVOLVING)
3369         dialog = AB_rev_prop_dialog;
3370     else
3371         dialog = palitem->fix_prop_dialog;
3372
3373     pstate = get_prop_state_info(dialog);
3374
3375     cur_list_palitem = palitem;
3376     abobj_list_obj_renamed(pstate->objlist, info->obj,
3377                 istr_string(info->old_name),
3378                 objlist_test_func);
3379
3380     return 0;
3381
3382 }
3383
3384 static int
3385 objlist_show_or_hide_obj(
3386     AB_PROP_TYPE        type,
3387     PalItemInfo         *palitem,
3388     ObjEvUpdateInfo     info
3389 )
3390 {
3391     Widget              dialog;
3392     PropStateInfo       *pstate;
3393     int                 orig_num_items = 0;
3394     int                 num_items = 0;
3395     int                 first_vis, last_vis;
3396
3397     if (type == AB_PROP_REVOLVING)
3398         dialog = AB_rev_prop_dialog;
3399     else
3400         dialog = palitem->fix_prop_dialog;
3401
3402     pstate = get_prop_state_info(dialog);
3403
3404     ui_list_get_info(pstate->objlist, &orig_num_items, &first_vis, &last_vis);
3405
3406     cur_list_palitem = palitem;
3407     abobj_list_obj_updated(pstate->objlist, info, objlist_test_func);
3408
3409     ui_list_get_info(pstate->objlist, &num_items, &first_vis, &last_vis);
3410
3411     if (orig_num_items == 0 && num_items > 0)
3412         (*(palitem->prop_activate))(type, TRUE);
3413
3414     if (num_items == 0) /* Hid Last one...*/
3415     {
3416          /* Clear Prop Sheet & Make it Inactive */
3417         (*(palitem->prop_clear))(type);
3418         (*(palitem->prop_activate))(type, FALSE);
3419         pstate->loaded_obj = NULL;
3420     }
3421     else if (!(pstate->loaded_obj != NULL &&
3422                 obj_has_flag(obj_get_module(pstate->loaded_obj), MappedFlag)) ||
3423         num_items == 1)
3424         /* Make sure 1 is selected */
3425         ui_list_select_pos(pstate->objlist, 1, True);
3426
3427     return 0;
3428 }
3429
3430 /*
3431  * Test whether an object should be loaded into the
3432  * Prop Dialog object list
3433  */
3434 static BOOL
3435 objlist_test_func(
3436         ABObj test_obj
3437 )
3438 {
3439     if ((obj_get_module(test_obj) != NULL) &&
3440          obj_is_defined(test_obj) &&
3441          obj_is_salient_ui(test_obj) &&
3442          obj_has_flag(test_obj, MappedFlag))
3443     {
3444         if (cur_list_palitem != NULL)
3445             return((*cur_list_palitem->is_a_test)(test_obj));
3446         return(True);
3447     }
3448     return(False);
3449 }
3450
3451 static void
3452 create_obj_option_item(
3453     PropObjOptionsSetting       pos,
3454     Widget                      item,
3455     ABObj                       obj
3456 )
3457 {
3458     Widget      newitem;
3459     STRING      modname = NULL;
3460     STRING      name = NULL;
3461     XmString    xmitem;
3462
3463     if (obj == NULL)
3464         name = (String)NoneItem;
3465     else if (pos->display_module)
3466         modname = abobj_get_moduled_name(obj);
3467     else
3468         name = obj_get_name(obj);
3469
3470     xmitem = XmStringCreateLocalized(modname? modname : name);
3471
3472     if (item == NULL)
3473     {
3474         /* Create new item */
3475         newitem = XtVaCreateWidget(modname? modname : name,
3476                 xmPushButtonWidgetClass,
3477                 pos->options.menu,
3478                 XmNlabelString, xmitem,
3479                 XmNuserData,    (XtArgVal)obj,
3480                 NULL);
3481
3482         XtAddCallback(newitem, XmNactivateCallback,
3483                         propP_setting_chgCB, (XtPointer)pos->options.changebar);
3484         XtAddCallback(newitem, XmNactivateCallback,
3485                         propP_options_itemCB, (XtPointer)pos->options.menu);
3486     }
3487     else /* Use existing item */
3488         XtVaSetValues(item,
3489                 XmNlabelString, xmitem,
3490                 XmNuserData,    (XtArgVal)obj,
3491                 NULL);
3492
3493     XmStringFree(xmitem);
3494     util_free(modname);
3495
3496 }
3497
3498
3499 /*
3500  ******************************************************************
3501  * Object Callbacks
3502  ******************************************************************
3503  */
3504
3505 /*
3506  * obj-callback: object name has changed - update Prop Dialog lists
3507  */
3508 static int
3509 obj_renamedOCB(
3510     ObjEvAttChangeInfo    info
3511 )
3512 {
3513     PalItemInfo         *palitem;
3514     int                 i;
3515
3516     if (!obj_is_salient(info->obj) ||
3517         obj_get_parent(info->obj) == NULL ||
3518         obj_is_item(info->obj))
3519         return 0;
3520
3521     util_dprintf(3, "obj_renamedOCB: from %s to %s\n", istr_string_safe(info->old_name),
3522         obj_get_name(info->obj));
3523
3524     if (obj_is_module(info->obj)) /* Module name changed */
3525     {
3526         /* Need to update ALL Prop Dialog object lists...*/
3527         for (i = 0; i < palette_item_cnt; i++)
3528         {
3529             palitem = cur_list_palitem = palette_item[i];
3530
3531             if (palitem->rev_prop_frame == revolv_current_frame)
3532                 objlist_rename_obj(AB_PROP_REVOLVING, palitem, info);
3533
3534             if (palitem->fix_prop_dialog != NULL)
3535                 objlist_rename_obj(AB_PROP_FIXED, palitem, info);
3536         }
3537     }
3538     else if ((palitem = pal_get_item_info(info->obj)) != NULL) /* Object name changed */
3539     {
3540         /* If obj's type is currently loaded in Revolving props, update the list */
3541         if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame)
3542             objlist_rename_obj(AB_PROP_REVOLVING, palitem, info);
3543
3544         /* If Fixed Props for obj's type exists, update its list */
3545         if (palitem->fix_prop_dialog != NULL)
3546             objlist_rename_obj(AB_PROP_FIXED, palitem, info);
3547     }
3548     return 0;
3549 }
3550
3551 /*
3552  * obj-callback: object geometry has changed - update Prop sheet if necessary
3553  */
3554 static int
3555 obj_geom_changedOCB(
3556     ObjEvAttChangeInfo    info
3557 )
3558 {
3559     PalItemInfo         *palitem;
3560     PropStateInfo       *pstate;
3561     unsigned long       geomflag = 0;
3562
3563     /* If "apply_in_progress" is True, then this update is being called
3564      * during the apply of geometry changes within a prop sheet, and we
3565      * DO not want to update prop fields in this case because it could
3566      * interfere with the apply.
3567      */
3568     if (!obj_is_salient(info->obj) ||
3569         obj_get_parent(info->obj) == NULL ||
3570         obj_is_item(info->obj) ||
3571         apply_in_progress)
3572         return 0;
3573
3574     /* If a layers's position changes, then we need to update the
3575      * position attrs of any of its panes which are currently loaded
3576      * in props (since, in props, their x,y position is displayed as the
3577      * entire layers's position, even though the panes' *real* position
3578      * within the layers object is 0,0).
3579      */
3580     if (info->atts & OBJEV_ATT_POSITION &&
3581         obj_is_layers(info->obj))
3582     {
3583         ABObj   layers = info->obj;
3584         ABObj   pane;
3585         int     num_panes = obj_get_num_children(layers);
3586         int     i;
3587
3588         for (i=0; i < num_panes; i++)
3589         {
3590             /* Use recursion to call this geometry callback for each
3591              * pane in the layers object
3592              */
3593             pane = obj_get_child(layers, i);
3594             info->obj = pane;
3595             obj_geom_changedOCB(info);
3596         }
3597         info->obj = layers; /* reset back to original obj */
3598     }
3599
3600     if ((palitem = pal_get_item_info(info->obj)) != NULL)
3601     {
3602         util_dprintf(3, "obj_geom_changedOCB: %s's geometry changed to %d,%d %dx%d\n",
3603                 obj_get_name(info->obj), obj_get_x(info->obj), obj_get_y(info->obj),
3604                 obj_get_width(info->obj), obj_get_height(info->obj));
3605
3606         if (info->atts & OBJEV_ATT_POSITION)
3607             geomflag |= LoadPosition;
3608         if (info->atts & OBJEV_ATT_SIZE)
3609             geomflag |= LoadSize;
3610
3611         /* If modified obj is currently loaded in the Revolving prop editor, update
3612          * only its geometry attributes in the prop sheet
3613          */
3614         if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame)
3615         {
3616             pstate = get_prop_state_info(AB_rev_prop_dialog);
3617             if (pstate->loaded_obj == info->obj)
3618                 (*(palitem->prop_load))(NULL, AB_PROP_REVOLVING, geomflag);
3619         }
3620
3621         /* If modified obj is currently loaded in its Fixed prop editor, update
3622          * only its geometry attributes in the prop sheet
3623          */
3624         if (palitem->fix_prop_dialog != NULL)
3625         {
3626             pstate = get_prop_state_info(palitem->fix_prop_dialog);
3627             if (pstate->loaded_obj == info->obj)
3628                 (*(palitem->prop_load))(NULL, AB_PROP_FIXED, geomflag);
3629         }
3630     }
3631     return 0;
3632 }
3633
3634 /*
3635  * obj-callback: object is being destroyed - remove from Prop dialog lists
3636  */
3637 static int
3638 obj_destroyedOCB(
3639     ObjEvDestroyInfo    info
3640 )
3641 {
3642     PalItemInfo *palitem;
3643
3644     if (!obj_is_salient(info->obj) ||
3645          obj_get_parent(info->obj) == NULL ||
3646          obj_is_item(info->obj))
3647         return 0;
3648
3649 #ifdef DEBUG
3650     {
3651         char    buf[1024];
3652         util_dprintf(3, "obj_destroyedOCB: %s\n",
3653             obj_get_safe_name(info->obj, buf, 1024));
3654     }
3655 #endif /* DEBUG */
3656
3657     if ((palitem = pal_get_item_info(info->obj)) != NULL) /* Object being destroyed */
3658     {
3659         /* If obj's type is currently loaded in Revolving props, update the list */
3660         if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame)
3661             objlist_delete_obj(AB_PROP_REVOLVING, palitem, info);
3662
3663         /* If Fixed Props for obj's type exists, update its list */
3664         if (palitem->fix_prop_dialog != NULL)
3665             objlist_delete_obj(AB_PROP_FIXED, palitem, info);
3666     }
3667     return 0;
3668 }
3669
3670 /*
3671  * obj-callback: object being shown or hidden - modify Prop dialog lists
3672  */
3673 static int
3674 obj_shown_or_hiddenOCB(
3675     ObjEvUpdateInfo     info
3676 )
3677 {
3678     PalItemInfo *palitem;
3679     int         i;
3680
3681     if (!obj_is_salient(info->obj) ||
3682          obj_get_parent(info->obj) == NULL ||
3683          obj_is_item(info->obj))
3684         return 0;
3685
3686     util_dprintf(3, "obj_shown_or_hiddenOCB: %s\n",
3687         obj_get_name(info->obj));
3688
3689     if (obj_is_module(info->obj))
3690     {
3691         /* Need to update ALL Prop Dialog object lists...*/
3692         for (i = 0; i < palette_item_cnt; i++)
3693         {
3694             palitem = palette_item[i];
3695
3696             if (palitem->rev_prop_frame == revolv_current_frame)
3697                 objlist_show_or_hide_obj(AB_PROP_REVOLVING, palitem, info);
3698
3699             if (palitem->fix_prop_dialog != NULL)
3700                 objlist_show_or_hide_obj(AB_PROP_FIXED, palitem, info);
3701         }
3702     }
3703     else if ((palitem = pal_get_item_info(info->obj)) != NULL) /* Object being Updated */
3704     {
3705         cur_list_palitem = palitem;
3706
3707         /* If obj's type is currently loaded in Revolving props, update the list */
3708         if (AB_rev_prop_dialog != NULL && revolv_current_frame == palitem->rev_prop_frame)
3709             objlist_show_or_hide_obj(AB_PROP_REVOLVING, palitem, info);
3710
3711         /* If Fixed Props for obj's type exists, update its list */
3712         if (palitem->fix_prop_dialog != NULL)
3713             objlist_show_or_hide_obj(AB_PROP_FIXED, palitem, info);
3714     }
3715     return 0;
3716 }
3717
3718 /*
3719  ******************************************************************
3720  * Xt Callbacks
3721  ******************************************************************
3722  */
3723
3724 /*
3725  * Callback: apply properties for current object
3726  */
3727 static void
3728 apply_propsCB(
3729     Widget      widget,
3730     XtPointer   client_data,
3731     XtPointer   calldata
3732 )
3733 {
3734     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3735     PropStateInfo       *pstate;
3736     Widget              dialog;
3737
3738     if (type == AB_PROP_REVOLVING)
3739         dialog = AB_rev_prop_dialog;
3740     else /* AB_PROP_FIXED */
3741     {
3742         pstate = get_prop_state_info(widget);
3743         dialog = pstate->palitem->fix_prop_dialog;
3744     }
3745
3746     apply_props(type, dialog);
3747
3748 }
3749
3750 /*
3751  * Callback:
3752  */
3753 static void
3754 cancel_propsCB(
3755     Widget      widget,
3756     XtPointer   client_data,
3757     XtPointer   calldata
3758 )
3759 {
3760     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3761     PropStateInfo       *pstate;
3762     Widget              dialog;
3763
3764     pstate = get_prop_state_info(widget);
3765
3766     if (type == AB_PROP_REVOLVING)
3767         dialog = AB_rev_prop_dialog;
3768
3769     else /* AB_PROP_FIXED */
3770         dialog = pstate->palitem->fix_prop_dialog;
3771
3772     (*(pstate->palitem->prop_load))(NULL,type,LoadAll);
3773
3774     ui_win_show(dialog, False, XtGrabNone);
3775
3776 }
3777
3778 /*
3779  * Callback: a new object has been selected off object menu
3780  */
3781 static void
3782 change_objecttypeCB(
3783     Widget      widget,
3784     XtPointer   client_data,
3785     XtPointer   calldata
3786 )
3787 {
3788     PalEditableObjInfo  *ed_obj_info = (PalEditableObjInfo*)client_data;
3789     PalItemInfo         *viz_palitem;
3790     PropStateInfo       *pstate;
3791
3792     viz_palitem = revolv_set_prop_type(ed_obj_info->palitem, NULL);
3793
3794     if (viz_palitem == ed_obj_info->palitem)
3795     {
3796         /* Object-type change was successful */
3797         pstate = get_prop_state_info(AB_rev_prop_dialog);
3798         objlist_ensure_selection(pstate->objlist);
3799     }
3800     else
3801         /* Object-type change rejected; reset object-type */
3802         ui_optionmenu_change_label(revolv_optionmenu, viz_palitem->name);
3803
3804
3805 }
3806
3807 /*
3808  * Callback: Prop dialog has been closed -- check for pending changes
3809  */
3810 static void
3811 close_propsCB(
3812     Widget      widget,
3813     XtPointer   client_data,
3814     XtPointer   calldata
3815 )
3816 {
3817     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3818     DTB_MODAL_ANSWER    answer;
3819     PalItemInfo         *palitem = NULL;
3820     PropStateInfo       *pstate;
3821     WidgetList          shell_child;
3822     Widget              dialog;
3823
3824     /* Get Immediate child of Shell */
3825     XtVaGetValues(widget,
3826                 XmNchildren,    &shell_child,
3827                 NULL);
3828
3829     dialog = shell_child[0];
3830     pstate = get_prop_state_info(dialog);
3831
3832     if ((*(pstate->palitem->prop_pending))(type) == TRUE)
3833         /* An Object is loaded with pending changes...*/
3834         answer = handle_auto_apply(type, pstate, pstate->palitem, NULL, &palitem);
3835
3836     if (answer != DTB_ANSWER_CANCEL)
3837         XtPopdown(widget);
3838
3839 }
3840
3841 /*
3842  * Callback: popup Attachment Editor
3843  */
3844 static void
3845 invoke_attach_editorCB(
3846     Widget      widget,
3847     XtPointer   client_data,
3848     XtPointer   calldata
3849 )
3850 {
3851     AB_PROP_TYPE type = (AB_PROP_TYPE)client_data;
3852     PropStateInfo       *pstate;
3853
3854     pstate = get_prop_state_info(widget);
3855
3856     if (pstate->loaded_obj == NULL)
3857         return;
3858
3859     attch_ed_show_dialog(pstate->loaded_obj);
3860 }
3861
3862 /*
3863  * Callback: popup Connections Editor
3864  */
3865 static void
3866 invoke_connectionsCB(
3867     Widget      widget,
3868     XtPointer   client_data,
3869     XtPointer   calldata
3870 )
3871 {
3872     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3873     PropStateInfo       *pstate;
3874
3875     pstate = get_prop_state_info(widget);
3876
3877     if (pstate->loaded_obj == NULL)
3878         return;
3879
3880     conn_set_source(pstate->loaded_obj);
3881     conn_set_target(NULL);
3882     conn_popup_dialog(widget, (XtPointer)0, NULL);
3883 }
3884
3885 /*
3886  * Callback: popup Help Editor Dialog
3887  */
3888 static void
3889 invoke_help_editorCB(
3890     Widget      widget,
3891     XtPointer   client_data,
3892     XtPointer   calldata
3893 )
3894 {
3895     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3896     PropStateInfo       *pstate;
3897
3898     pstate = get_prop_state_info(widget);
3899
3900     if (pstate->loaded_obj == NULL)
3901         return;
3902
3903     ab_set_help_obj(pstate->loaded_obj);
3904     ab_popup_help(widget,(XtPointer)0,NULL);
3905 }
3906
3907 static void
3908 objlist_selectCB(
3909     Widget      widget,
3910     XtPointer   client_data,
3911     XmListCallbackStruct *listdata
3912 )
3913 {
3914     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3915     PropStateInfo       *pstate;
3916     PalItemInfo         *palitem = NULL;
3917     ABObj               module;
3918     ABObj               selected_obj;
3919     STRING              name;
3920
3921     pstate = get_prop_state_info(widget);
3922
3923     name = objxm_xmstr_to_str(listdata->item);
3924     if (name)
3925     {
3926         abobj_moduled_name_extract(name, &module, &selected_obj);
3927         util_free(name);
3928
3929         /* If the object selected in the list is the one already
3930          * loaded, then don't do anything.
3931          */
3932         if (selected_obj && selected_obj != pstate->loaded_obj)
3933         {
3934             if ((*(pstate->palitem->prop_pending))(type) == TRUE)
3935                 /* An Object is loaded with pending changes...*/
3936                 handle_auto_apply(type, pstate, pstate->palitem, selected_obj, &palitem);
3937             else
3938                 load_props(type, pstate, selected_obj);
3939             return;
3940         }
3941     }
3942 }
3943
3944 /*
3945  * Callback: apply properties for current object & take down dialog
3946  */
3947 static void
3948 ok_propsCB(
3949     Widget      widget,
3950     XtPointer   client_data,
3951     XtPointer   calldata
3952 )
3953 {
3954     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3955     PropStateInfo       *pstate;
3956     Widget              dialog;
3957
3958     if (type == AB_PROP_REVOLVING)
3959         dialog = AB_rev_prop_dialog;
3960
3961     else /* AB_PROP_FIXED */
3962     {
3963         pstate = get_prop_state_info(widget);
3964         dialog = pstate->palitem->fix_prop_dialog;
3965     }
3966
3967     if (apply_props(type, dialog) == OK)
3968         ui_win_show(dialog, False, XtGrabNone);
3969
3970 }
3971
3972 /*
3973  * Callback: reset properties for current object
3974  */
3975 static void
3976 reset_propsCB(
3977     Widget      widget,
3978     XtPointer   client_data,
3979     XtPointer   calldata
3980 )
3981 {
3982     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
3983     PropStateInfo       *pstate;
3984
3985     pstate = get_prop_state_info(widget);
3986
3987     (*(pstate->palitem->prop_load))(NULL,type,LoadAll);
3988
3989 }
3990
3991 /*
3992  * Callback:
3993  */
3994 static void
3995 tearoff_propsCB(
3996     Widget      widget,
3997     XtPointer   client_data,
3998     XtPointer   calldata
3999 )
4000 {
4001     PropStateInfo       *pstate;
4002
4003     pstate = get_prop_state_info(AB_rev_prop_dialog);
4004
4005     if (pstate->loaded_obj != NULL)
4006         prop_load_obj(pstate->loaded_obj, AB_PROP_FIXED);
4007     else
4008         fixed_invoke_props(pstate->palitem);
4009
4010 }
4011
4012 static void
4013 color_chooserCB(
4014     Widget   w,
4015     XtPointer clientdata,
4016     XtPointer calldata
4017 )
4018 {
4019     PropColorSetting    pcs = (PropColorSetting)clientdata;
4020     String              color_choice;
4021     Pixel               c;
4022     int                 status;
4023
4024     color_choice = display_color_chooser();
4025
4026     if (color_choice[0] != 0)
4027     {
4028         /* This should never error since the chooser enforces choosing
4029          * a valid & available color, but check just to be sure.
4030          */
4031         if ((status = objxm_name_to_pixel(w, color_choice, &c)) == OK)
4032         {
4033              XtVaSetValues(pcs->swatch,
4034                 XmNbackground, c,
4035                 NULL);
4036              XmTextSetString(pcs->field, color_choice);
4037         }
4038     }
4039 }
4040
4041 static void
4042 color_noneCB(
4043     Widget   w,
4044     XtPointer clientdata,
4045     XtPointer calldata
4046 )
4047 {
4048     PropColorSetting    pcs = (PropColorSetting)clientdata;
4049
4050     /* Reset Swatch to appear transparent */
4051     prop_colorfield_set_value(pcs, "", True);
4052
4053 }
4054
4055 static void
4056 menu_newCB(
4057     Widget      w,
4058     XtPointer   client_data,
4059     XtPointer   call_data
4060 )
4061 {
4062     PropMenunameSetting pms = (PropMenunameSetting)client_data;
4063     PropStateInfo       *pstate;
4064     AB_PROP_TYPE        alt_prop_type = AB_PROP_FIXED;
4065     ABObj               module;
4066     Widget              prop_dialog;
4067     STRING              base = NULL;
4068     STRING              unique_name;
4069     STRING              menu_name;
4070     STRING              name;
4071
4072     /* Build a menu-name based on the menu-owner's name or label */
4073     if (pms->owner_name_field != NULL)
4074     {
4075         /* Use owner's name as prefix */
4076         base = ui_field_get_string(pms->owner_name_field);
4077     }
4078
4079     module = obj_get_module(*(pms->current_obj_ptr));
4080     name = (base? ab_ident_from_name_and_label(base, "menu") : "menu");
4081     menu_name = strdup(name);
4082     unique_name = obj_alloc_unique_name_for_child(module, menu_name, -1);
4083
4084     /* We want to create/load the new menu in a separate editor if
4085      * possible so that the user can view both the new menu AND the
4086      * object which owns it simultaneously.  However, if we are currently
4087      * in the Fixed Menu Props dialog and there is an object loaded in
4088      * the Revolving Prop dialog which has *pending* edits, don't try
4089      * to use it (suddently changing it's type & object will probably
4090      * confuse the user!).
4091      */
4092     if (pms->prop_type == AB_PROP_FIXED)
4093     {
4094         prop_dialog = ui_get_ancestor_dialog(pms->owner_name_field);
4095
4096         /* Try using the Revolving Prop Editor if either we are currently
4097          * in the Menu Fixed Props, or if the Menu Fixed Props has
4098          * edits pending...
4099          */
4100         if (prop_dialog == ab_menu_palitem->fix_prop_dialog ||
4101             (ab_menu_palitem->fix_prop_dialog &&
4102              (*ab_menu_palitem->prop_pending)(AB_PROP_FIXED) == True))
4103         {
4104             pstate = get_prop_state_info(AB_rev_prop_dialog);
4105
4106             if (pstate->palitem &&
4107                (*pstate->palitem->prop_pending)(AB_PROP_REVOLVING) == False)
4108             {
4109                 alt_prop_type = AB_PROP_REVOLVING;
4110                 revolv_invoke_props(ab_menu_palitem, NULL);
4111             }
4112         }
4113     }
4114
4115     if (alt_prop_type == AB_PROP_FIXED)
4116         prop_show_fixed(ab_menu_palitem);
4117
4118     /* Insert the new menu name into the owner's field, UNLESS we
4119      * happen to be inside the Fixed Menu Prop dialog AND are also
4120      * creating the new menu in the Fixed Menu Prop dialog.
4121      */
4122     if (pal_create_menu(alt_prop_type, module, unique_name, NULL) == 0 &&
4123         !(prop_dialog == ab_menu_palitem->fix_prop_dialog &&
4124           alt_prop_type == AB_PROP_FIXED))
4125         ui_field_set_string(pms->field, unique_name);
4126
4127     util_free(base);
4128     util_free(menu_name);
4129     util_free(unique_name);
4130 }
4131
4132 static BOOL
4133 is_submenu_of(
4134     STRING      submenu_name,
4135     ABObj       menu
4136 )
4137 {
4138     ABObj       item;
4139     AB_TRAVERSAL trav;
4140     BOOL        is_sub = False;
4141
4142     for(trav_open(&trav, menu, AB_TRAV_ITEMS);
4143        (item = trav_next(&trav)) != NULL; )
4144     {
4145         if (util_strcmp(obj_get_menu_name(item), submenu_name) == 0)
4146         {
4147            is_sub = True;
4148            break;
4149         }
4150     }
4151     trav_close(&trav);
4152     return is_sub;
4153 }
4154
4155 static void
4156 find_submenu_owners(
4157     ABObj       submenu,
4158     ABObj       *menulist,
4159     int         menu_count,
4160     ABObj       *i_menulist,
4161     int         *i_count_ptr
4162 )
4163 {
4164     STRING      submenu_name;
4165     int         i;
4166
4167     submenu_name = obj_get_name(submenu);
4168     for(i = 0; i < menu_count; i++)
4169     {
4170         if (submenu != menulist[i] &&
4171             is_submenu_of(submenu_name, menulist[i]))
4172         {
4173             i_menulist[(*i_count_ptr)++] = menulist[i];
4174             find_submenu_owners(menulist[i], menulist, menu_count,
4175                 i_menulist, i_count_ptr);
4176         }
4177     }
4178 }
4179
4180 static BOOL
4181 menu_in_list(
4182    ABObj        *menulist,
4183    int          menu_count,
4184    ABObj        target_menu
4185 )
4186 {
4187     int i;
4188
4189     for(i = 0; i < menu_count; i++)
4190         if (menulist[i] == target_menu)
4191             return True;
4192
4193     return False;
4194 }
4195
4196 static void
4197 menulist_buildCB(
4198     Widget      widget,
4199     XtPointer   client_data,
4200     XtPointer   call_data
4201 )
4202 {
4203     PropMenunameSetting pms;
4204     ABObj       current_obj;
4205     ABObj       *menus;
4206     ABObj       *ineligible_menus = NULL;
4207     int         num_menus = 0;
4208     int         ineligible_count = 0;
4209     Widget      submenu;
4210     Widget      menus_item = (Widget)client_data;
4211     Widget      menus_menu = NULL;
4212     Widget      menus_menuitem;
4213     Widget      menu_field;
4214     STRING      menu_name;
4215     int         num_children;
4216     int         i, j;
4217
4218     XtVaGetValues(widget, XmNsubMenuId, &submenu, NULL);
4219     XtVaGetValues(menus_item, XmNuserData, &pms, NULL);
4220
4221     current_obj = *(pms->current_obj_ptr);
4222
4223     abobj_build_menus_array(obj_get_module(current_obj), &menus, &num_menus);
4224
4225     if (num_menus > 0)
4226     {
4227         if (obj_is_menu(current_obj)) /* Need to prevent circular menus */
4228         {
4229             /* Build up a list of menus that belong to the current menu's
4230              * ancestory (if it's a submenu) - these menus will not be eligible
4231              * for selection as a submenu off the current menu.
4232              */
4233             ineligible_menus = (ABObj*)util_malloc(num_menus*sizeof(ABObj));
4234             ineligible_menus[ineligible_count++] = current_obj;
4235             find_submenu_owners(current_obj, menus, num_menus,
4236                 ineligible_menus, &ineligible_count);
4237         }
4238
4239         for (j = 0; j < num_menus; j++)
4240         {
4241             if (menus_menu == NULL)
4242                 menus_menu = XmCreatePulldownMenu(submenu, "menus_menu", NULL, 0);
4243
4244             menu_name = obj_get_name(menus[j]);
4245
4246             menus_menuitem = XtVaCreateManagedWidget("menus_menuitem",
4247                         xmCascadeButtonWidgetClass,
4248                         menus_menu,
4249                         XtVaTypedArg, XmNlabelString, XtRString,
4250                                 menu_name, strlen(menu_name)+1,
4251                         NULL);
4252
4253             /* If Menu is ineligible to be a Submenu, make it inactive */
4254             if (menu_in_list(ineligible_menus, ineligible_count, menus[j]))
4255                 ui_set_active(menus_menuitem, False);
4256
4257             XtAddCallback(menus_menuitem, XmNactivateCallback,
4258                         menuname_setCB, (XtPointer)pms->field);
4259         }
4260
4261         ui_set_active(menus_item, TRUE);
4262         XtVaSetValues(menus_item, XmNsubMenuId, menus_menu, NULL);
4263         XtVaSetValues(submenu, XmNuserData, (XtArgVal)menus_menu, NULL);
4264
4265         util_free(menus);
4266         util_free(ineligible_menus);
4267     }
4268     else /* No Menus - inactivate the item */
4269     {
4270         ui_set_active(menus_item, FALSE);
4271         XtVaSetValues(submenu, XmNuserData, (XtArgVal)NULL, NULL);
4272     }
4273 }
4274
4275 /*
4276  * Callback: destroy the Menu->Names submenu after it pops down
4277  */
4278 static void
4279 menulist_destroyCB(
4280     Widget      w,
4281     XtPointer   client_data,
4282     XtPointer   calldata
4283 )
4284 {
4285     Widget      submenu = (Widget)client_data;
4286     Widget      menus_menu;
4287
4288     XtVaGetValues(submenu, XmNuserData, &menus_menu, NULL);
4289
4290     if (menus_menu != NULL)
4291         XtDestroyWidget(menus_menu);
4292 }
4293
4294 static void
4295 menu_edit_set_stateCB(
4296     Widget      widget,
4297     XtPointer   client_data,
4298     XtPointer   call_data
4299 )
4300 {
4301     PropMenunameSetting         pms;
4302     Widget                      edit_item = (Widget)client_data;
4303     STRING                      current_menuname = NULL;
4304
4305     /* Set the "Edit Current" item to be active ONLY if there is a
4306      * menu name in the field
4307      */
4308     XtVaGetValues(edit_item, XmNuserData, &pms, NULL);
4309     current_menuname = ui_field_get_string(pms->field);
4310     ui_set_active(edit_item, !util_strempty(current_menuname));
4311     util_free(current_menuname);
4312 }
4313
4314
4315 /*
4316  * Callback: Clear Menu Name field
4317  */
4318 static void
4319 menuname_clearCB(
4320     Widget      w,
4321     XtPointer   client_data,
4322     XtPointer   calldata
4323 )
4324 {
4325     PropMenunameSetting pms = (PropMenunameSetting)client_data;
4326     ui_field_set_string(pms->field, "");
4327
4328 }
4329
4330 /*
4331  * Callback: an item off the Menu->Names submenu was selected:
4332  * Set the value of the menu textfield to its label
4333  */
4334 static void
4335 menuname_setCB(
4336     Widget      w,
4337     XtPointer   client_data,
4338     XtPointer   calldata
4339 )
4340 {
4341     Widget      menu_field = (Widget)client_data;
4342     XmString    xm_menuname;
4343     STRING      menu_name;
4344
4345     XtVaGetValues(w, XmNlabelString, &xm_menuname, NULL);
4346     menu_name = objxm_xmstr_to_str(xm_menuname);
4347     ui_field_set_string(menu_field, menu_name);
4348     util_free(menu_name);
4349 }
4350
4351 static void
4352 menu_editCB(
4353     Widget      w,
4354     XtPointer   client_data,
4355     XtPointer   call_data
4356 )
4357 {
4358     PropMenunameSetting pms = (PropMenunameSetting)client_data;
4359     STRING              current_menuname = NULL;
4360     ABObj               module;
4361     ABObj               menu;
4362
4363     current_menuname = ui_field_get_string(pms->field);
4364     module = obj_get_module(*(pms->current_obj_ptr));
4365
4366     if (!util_strempty(current_menuname))
4367     {
4368         if ((menu = obj_find_by_name(module, current_menuname)) != NULL)
4369             prop_load_obj(menu, pms->prop_type == AB_PROP_FIXED?
4370                 AB_PROP_REVOLVING : AB_PROP_FIXED);
4371         else
4372         {
4373             STRING  fmtStr = NULL;
4374             STRING  help_buf = NULL;
4375             char Buf[256];
4376
4377             fmtStr = XtNewString(catgets(Dtb_project_catd, 100, 135,
4378                 "The menu with the name \"%s\" does not exist in\nthe module \"%s\". Specify a valid menu name."));
4379
4380             help_buf = (STRING) util_malloc(strlen(fmtStr) +
4381                 strlen(current_menuname) + strlen(obj_get_name(module)) +1);
4382             sprintf(help_buf, fmtStr, current_menuname, obj_get_name(module));
4383
4384             util_set_help_data(help_buf, NULL, NULL);
4385             sprintf(Buf, catgets(Dtb_project_catd, 100, 134,
4386                 "Could not find menu \"%s\" in module \"%s\"."),
4387                 current_menuname, obj_get_name(module));
4388             propP_popup_message(pms->field, Buf, False);
4389
4390             XtFree(fmtStr);
4391             util_free(help_buf);
4392         }
4393     }
4394     util_free(current_menuname);
4395 }
4396
4397 static void
4398 menu_field_chgCB(
4399     Widget      w,
4400     XtPointer   client_data,
4401     XtPointer   call_data
4402 )
4403 {
4404     PropMenunameSetting pms = (PropMenunameSetting)client_data;
4405     STRING              value;
4406     BOOL                menu_there = False;
4407
4408     if (pms->menu_title_pfs)
4409     {
4410         /* If a non-empty string in in Menu field, make Title active */
4411         value = ui_field_get_string(pms->field);
4412         menu_there = (!util_strempty(value));
4413         ui_set_active(pms->menu_title_pfs->label, menu_there);
4414         ui_set_active(pms->menu_title_pfs->field, menu_there);
4415         util_free(value);
4416     }
4417 }
4418
4419
4420 int
4421 prop_geomfield_clear(
4422     PropGeometrySetting pgs,
4423     GEOM_KEY            gkey
4424 )
4425 {
4426     Widget      field = NULL;
4427
4428     switch(gkey)
4429     {
4430         case GEOM_X:
4431             field = pgs->x_field;
4432             break;
4433         case GEOM_Y:
4434             field = pgs->y_field;
4435             break;
4436         case GEOM_WIDTH:
4437             field = pgs->w_field;
4438             break;
4439         case GEOM_HEIGHT:
4440             field = pgs->h_field;
4441             break;
4442         default:
4443             field = NULL;
4444     }
4445
4446     if (field)
4447     {
4448         /* Set state so changebar is not triggered */
4449         XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_LOAD,NULL);
4450
4451         /* Convert int to string */
4452         ui_field_set_string(field, NULL);
4453
4454         /* Reset state */
4455         XtVaSetValues(field, XmNuserData, (XtArgVal)PROP_EDIT,NULL);
4456     }
4457
4458     return OK;
4459 }
4460
4461 static void
4462 obj_options_buildCB(
4463     Widget      widget,
4464     XtPointer   client_data,
4465     XtPointer   call_data
4466 )
4467 {
4468     PropObjOptionsSetting pos = (PropObjOptionsSetting)client_data;
4469
4470     prop_obj_options_load(pos, pos->search_root);
4471 }
4472
4473 void
4474 strings_init(
4475 )
4476 {
4477     LabelForString =
4478         XtNewString(catgets(Dtb_project_catd, 100, 215, "Label:"));
4479     LabelForGraphic =
4480         XtNewString(catgets(Dtb_project_catd, 100, 216, "Graphic Filename:"));
4481     NoneItem =
4482         XtNewString(catgets(Dtb_project_catd, 100, 217, "None"));
4483     XFieldStr =
4484         XtNewString(catgets(Dtb_project_catd, 100, 218, "X Field"));
4485     YFieldStr =
4486         XtNewString(catgets(Dtb_project_catd, 100, 219, "Y Field"));
4487     WFieldStr =
4488         XtNewString(catgets(Dtb_project_catd, 100, 220, "Width Field"));
4489     HFieldStr =
4490         XtNewString(catgets(Dtb_project_catd, 100, 221, "Height Field"));
4491     OffsetFieldStr =
4492         XtNewString(catgets(Dtb_project_catd, 100, 222, "Offset Field"));
4493     PercentageFieldStr =
4494         XtNewString(catgets(Dtb_project_catd, 100, 223, "Percentage Field"));
4495     menu_strs[0] =
4496         XtNewString(catgets(Dtb_project_catd, 100, 224, "None"));
4497     menu_strs[1] =
4498         XtNewString(catgets(Dtb_project_catd, 100, 225, "Create New Menu..."));
4499     menu_strs[2] =
4500         XtNewString(catgets(Dtb_project_catd, 100, 226, "Menus"));
4501     menu_strs[3] =
4502         XtNewString(catgets(Dtb_project_catd, 100, 227, "Edit Current..."));
4503     RowColFieldStr =
4504         XtNewString(catgets(Dtb_project_catd, 100, 250, "Rows/Columns Field"));
4505     VertSpacingFieldStr =
4506         XtNewString(catgets(Dtb_project_catd, 100, 251, "Vertical Spacing Field"));
4507     HorizSpacingFieldStr =
4508         XtNewString(catgets(Dtb_project_catd, 100, 252, "Horizontal Spacing Field"));
4509 }