Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / pal_menu.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: pal_menu.c /main/5 1996/08/08 18:02:46 mustafa $
25  *
26  * @(#)pal_menu.c       1.38 15 Feb 1994      cde_app_builder/src/ab
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  * pal_menu.c - Implements Palette Menu object functionality
45  *              NOTE: menu not actually ON the main palette
46  */
47 #include <stdio.h>
48 #include <Xm/Xm.h>
49 #include <ab_private/obj_notify.h>
50 #include <ab_private/trav.h>
51 #include <ab_private/objxm.h>
52 #include <ab_private/ab.h>
53 #include <ab_private/pal.h>
54 #include <ab_private/proj.h>
55 #include <ab_private/prop.h>
56 #include <ab_private/abobj.h>
57 #include <ab_private/abobj_set.h>
58 #include <ab_private/abobj_edit.h>
59 #include <ab_private/ui_util.h>
60 #include "menu_ui.h"
61
62
63 typedef struct  PROP_MENU_SETTINGS
64 {
65     Widget                      prop_sheet;
66     PropFieldSettingRec         name;
67     PropRadioSettingRec         tearoff;
68     Widget                      color_label;
69     PropColorSettingRec         bg_color;
70     PropColorSettingRec         fg_color;
71     Widget                      item_list_label;
72     Widget                      item_list_button_group;
73     PropFieldSettingRec         item_label;
74     PropOptionsSettingRec       item_label_type;
75     PropFieldSettingRec         item_mnemonic;
76     PropFieldSettingRec         item_accel;
77     PropOptionsSettingRec       item_line_style;
78     PropCheckboxSettingRec      item_state;
79     PropMenunameSettingRec      item_menuname;
80     PropItemsSettingRec         items;
81     Widget                      button_group;
82     Widget                      edit_menu;
83     ABObj                       current_obj;
84     ABObj                       clipboard_menu;
85 } PropMenuSettingsRec, *PropMenuSettings;
86
87 /*************************************************************************
88 **                                                                      **
89 **       Private Function Declarations                                  **
90 **                                                                      **
91 **************************************************************************/
92 /*
93  * Methods
94  */
95 static int      menu_initialize(
96                     ABObj   obj
97                 );
98 static Widget   menu_prop_init(
99                     Widget  parent,
100                     AB_PROP_TYPE type
101                 );
102 static int      menu_prop_activate(
103                     AB_PROP_TYPE type,
104                     BOOL         active
105                 );
106 static int      menu_prop_clear(
107                     AB_PROP_TYPE type
108                 );
109 static int      menu_prop_load(
110                     ABObj        obj,
111                     AB_PROP_TYPE type,
112                     unsigned long loadkey
113                 );
114 static int      menu_prop_apply(
115                     AB_PROP_TYPE type
116                 );
117 static BOOL     menu_prop_pending(
118                     AB_PROP_TYPE type
119                 );
120
121 static BOOL     verify_props(
122                     AB_PROP_TYPE type
123                 );
124 static void     turnoff_changebars(
125                     AB_PROP_TYPE type
126                 );
127
128 /*
129  * Menu Clipboard Functions
130  */
131 static void     edit_item_init(
132                     Widget       widget,
133                     AB_PROP_TYPE ptype,
134                     AB_EDIT_TYPE etype
135                 );
136 static void     copy_menu_to_clipboard(
137                     ABObj       mobj,
138                     ABObj       *menu_clipboard
139                 );
140
141 /*
142  * ABObj callbacks
143  */
144 static int      prop_menu_obj_destroy_CB(
145                     ObjEvDestroyInfo destroyInfo
146                 );
147 static int      prop_menu_install_obj_destroy_CB(void);
148
149 /*
150  * Xt Callbacks
151  */
152 static void     menu_createCB(
153                     Widget      widget,
154                     XtPointer   client_data,
155                     XtPointer   call_data
156                 );
157 static void     menu_editCB(
158                     Widget      widget,
159                     XtPointer   client_data,
160                     XtPointer   call_data
161                 );
162 static void     set_edit_menu_stateCB(
163                     Widget      widget,
164                     XtPointer   client_data,
165                     XtPointer   call_data
166                 );
167
168 /*************************************************************************
169 **                                                                      **
170 **       Data                                                            **
171 **                                                                      **
172 **************************************************************************/
173 PalItemInfo menu_palitem_rec = {
174
175     /* type             */  AB_TYPE_MENU,
176     /* name             */  "Menu",
177     /* animation pixmaps*/  NULL,
178     /* number of pixmaps*/  0,
179     /* rev_prop_frame   */  NULL,
180     /* fix_prop_dialog  */  NULL,
181     /* initialize       */  menu_initialize,
182     /* is_a_test        */  obj_is_menu,
183     /* prop_initialize  */  menu_prop_init,
184     /* prop_activate    */  menu_prop_activate,
185     /* prop_clear       */  menu_prop_clear,
186     /* prop_load        */  menu_prop_load,
187     /* prop_apply       */  menu_prop_apply,
188     /* prop_pending     */  menu_prop_pending
189
190 };
191
192 PalItemInfo *ab_menu_palitem = &menu_palitem_rec;
193 PropMenuSettingsRec prop_menu_settings_rec[AB_PROP_TYPE_NUM_VALUES];
194
195
196 /*************************************************************************
197 **                                                                      **
198 **       Function Definitions                                           **
199 **                                                                      **
200 **************************************************************************/
201 static int
202 menu_initialize(
203     ABObj    obj
204 )
205 {
206     STRING      items[2];
207     ABObj       iobj;
208     int         i;
209
210     if (util_strempty(obj_get_name(obj)))
211     {
212         obj_set_unique_name(obj, "menu");
213     }
214
215     obj_set_is_initially_active(obj, True);
216
217     /* Add initial items to Choice */
218     items[0] = catgets(Dtb_project_catd,   6, 136, "Item1");
219     items[1] = catgets(Dtb_project_catd, 100, 259, "Item2");
220     for (i=0; i < XtNumber(items); i++)
221     {
222         iobj = obj_create(AB_TYPE_ITEM, NULL);
223         obj_append_child(obj, iobj);
224         obj_set_subtype(iobj, AB_ITEM_FOR_MENU);
225         iobj->label_type = AB_LABEL_STRING;
226         obj_set_is_initially_active(iobj, True);
227         abobj_set_item_name(iobj, obj_get_module(obj), obj_get_name(obj), items[i]);
228         obj_set_label(iobj, items[i]);
229     }
230
231     return OK;
232 }
233
234 static Widget
235 menu_prop_init(
236     Widget    parent,
237     AB_PROP_TYPE type
238 )
239 {
240     DtbMenuPropDialogInfoRec    rev_menu_prop_dialog; /* Revolving Props */
241     DtbMenuPropDialogInfo       cgen = &dtb_menu_prop_dialog; /* Codegen structure */
242     DtbRevolvPropDialogInfo     rpd = &(dtb_revolv_prop_dialog);
243     PropMenuSettingsRec         *pms = &(prop_menu_settings_rec[type]);
244     Widget                      item[12];
245     int                         item_val[12];
246     Widget                      item2[12];
247     int                         item2_val[12];
248     int                         i, n, j;
249
250     if (type == AB_PROP_REVOLVING)
251     {
252         /* Cloning Trick:
253          * Only the Attributes ControlPanel needs to be created within
254          * the existing Revolving Prop dialog, so fill out all other
255          * fields with the Revolving Prop dialog equivelents, so the
256          * dtb initialize proc will skip those non-NULL fields...
257          */
258         dtbMenuPropDialogInfo_clear(&rev_menu_prop_dialog);
259
260         cgen = &(rev_menu_prop_dialog);
261         cgen->prop_dialog = rpd->prop_dialog;
262         cgen->prop_dialog_shellform = rpd->prop_dialog_shellform;
263         cgen->prop_dialog_panedwin = rpd->prop_dialog_panedwin;
264         cgen->prop_dialog_form = rpd->prop_dialog_form;
265         cgen->objlist_panel = rpd->objlist_panel;
266         cgen->objlist_label = rpd->objlist_label2;
267         cgen->objlist_scrolledwin = rpd->objlist_scrolledwin;
268         cgen->objlist = rpd->objlist;
269         cgen->attrs_ctrlpanel_frame = rpd->attrs_ctrlpanel_frame;
270         cgen->activate_panel = rpd->activate_panel;
271         cgen->apply_button = rpd->apply_button;
272         cgen->ok_button = rpd->ok_button;
273         cgen->cancel_button = rpd->cancel_button;
274         cgen->reset_button = rpd->reset_button;
275         cgen->help_button = rpd->help_button;
276
277         /*
278          * Get notification of object destruction!
279          */
280         prop_menu_install_obj_destroy_CB();
281
282     }
283     else /* AB_PROP_FIXED */
284         cgen = &dtb_menu_prop_dialog;
285
286     if (dtb_menu_prop_dialog_initialize(cgen, parent) == 0)
287     {
288         pms->prop_sheet = cgen->attrs_ctrlpanel;
289         pms->current_obj = NULL;
290         pms->clipboard_menu = NULL;
291
292         if (type == AB_PROP_REVOLVING)
293             XtVaSetValues(parent,
294                         XmNuserData, pms->current_obj,
295                         NULL);
296
297         /* Dialog/Object List */
298         if (type == AB_PROP_FIXED)
299         {
300             prop_fixed_dialog_init(ab_menu_palitem,
301                         cgen->prop_dialog_shellform, cgen->objlist);
302             prop_activate_panel_init(type, ab_menu_palitem,
303                         cgen->ok_button, cgen->apply_button,
304                         cgen->reset_button, cgen->cancel_button,
305                         cgen->help_button);
306         }
307
308         /* Alternate Editor Buttons */
309         prop_editors_panel_init(type, ab_menu_palitem,
310             NULL, cgen->conn_button, cgen->helptxt_button);
311
312         /*
313           * Prop Sheet Settings....
314          */
315         /* New & Edit Buttons */
316         XtAddCallback(cgen->newbutton, XmNactivateCallback,
317                 menu_createCB, (XtPointer)type);
318
319         edit_item_init(cgen->menuedit_mbutton_menu_editmenu_items.Cut_item,
320                 type, AB_EDIT_CUT);
321         edit_item_init(cgen->menuedit_mbutton_menu_editmenu_items.Copy_item,
322                 type, AB_EDIT_COPY);
323         edit_item_init(cgen->menuedit_mbutton_menu_editmenu_items.Paste_item,
324                 type, AB_EDIT_PASTE);
325         edit_item_init(cgen->menuedit_mbutton_menu_editmenu_items.Delete_item,
326                 type, AB_EDIT_DELETE);
327
328         pms->edit_menu = cgen->menuedit_mbutton_menu_editmenu;
329         XtAddCallback(XtParent(pms->edit_menu), XtNpopupCallback,
330                 set_edit_menu_stateCB, (XtPointer)type);
331
332         /* Name */
333         prop_field_init(&(pms->name), cgen->name_field_label,
334                 cgen->name_field, cgen->name_cb);
335
336         /* Tear-off */
337         n = 0;
338         item[n] = cgen->tearoff_rbox_items.Enabled_item;
339         item_val[n] = True; n++;
340         item[n] = cgen->tearoff_rbox_items.Disabled_item;
341         item_val[n] = False; n++;
342         prop_radiobox_init(&(pms->tearoff), cgen->tearoff_rbox_label,
343                 cgen->tearoff_rbox, n, item, (XtPointer*)item_val,
344                 cgen->tearoff_cb);
345
346         /* Color */
347         prop_colorfield_init(&(pms->bg_color), cgen->bg_mbutton,
348                 cgen->bg_mbutton_bg_mbutton_menu_items.None_item,
349                 cgen->bg_mbutton_bg_mbutton_menu_items.Color_Chooser_item,
350                 cgen->bg_swatch, cgen->bg_field, cgen->bg_cb);
351
352         prop_colorfield_init(&(pms->fg_color), cgen->fg_mbutton,
353                 cgen->fg_mbutton_fg_mbutton_menu_items.None_item,
354                 cgen->fg_mbutton_fg_mbutton_menu_items.Color_Chooser_item,
355                 cgen->fg_swatch, cgen->fg_field, cgen->fg_cb);
356         pms->color_label = cgen->color_label;
357
358         /* Item Editor....*/
359
360         pms->item_list_label = cgen->itemlist_label;
361         pms->item_list_button_group = cgen->item_button_group;
362
363         /* Item Label */
364         prop_field_init(&(pms->item_label), cgen->itemlabel_field_label,
365                 cgen->itemlabel_field, cgen->itemlist_cb);
366         n = 0;
367         item[n] = cgen->itemlabeltype_opmenu_items.String_item;
368         item_val[n] = AB_LABEL_STRING; n++;
369         item[n] = cgen->itemlabeltype_opmenu_items.Graphic_item;
370         item_val[n] = AB_LABEL_GLYPH; n++;
371         item[n] = cgen->itemlabeltype_opmenu_items.Separator_item;
372         item_val[n] = AB_LABEL_SEPARATOR; n++;
373         prop_options_init(&(pms->item_label_type), cgen->itemlabeltype_opmenu_label,
374                 cgen->itemlabeltype_opmenu, cgen->itemlabeltype_opmenu_menu,
375                 n, item, (XtPointer*)item_val, cgen->itemlist_cb);
376
377         for(i=0; i < n; i++)
378             XtAddCallback(item[i], XmNactivateCallback,
379                   (XtCallbackProc)prop_item_labeltypeCB, (XtPointer)&(pms->items));
380
381         /* Item Mnemonic */
382         prop_field_init(&(pms->item_mnemonic), cgen->mnemonic_field_label,
383                 cgen->mnemonic_field, cgen->itemlist_cb);
384
385         /* Item Accelerator */
386         prop_field_init(&(pms->item_accel), cgen->accel_field_label,
387                 cgen->accel_field, cgen->itemlist_cb);
388
389         /* Item Line Style */
390         n = 0;
391         item[n] = cgen->linestyle_opmenu_items.None_item;
392         item_val[n] = AB_LINE_NONE; n++;
393         item[n] = cgen->linestyle_opmenu_items.Etched_In_item;
394         item_val[n] = AB_LINE_ETCHED_IN; n++;
395         item[n] = cgen->linestyle_opmenu_items.Etched_Out_item;
396         item_val[n] = AB_LINE_ETCHED_OUT; n++;
397         item[n] = cgen->linestyle_opmenu_items.Etched_In_Dash_item;
398         item_val[n] = AB_LINE_ETCHED_IN_DASH; n++;
399         item[n] = cgen->linestyle_opmenu_items.Etched_Out_Dash_item;
400         item_val[n] = AB_LINE_ETCHED_OUT_DASH; n++;
401         item[n] = cgen->linestyle_opmenu_items.Single_Line_item;
402         item_val[n] = AB_LINE_SINGLE_LINE; n++;
403         item[n] = cgen->linestyle_opmenu_items.Double_Line_item;
404         item_val[n] = AB_LINE_DOUBLE_LINE; n++;
405         item[n] = cgen->linestyle_opmenu_items.Single_Dashed_Line_item;
406         item_val[n] = AB_LINE_SINGLE_DASHED_LINE; n++;
407         item[n] = cgen->linestyle_opmenu_items.Double_Dashed_Line_item;
408         item_val[n] = AB_LINE_DOUBLE_DASHED_LINE; n++;
409         prop_options_init(&(pms->item_line_style), cgen->linestyle_opmenu_label,
410                 cgen->linestyle_opmenu, cgen->linestyle_opmenu_menu,
411                 n, item, (XtPointer*)item_val,
412                 cgen->itemlist_cb);
413         prop_options_set_value(&(pms->item_line_style), (XtPointer)AB_LINE_ETCHED_OUT, False);
414
415         /* Item State */
416         n = 0;
417         item[n] = cgen->itemstate_ckbox_items.Active_item;
418         item_val[n] = AB_STATE_ACTIVE; n++;
419         prop_checkbox_init(&(pms->item_state), cgen->itemstate_ckbox_label,
420                 cgen->itemstate_ckbox, n, item, item_val,
421                 cgen->itemlist_cb);
422
423         /* Item Menu Name */
424         prop_menuname_init(&(pms->item_menuname), type, cgen->label,
425                         cgen->item_menu_mbutton,
426                         cgen->item_menu_field,
427                         cgen->itemlabel_field, cgen->itemlist_cb, NULL/*title*/,
428                         &(pms->current_obj), True);
429
430         /* Store Items->Insert menu items in array */
431         n = 0;
432         item[n] = cgen->item_edit_mbutton_editmenu_items.Add_Before_item;
433         item_val[n] = INSERT_BEFORE; n++;
434         item[n] = cgen->item_edit_mbutton_editmenu_items.Add_After_item;
435         item_val[n] = INSERT_AFTER; n++;
436
437         /* Store Items->Edit menu items in array */
438         j = 0;
439         item2[j] = cgen->item_edit_mbutton_editmenu_items.Cut_item;
440         item2_val[j] = AB_EDIT_CUT; j++;
441         item2[j] = cgen->item_edit_mbutton_editmenu_items.Copy_item;
442         item2_val[j] = AB_EDIT_COPY; j++;
443         item2[j] = cgen->item_edit_mbutton_editmenu_items.Paste_item;
444         item2_val[j] = AB_EDIT_PASTE; j++;
445         item2[j] = cgen->item_edit_mbutton_editmenu_items.Delete_item;
446         item2_val[j] = AB_EDIT_DELETE; j++;
447         item2[j] = cgen->item_edit_mbutton_editmenu_items.Change_item;
448         item2_val[j] = EDIT_CHANGE; j++;
449
450         /* Hook up Item Editing mechanism to Item List*/
451         prop_item_editor_init(&(pms->items), AB_ITEM_FOR_MENU,
452                 cgen->itemlist, cgen->itemlist_cb,
453                 cgen->item_add_button,
454                 n, item, item_val, /* Insert */
455                 j, item2, item2_val,/* Edit */
456                 &(pms->item_label), &(pms->item_label_type), cgen->graphic_hint,
457                 &(pms->item_mnemonic), &(pms->item_accel), &(pms->item_line_style),
458                 &(pms->item_state), &(pms->item_menuname),
459                 &(pms->current_obj));
460
461         pms->button_group = cgen->button_group;
462
463         prop_changebars_cleared(pms->prop_sheet);
464
465         return (cgen->prop_dialog_shellform);
466     }
467     else
468         return NULL;
469 }
470
471 static int
472 menu_prop_activate(
473     AB_PROP_TYPE type,
474     BOOL         active
475 )
476 {
477     /*
478      * Since the "Add Menu" button must remain active at all times, we cannot
479      * make the entire prop sheet inactive;  Therefore, we set sensitivity
480      * on more specific controls in the prop sheet (not the entire Form).
481      */
482
483     ui_set_active(prop_menu_settings_rec[type].name.label, active);
484     ui_set_active(prop_menu_settings_rec[type].name.field, active);
485
486     ui_set_active(prop_menu_settings_rec[type].tearoff.label, active);
487     ui_set_active(prop_menu_settings_rec[type].tearoff.radiobox, active);
488
489     ui_set_active(prop_menu_settings_rec[type].item_list_label, active);
490     ui_set_active(prop_menu_settings_rec[type].item_list_button_group, active);
491     ui_set_active(prop_menu_settings_rec[type].item_label.label, active);
492     ui_set_active(prop_menu_settings_rec[type].item_label.field, active);
493     ui_set_active(prop_menu_settings_rec[type].item_label_type.label, active);
494     ui_set_active(prop_menu_settings_rec[type].item_label_type.optionbox, active);
495     ui_set_active(prop_menu_settings_rec[type].item_mnemonic.label, active);
496     ui_set_active(prop_menu_settings_rec[type].item_mnemonic.field, active);
497     ui_set_active(prop_menu_settings_rec[type].item_accel.label, active);
498     ui_set_active(prop_menu_settings_rec[type].item_accel.field, active);
499     ui_set_active(prop_menu_settings_rec[type].item_line_style.label, active);
500     ui_set_active(prop_menu_settings_rec[type].item_line_style.optionbox, active);
501     ui_set_active(prop_menu_settings_rec[type].item_state.label, active);
502     ui_set_active(prop_menu_settings_rec[type].item_state.checkbox, active);
503     ui_set_active(prop_menu_settings_rec[type].item_menuname.label, active);
504     ui_set_active(prop_menu_settings_rec[type].item_menuname.menubutton, active);
505     ui_set_active(prop_menu_settings_rec[type].item_menuname.field, active);
506     ui_set_active(prop_menu_settings_rec[type].items.item_list, active);
507
508     ui_set_active(prop_menu_settings_rec[type].color_label, active);
509     ui_set_active(prop_menu_settings_rec[type].bg_color.menubutton, active);
510     ui_set_active(prop_menu_settings_rec[type].bg_color.field, active);
511     ui_set_active(prop_menu_settings_rec[type].fg_color.menubutton, active);
512     ui_set_active(prop_menu_settings_rec[type].fg_color.field, active);
513
514     ui_set_active(prop_menu_settings_rec[type].button_group, active);
515
516     return OK;
517 }
518
519
520 static int
521 menu_prop_clear(
522     AB_PROP_TYPE type
523 )
524 {
525     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
526
527     /* Clear Name */
528     prop_field_set_value(&(pms->name), "", False);
529
530     /* Clear Tearoff */
531     prop_radiobox_set_value(&(pms->tearoff),  (XtPointer)False, False);
532
533     /* Clear Background Color */
534     prop_colorfield_set_value(&(pms->bg_color), "", False);
535
536     /* Clear Foreground Color */
537     prop_colorfield_set_value(&(pms->fg_color), "", False);
538
539     /* Clear Items */
540     prop_item_editor_clear(&(pms->items));
541
542     pms->current_obj = NULL;
543
544     turnoff_changebars(type);
545
546     return OK;
547
548 }
549
550 static int
551 menu_prop_load(
552     ABObjPtr     obj,
553     AB_PROP_TYPE type,
554     unsigned long loadkey
555 )
556 {
557     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
558     BOOL                load_all = (loadkey & LoadAll);
559
560     if (obj == NULL)
561     {
562         if (pms->current_obj != NULL)
563             obj = pms->current_obj;
564         else
565             return ERROR;
566     }
567     else if (!obj_is_menu(obj))
568         return ERROR;
569     else
570         pms->current_obj = obj;
571
572     /* Load Name */
573     if (load_all || loadkey & LoadName)
574         prop_field_set_value(&(pms->name), obj_get_name(obj), False);
575
576     if (load_all)
577     {
578         /* Load Tearoff */
579         prop_radiobox_set_value(&(pms->tearoff),
580                 (XtPointer)(obj->info.menu.tear_off), False);
581
582         /* Load Color */
583         prop_colorfield_set_value(&(pms->bg_color), obj_get_bg_color(obj), False);
584         prop_colorfield_set_value(&(pms->fg_color), obj_get_fg_color(obj), False);
585
586         /* Load Items */
587         prop_item_editor_load(&(pms->items), obj);
588
589         turnoff_changebars(type);
590     }
591
592     return OK;
593 }
594
595 static int
596 menu_prop_apply(
597     AB_PROP_TYPE   type
598 )
599 {
600     PropMenuSettingsRec         *pms = &(prop_menu_settings_rec[type]);
601     STRING                      value;
602     BOOL                        reset_bg = False;
603     BOOL                        reset_fg = False;
604
605     if (!verify_props(type))
606         return ERROR;
607
608     if (prop_changed(pms->name.changebar))
609     {
610         value = prop_field_get_value(&(pms->name));
611         abobj_set_name(pms->current_obj, value);
612         util_free(value);
613     }
614     if (prop_changed(pms->tearoff.changebar))
615     {
616         abobj_set_tearoff(pms->current_obj, prop_radiobox_get_value(&(pms->tearoff)));
617     }
618     if (prop_changed(pms->fg_color.changebar))
619     {
620         value = prop_colorfield_get_value(&(pms->fg_color));
621         abobj_set_foreground_color(pms->current_obj, value);
622         if (util_strempty(value))
623             reset_fg = True;
624         util_free(value);
625         prop_colorfield_set_value(&(pms->fg_color),
626                 obj_get_fg_color(pms->current_obj), False);
627     }
628     if (prop_changed(pms->bg_color.changebar))
629     {
630         value = prop_colorfield_get_value(&(pms->bg_color));
631         abobj_set_background_color(pms->current_obj, value);
632         if (util_strempty(value))
633             reset_bg = True;
634         util_free(value);
635         prop_colorfield_set_value(&(pms->bg_color),
636                 obj_get_bg_color(pms->current_obj), False);
637     }
638     if (prop_changed(pms->items.changebar))
639     {
640         /* Ensure edits to current item are saved before apply */
641         prop_item_change(&(pms->items), False);
642         prop_item_editor_apply(&(pms->items));
643     }
644    /*
645     * Menus are a SPECIAL CASE:
646     * Menu objects are NOT instantiated during build-mode, therefore DO NOT
647     * call abobj_instantiate_changes()
648     */
649     turnoff_changebars(type);
650
651     return OK;
652 }
653
654 static BOOL
655 menu_prop_pending(
656     AB_PROP_TYPE type
657 )
658 {
659     return(prop_changebars_pending(prop_menu_settings_rec[type].prop_sheet));
660 }
661
662 static BOOL
663 verify_props(
664     AB_PROP_TYPE type
665 )
666 {
667     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
668
669     if (prop_changed(pms->name.changebar) &&
670         !prop_name_ok(pms->current_obj, pms->name.field))
671         return False;
672
673     if (prop_changed(pms->fg_color.changebar) && !prop_color_ok(pms->fg_color.field))
674         return False;
675
676     if (prop_changed(pms->bg_color.changebar) && !prop_color_ok(pms->bg_color.field))
677         return False;
678
679     return True;
680 }
681
682
683 static void
684 turnoff_changebars(
685     AB_PROP_TYPE type
686 )
687 {
688     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
689
690     prop_set_changebar(pms->name.changebar,             PROP_CB_OFF);
691     prop_set_changebar(pms->tearoff.changebar,          PROP_CB_OFF);
692     prop_set_changebar(pms->bg_color.changebar,         PROP_CB_OFF);
693     prop_set_changebar(pms->fg_color.changebar,         PROP_CB_OFF);
694     prop_set_changebar(pms->items.changebar,            PROP_CB_OFF);
695
696     prop_changebars_cleared(pms->prop_sheet);
697
698 }
699
700 static void
701 edit_item_init(
702     Widget       widget,
703     AB_PROP_TYPE ptype,
704     AB_EDIT_TYPE etype
705 )
706 {
707     XtVaSetValues(widget, XmNuserData, (XtArgVal)etype, NULL);
708     XtAddCallback(widget, XmNactivateCallback, menu_editCB, (XtPointer)ptype);
709 }
710
711 static void
712 set_edit_menu_stateCB(
713     Widget      widget,
714     XtPointer   client_data,
715     XtPointer   call_data
716 )
717 {
718     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
719     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
720     BOOL                menu_exists = False;
721     BOOL                clipboard_full = False;
722     WidgetList          menu_items;
723     int                 num_menu_items;
724     int                 value;
725     AB_EDIT_TYPE        item_key;
726     int                 i;
727
728     menu_exists = (pms->current_obj != NULL);
729     clipboard_full = (pms->clipboard_menu != NULL);
730
731     XtVaGetValues(pms->edit_menu,
732                 XmNnumChildren, &num_menu_items,
733                 XmNchildren,    &menu_items,
734                 NULL);
735
736     /* Loop through the Edit menuitems, setting their sensitivity
737      * according to the state of the Menu Props editor
738      */
739     for (i = 0; i < num_menu_items; i++)
740     {
741         XtVaGetValues(menu_items[i], XmNuserData, &value, NULL);
742         item_key = (AB_EDIT_TYPE)value;
743
744         switch(item_key)
745         {
746             case AB_EDIT_CUT:
747             case AB_EDIT_COPY:
748             case AB_EDIT_DELETE:
749                 ui_set_active(menu_items[i], menu_exists);
750                 break;
751             case AB_EDIT_PASTE:
752                 ui_set_active(menu_items[i], clipboard_full);
753                 break;
754             default:
755                 break;
756                 /* do nothing */
757         }
758     }
759 }
760
761
762 static void
763 copy_menu_to_clipboard(
764     ABObj       mobj,
765     ABObj       *menu_clipboard
766 )
767 {
768     ABObj       old_selection;
769     ABObj       new_selection;
770
771     old_selection = *menu_clipboard;
772     new_selection = obj_tree_dup(mobj);
773
774     /* We must clear the MappedFlag so that the editors do not
775      * think this menu (or immediately after a "paste", the menu copy)
776      * is "shown".
777      */
778     obj_tree_clear_flag(new_selection, MappedFlag);
779
780     *menu_clipboard = new_selection;
781
782     if (old_selection != NULL)
783         obj_destroy(old_selection);
784 }
785
786
787 int
788 pal_create_menu(
789     AB_PROP_TYPE        type,
790     ABObj               module,
791     STRING              menu_name,
792     STRING              menu_title
793 )
794 {
795     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
796     ABObj        newmenu;
797
798     if (module == NULL) /* No module created yet */
799     {
800         ABObj   proj = proj_get_project();
801
802         module = obj_create(AB_TYPE_MODULE, proj);
803         abobj_set_save_needed(proj, True);
804         obj_set_name(module, "module");
805         abobj_show_tree(module, FALSE);
806         proj_set_cur_module(module);
807         proj_show_name_dlg(module, pms->prop_sheet);
808     }
809     newmenu = obj_create(AB_TYPE_MENU, module);
810     abobj_set_save_needed(module, True);
811
812     /* menu_name MUST already be unique! */
813     obj_set_name(newmenu, menu_name);
814
815     pal_initialize_obj(newmenu);
816     abobj_show_tree(newmenu, False);
817
818     prop_load_obj(newmenu, type);
819
820     /* Set Focus directly to Item Label field */
821     ui_field_select_string(pms->item_label.field, True);
822
823     return 0;
824 }
825
826 static void
827 menu_createCB(
828     Widget      widget,
829     XtPointer   client_data,
830     XtPointer   call_data
831 )
832 {
833     AB_PROP_TYPE type = (AB_PROP_TYPE)client_data;
834     STRING      name = NULL;
835     char        nameBuf[5001] = "";
836
837     name = obj_get_unique_name_for_child(
838                 proj_get_cur_module(), "menu", 5000, nameBuf);
839     pal_create_menu(type, proj_get_cur_module(), name, "Menu");
840
841 }
842
843 static void
844 menu_editCB(
845     Widget      widget,
846     XtPointer   client_data,
847     XtPointer   call_data
848 )
849 {
850     AB_PROP_TYPE        type = (AB_PROP_TYPE)client_data;
851     PropMenuSettingsRec *pms = &(prop_menu_settings_rec[type]);
852     char                namebuf[512];
853     STRING              name;
854     AB_EDIT_TYPE        etype;
855     ABObj               module;
856     ABObj               newmenu;
857     ABObj               delmenu;
858
859     module = proj_get_cur_module();
860
861     XtVaGetValues(widget, XmNuserData, &etype, NULL);
862
863     switch(etype)
864     {
865         case AB_EDIT_CUT:
866             if (pms->current_obj != NULL)
867             {
868                 copy_menu_to_clipboard(pms->current_obj, &(pms->clipboard_menu));
869                 delmenu = pms->current_obj;
870                 obj_destroy(delmenu);
871             }
872             break;
873         case AB_EDIT_COPY:
874             if (pms->current_obj != NULL)
875                 copy_menu_to_clipboard(pms->current_obj, &(pms->clipboard_menu));
876             break;
877         case AB_EDIT_PASTE:
878             if (pms->clipboard_menu != NULL)
879             {
880                 /* We need to use some trickery here in order to give the
881                  * new copy of the menu an incremented/unique name based
882                  * on the clipboard menu's name.  We must temporarily re-name
883                  * the clipboard menu so that the dup'd copy won't get an
884                  * identicle name as the clipboard menu (which in turn will
885                  * cause the prop sheet mechanism to think the clipboard menu
886                  * is being renamed, rather than a new menu being added).
887                  * Trust me - this works.
888                  */
889
890                 /* store off original clipboard menu name and temporarily
891                  * set it to a dummy string.
892                  */
893                 strcpy(namebuf, obj_get_name(pms->clipboard_menu));
894                 obj_set_name(pms->clipboard_menu, "MENU_DUMMY");
895
896                 /* duplicate clipboard menu & menu-items */
897                 newmenu = obj_tree_dup(pms->clipboard_menu);
898                 obj_append_child(proj_get_cur_module(), newmenu);
899
900                 /* Change name to be based on clipboard menu name instead
901                  * of "MENU_DUMMY"; Note that abobj_set_name() will also
902                  * take care of updating the menu-item names.
903                  */
904                 name = obj_alloc_unique_name(newmenu, namebuf, -1);
905                 abobj_set_name(newmenu, name);
906
907                 /* reset the clipboard menu name back to original */
908                 obj_set_name(pms->clipboard_menu, namebuf);
909                 util_free(name);
910
911                 abobj_show_tree(newmenu, False);
912                 prop_load_obj(newmenu, type);
913             }
914             break;
915         case AB_EDIT_DELETE:
916             if (pms->current_obj != NULL)
917             {
918                 delmenu = pms->current_obj;
919                 obj_destroy(delmenu);
920             }
921             break;
922         default:
923             /* catch-all case to avoid compiler warnings */
924             break;
925     }
926 }
927
928
929 /*
930  * Object destroy callback
931  */
932 static int
933 prop_menu_install_obj_destroy_CB()
934 {
935     static BOOL callback_installed = False;
936
937     if (callback_installed)
938     {
939         return 0;
940     }
941     obj_add_destroy_callback(prop_menu_obj_destroy_CB, "Menu Props");
942     return 0;
943 }
944
945 static int
946 prop_menu_obj_destroy_CB(ObjEvDestroyInfo destroyInfo)
947 {
948     PropMenuSettingsRec *pms;
949     int                 i;
950     ABObj               doomedObj = destroyInfo->obj;
951     ABObj               obj, item;
952     AB_TRAVERSAL        trav;
953     STRING              doomed_menu_name;
954
955     if (!obj_is_menu_item(doomedObj) &&
956         !obj_is_menu(doomedObj))
957     {
958         return 0;
959     }
960
961     for (i = 1; i < AB_PROP_TYPE_NUM_VALUES; i++)
962     {
963         pms = &(prop_menu_settings_rec[i]);
964
965         if (pms->current_obj == doomedObj)
966             pms->current_obj = NULL;
967         if (pms->items.current_item == doomedObj)
968             pms->items.current_item = NULL;
969         if (pms->items.clipboard_item == doomedObj)
970             pms->items.clipboard_item = NULL;
971     }
972
973     if (obj_is_menu(doomedObj) && obj_get_parent(doomedObj) != NULL)
974     {
975         doomed_menu_name = obj_get_name(doomedObj);
976
977         /* Look through the module to see if any objects refer to
978          * the menu being destroyed.  If so, set their menu-name attributes
979          * to NULL.
980          */
981         for (trav_open(&trav, obj_get_module(doomedObj), AB_TRAV_SALIENT);
982             (obj= trav_next(&trav)) != NULL; )
983             if (util_strcmp(obj_get_menu_name(obj), doomed_menu_name) == 0)
984                 abobj_set_menu_name(obj, "");
985
986         trav_close(&trav);
987
988         for (i = 1; i < AB_PROP_TYPE_NUM_VALUES; i++)
989         {
990             pms = &(prop_menu_settings_rec[i]);
991
992             /* Look to see if any of the clipboard menu item's refer to
993              * the menu being destroyed.  If so, set their menu-name attributes
994              * to NULL.
995              */
996             if (pms->clipboard_menu != NULL)
997             {
998                 for (trav_open(&trav, pms->clipboard_menu, AB_TRAV_ITEMS);
999                     (item = trav_next(&trav)) != NULL; )
1000                     if (util_strcmp(obj_get_menu_name(item), doomed_menu_name) == 0)
1001                         obj_set_menu_name(item, NULL);
1002             }
1003             trav_close(&trav);
1004         }
1005     }
1006     return 0;
1007 }