Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / pal_panedwin.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_panedwin.c /main/3 1995/11/06 17:41:05 rswiston $
25  *
26  *      @(#)pal_panedwin.c      1.10 01 May 1995
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  * panedwin.c - functions for Paned Window prop sheet.
45  */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <stdlib.h>
50 #include <sys/param.h>          /* MAXPATHLEN */
51 #include <Xm/Xm.h>
52 #include <Xm/List.h>
53 #include <ab/util_types.h>
54 #include <ab_private/ab.h>
55 #include <ab_private/obj.h>
56 #include <ab_private/pal.h>
57 #include <ab_private/prop.h>
58 #include <ab_private/proj.h>
59 #include <ab_private/brws.h>
60 #include <ab_private/abobj.h>
61 #include <ab_private/abobj_set.h>
62 #include <ab_private/abobj_list.h>
63 #include <ab_private/ui_util.h>
64 #include <ab_private/obj_notify.h>
65 #include <ab_private/objxm.h>
66 #include "panedwin_ed_ui.h"
67
68 typedef struct  PROP_PANEDWIN_SETTINGS
69 {
70     Widget                      prop_sheet;
71     PropFieldSettingRec         name;
72     PropCheckboxSettingRec      init_state;
73     Widget                      panelist;
74     Widget                      width;
75     Widget                      height;
76     PropGeometrySettingRec      min_max_geo;
77     ABObj                       current_pw_obj;
78     ABObj                       current_pane_obj;
79 } PropPanedWinSettingsRec, *PropPanedWinSettings;
80
81
82 /*************************************************************************
83 **                                                                      **
84 **       Private Function Declarations                                  **
85 **                                                                      **
86 **************************************************************************/
87
88 static int      panedwin_initialize(
89                     ABObj    obj
90                 );
91 static Widget   panedwin_prop_init(
92                     Widget      parent,
93                     AB_PROP_TYPE type
94                 );
95 static int      panedwin_prop_load(
96                     ABObj        obj,
97                     AB_PROP_TYPE type,
98                     unsigned long loadkey
99                 );
100 static int      panedwin_load_panes(
101                     ABObj       obj,
102                     AB_PROP_TYPE type
103                 );
104 static int      panedwin_prop_clear(
105                     AB_PROP_TYPE type
106                 );
107 static int      panedwin_prop_clear_geom(
108                     AB_PROP_TYPE type
109                 );
110 static int      panedwin_prop_activate(
111                     AB_PROP_TYPE type,
112                     BOOL         active
113                 );
114 static int      panedwin_prop_apply(
115                     AB_PROP_TYPE type
116                 );
117 static BOOL     panedwin_prop_pending(
118                     AB_PROP_TYPE type
119                 );
120 static void     panedwinEdP_init();
121 static BOOL     pw_child_test_func(
122                     ABObj test_obj
123                 );
124 static BOOL     verify_props(
125                     AB_PROP_TYPE type
126                 );
127 static void     turnoff_changebars(
128                     AB_PROP_TYPE type
129                 );
130
131 static int      position_compare(
132                     const void *leftEntry,
133                     const void *rightEntry
134                 );
135
136 static int      east_compare(
137                     const void *leftEntry,
138                     const void *rightEntry
139                 );
140
141 static int      west_compare(
142                     const void *leftEntry,
143                     const void *rightEntry
144                 );
145
146 /*
147  * Callbacks
148  */
149 static int      pw_obj_reparentedOCB(
150                     ObjEvReparentInfo   info
151                 );
152 static int      pw_obj_destroyedOCB(
153                     ObjEvDestroyInfo    info
154                 );
155 static int      pw_obj_renamedOCB(
156                     ObjEvAttChangeInfo  info
157                 );
158 static void     pw_panelist_selectCB(
159                     Widget              widget,
160                     XtPointer           client_data,
161                     XmListCallbackStruct *listdata
162                 );
163
164 /*************************************************************************
165 **                                                                      **
166 **       Data                                                           **
167 **                                                                      **
168 **************************************************************************/
169
170 PalItemInfo panedwin_palitem_rec = {
171     /* type             */  AB_TYPE_CONTAINER,
172     /* name             */  "Paned Window",
173     /* animation pixmaps*/  NULL,
174     /* number of pixmaps*/  0,
175     /* rev_prop_frame   */  NULL,
176     /* fix_prop_dialog  */  NULL,
177     /* initialize       */  panedwin_initialize,
178     /* is_a_test        */  obj_is_paned_win,
179     /* prop_initialize  */  panedwin_prop_init,
180     /* prop_active      */  panedwin_prop_activate,
181     /* prop_clear       */  panedwin_prop_clear,
182     /* prop_load        */  panedwin_prop_load,
183     /* prop_apply       */  panedwin_prop_apply,
184     /* prop_pending     */  panedwin_prop_pending
185 };
186
187 PalItemInfo *ab_panedwin_palitem = &panedwin_palitem_rec;
188 PropPanedWinSettingsRec    prop_pw_settings_rec[AB_PROP_TYPE_NUM_VALUES];
189
190 /*************************************************************************
191 **                                                                      **
192 **       Function Definitions                                           **
193 **                                                                      **
194 **************************************************************************/
195 static int
196 panedwin_initialize(
197     ABObj    obj
198 )
199 {
200     if (!obj_is_paned_win(obj))
201         return ERROR;
202
203     obj_set_unique_name(obj, "panedwin"); 
204     obj_set_is_initially_active(obj, True);
205
206     return OK;
207 }
208
209 static Widget
210 panedwin_prop_init(
211     Widget              parent,
212     AB_PROP_TYPE        type
213 )
214 {
215     DtbPanedwinEdDialogInfoRec  rev_panedwin_prop_dialog;
216     DtbPanedwinEdDialogInfo     cgen = &dtb_panedwin_ed_dialog; /* Codegen structure */
217     DtbRevolvPropDialogInfo     rpd = &(dtb_revolv_prop_dialog);
218     PropPanedWinSettingsRec     *pws = &(prop_pw_settings_rec[type]);
219     Widget                      item[2];
220     int                         item_val[2];
221     int                         n = 0;
222
223     if (type == AB_PROP_REVOLVING)
224     {
225         /* Cloning Trick:
226          * Only the Attributes ControlPanel needs to be created within
227          * the existing Revolving Prop dialog, so fill out all other
228          * fields with the Revolving Prop dialog equivelents, so the
229          * dtb initialize proc will skip those non-NULL fields...
230          */
231         dtbPanedwinEdDialogInfo_clear(&rev_panedwin_prop_dialog);
232  
233         cgen = &(rev_panedwin_prop_dialog);
234         cgen->dialog = rpd->prop_dialog;
235         cgen->dialog_shellform = rpd->prop_dialog_shellform;
236         cgen->dialog_panedwin = rpd->prop_dialog_panedwin;
237         cgen->dialog_form = rpd->prop_dialog_form;
238         cgen->objlist_panel = rpd->objlist_panel;
239         cgen->objlist_label = rpd->objlist_label2;
240         cgen->objlist_scrolledwin = rpd->objlist_scrolledwin;
241         cgen->objlist = rpd->objlist;
242         cgen->attrs_ctrlpanel_frame = rpd->attrs_ctrlpanel_frame;
243         cgen->activate_panel = rpd->activate_panel;
244         cgen->apply_button = rpd->apply_button;
245         cgen->ok_button = rpd->ok_button;
246         cgen->cancel_button = rpd->cancel_button;
247         cgen->reset_button = rpd->reset_button;
248         cgen->help_button = rpd->help_button;
249     }
250     else /* AB_PROP_FIXED */
251         cgen = &dtb_panedwin_ed_dialog;
252
253     if (dtb_panedwin_ed_dialog_initialize(cgen, parent) == 0)
254     {
255         pws->prop_sheet = cgen->attrs_ctrlpanel;
256         pws->panelist = cgen->panelist;
257         pws->current_pw_obj = NULL;
258         pws->current_pane_obj = NULL;
259         pws->width = cgen->width_value;
260         pws->height = cgen->height_value;
261
262         /* Add Update, Rename, and Destroy object callbacks */
263         panedwinEdP_init();
264
265         /* Add Callback to load pane children values when a pane 
266          * is selected from the "Panes" list. 
267          */
268         XtAddCallback(cgen->panelist,
269                 XmNbrowseSelectionCallback,
270                 (XtCallbackProc)pw_panelist_selectCB, (XtPointer)type);
271
272         if (type == AB_PROP_REVOLVING)
273                 XtVaSetValues(parent,
274                         XmNuserData, pws->current_pw_obj,
275                         NULL);
276
277         /* Dialog/Object List */
278         if (type == AB_PROP_FIXED)
279         {
280             prop_fixed_dialog_init(ab_panedwin_palitem,
281                         cgen->dialog_shellform, cgen->objlist);
282             prop_activate_panel_init(type, ab_panedwin_palitem,
283                         cgen->ok_button, cgen->apply_button,
284                         cgen->reset_button, cgen->cancel_button,
285                         cgen->help_button);
286         }
287
288         /* Alternate Editor Buttons */
289         /* Alternate Editor Buttons */
290         prop_editors_panel_init(type, ab_panedwin_palitem,
291             cgen->attach_button, cgen->conn_button, cgen->helptxt_button);
292  
293         /*
294          * Prop Sheet Settings....
295          */
296
297         /* Name Field */
298         prop_field_init(&(pws->name), cgen->name_field_label,
299                             cgen->name_field, cgen->name_cb);
300
301         /* Initial State */
302         n = 0;
303         item[n] = cgen->init_state_cbox_items.Visible_item;
304         item_val[n] = AB_STATE_VISIBLE; n++;
305         item[n] = cgen->init_state_cbox_items.Active_item;
306         item_val[n] = AB_STATE_ACTIVE; n++;
307         prop_checkbox_init(&(pws->init_state),cgen->init_state_cbox_label,
308                 cgen->init_state_cbox, n, item, item_val,
309                 cgen->init_state_cb);
310
311         /* Pane Minimum/Maximum Setting */
312         prop_geomfield_init(&(pws->min_max_geo), cgen->pane_height_lbl, 
313                 NULL, NULL, NULL, NULL,
314                 cgen->min_height_field_label, cgen->min_height_field,
315                 cgen->max_height_field_label, cgen->max_height_field,
316                 cgen->height_cb); 
317
318         prop_changebars_cleared(pws->prop_sheet);
319
320         return (cgen->dialog_shellform);
321     }
322     else
323         return NULL;
324 }  
325
326 static int
327 panedwin_prop_activate(
328     AB_PROP_TYPE type,
329     BOOL         active
330 )
331 {
332     ui_set_active(prop_pw_settings_rec[type].prop_sheet, active);
333     return OK;
334 }
335
336
337 static int
338 panedwin_prop_clear(
339     AB_PROP_TYPE type
340 )
341 {
342     PropPanedWinSettingsRec   *pws = &(prop_pw_settings_rec[type]);
343
344     /* Clear Name Field */
345     prop_field_set_value(&(pws->name), "", False);
346
347     /* Clear Initial State */
348     prop_checkbox_set_value(&(pws->init_state), AB_STATE_VISIBLE, 
349                                 True, False);
350     prop_checkbox_set_value(&(pws->init_state), AB_STATE_ACTIVE, 
351                                 True, False);
352
353     /* Clear pane information */
354     panedwin_prop_clear_geom(type);
355  
356     pws->current_pw_obj = NULL;
357     pws->current_pane_obj = NULL;
358
359     turnoff_changebars(type);
360
361     return OK;
362 }
363
364 static int
365 panedwin_prop_clear_geom(
366     AB_PROP_TYPE type
367 )
368 {
369     PropPanedWinSettingsRec   *pws = &(prop_pw_settings_rec[type]);
370
371     /* Clear Pane Geometry Setting */
372     XtVaSetValues(pws->width,
373                 XtVaTypedArg, XmNlabelString, XtRString,
374                     "   0", strlen("   0")+1,
375                 NULL);
376     XtVaSetValues(pws->height,
377                 XtVaTypedArg, XmNlabelString, XtRString,
378                     "   0", strlen("   0")+1,
379                 NULL);
380
381     /* Clear Pane Minimum/Maximum Setting */
382     prop_geomfield_clear(&(pws->min_max_geo), GEOM_WIDTH);
383     prop_geomfield_clear(&(pws->min_max_geo), GEOM_HEIGHT);
384
385     return OK;
386 }
387
388 static int
389 panedwin_prop_load(
390     ABObj        obj,
391     AB_PROP_TYPE type,
392     unsigned long loadkey
393 )
394 {
395     PropPanedWinSettingsRec     *pws = &(prop_pw_settings_rec[type]);
396     BOOL                        load_all = (loadkey & LoadAll);
397
398     if (obj == NULL)
399     {
400         if (pws->current_pw_obj != NULL)
401             obj = pws->current_pw_obj;
402         else
403             return ERROR;
404     }
405     else if (!obj_is_paned_win(obj))
406         return ERROR;
407     else
408         pws->current_pw_obj = obj;
409
410
411     /* Load  Name of paned window object */
412     if (load_all || loadkey & LoadName)
413         prop_field_set_value(&(pws->name), obj_get_name(obj), False);
414
415     if (load_all)
416     {
417         /* Load Initial State */
418         prop_checkbox_set_value(&(pws->init_state), AB_STATE_VISIBLE,
419                                 obj_is_initially_visible(obj), False);
420         prop_checkbox_set_value(&(pws->init_state), AB_STATE_ACTIVE,
421                                 obj_is_initially_active(obj), False);
422
423         /* Load children of the paned window */
424         panedwin_load_panes(obj, type);
425
426         turnoff_changebars(type);
427     }
428
429     return OK;
430 }
431
432 static int
433 panedwin_load_panes(
434     ABObj       obj,
435     AB_PROP_TYPE type
436 )
437 {
438     PropPanedWinSettingsRec     *pws = &(prop_pw_settings_rec[type]);
439
440     if (obj == NULL || !obj_is_paned_win(obj))
441         return ERROR;
442
443     /* Clear out the panes list first */
444     XmListDeleteAllItems(pws->panelist);
445          
446     /* Populate the panes list in the prop sheet */
447     abobj_list_update(pws->panelist, obj, pw_child_test_func);      
448
449     return OK;
450 }
451
452 static int
453 panedwin_pane_prop_load(
454     ABObj       obj,
455     AB_PROP_TYPE type
456 )
457 {
458     PropPanedWinSettingsRec     *pws = &(prop_pw_settings_rec[type]);
459     char                        width[MAXPATHLEN], 
460                                 height[MAXPATHLEN];
461     *width = 0;
462     *height = 0;
463
464     if (obj == NULL)
465     {
466         if (pws->current_pane_obj != NULL)
467             obj = pws->current_pane_obj;
468         else
469             return ERROR;
470     }
471     else if (!obj_is_pane(obj) && !obj_is_layers(obj))
472         return ERROR;
473     else
474         pws->current_pane_obj = obj;
475
476     /* Pane Geometry Setting */
477     sprintf(width, "%d", abobj_get_actual_width(obj));
478     sprintf(height,"%d", abobj_get_actual_height(obj));
479     XtVaSetValues(pws->width, 
480                 XtVaTypedArg, XmNlabelString, XtRString,
481                     width, strlen(width)+1,
482                 NULL);
483     XtVaSetValues(pws->height, 
484                 XtVaTypedArg, XmNlabelString, XtRString,
485                     height, strlen(height)+1,
486                 NULL);
487
488     /* Pane Minimum/Maximum Setting */
489     prop_geomfield_set_value(&(pws->min_max_geo), GEOM_WIDTH, 
490                         obj_get_pane_min(obj),False);
491     prop_geomfield_set_value(&(pws->min_max_geo), GEOM_HEIGHT, 
492                         obj_get_pane_max(obj),False);
493
494     turnoff_changebars(type);
495
496     return OK;
497 }
498
499 /* This routine is called when the "Apply" button is
500  * pressed.  It sets all the values of attributes that
501  * have changed to their new values.
502  */
503 int
504 panedwin_prop_apply(
505     AB_PROP_TYPE   type
506 )
507 {
508     PropPanedWinSettingsRec     *pws = &(prop_pw_settings_rec[type]);
509     STRING                      value;
510     int                         geom;
511
512     if (!verify_props(type))
513         return ERROR;
514
515     if (prop_changed(pws->name.changebar))
516     {
517         value = prop_field_get_value(&(pws->name));   
518         abobj_set_name(pws->current_pw_obj, value);
519         util_free(value);
520     }
521     if (prop_changed(pws->init_state.changebar))
522     {
523         abobj_set_visible(pws->current_pw_obj,
524                 prop_checkbox_get_value(&(pws->init_state), AB_STATE_VISIBLE));
525         abobj_set_active(pws->current_pw_obj,
526                 prop_checkbox_get_value(&(pws->init_state), AB_STATE_ACTIVE));
527     }
528     if (prop_changed(pws->min_max_geo.changebar))
529     {
530         geom = prop_geomfield_get_value(&(pws->min_max_geo), GEOM_WIDTH);
531         abobj_set_pane_min(pws->current_pane_obj, geom);
532         geom = prop_geomfield_get_value(&(pws->min_max_geo), GEOM_HEIGHT);
533         abobj_set_pane_max(pws->current_pane_obj, geom);
534     }
535
536     if (pws->current_pw_obj != NULL)
537         abobj_instantiate_changes(pws->current_pw_obj);
538
539     if (pws->current_pane_obj != NULL)
540         abobj_instantiate_changes(pws->current_pane_obj);
541
542     turnoff_changebars(type);
543
544     return OK;
545 }
546
547 static BOOL
548 panedwin_prop_pending(
549     AB_PROP_TYPE type
550 )
551 {
552     return(prop_changebars_pending(prop_pw_settings_rec[type].prop_sheet));
553 }
554
555 static BOOL
556 verify_props(
557     AB_PROP_TYPE type
558 )
559 {
560     PropPanedWinSettingsRec   *pws = &(prop_pw_settings_rec[type]);
561
562     if (prop_changed(pws->name.changebar) && 
563         !prop_name_ok(pws->current_pw_obj, pws->name.field))
564         return False;
565
566     if (prop_changed(pws->min_max_geo.changebar) &&
567         (!prop_number_ok(pws->min_max_geo.w_field, "Pane Height Min Field", 1, SHRT_MAX) ||
568          !prop_number_ok(pws->min_max_geo.h_field, "Pane Height Max Field", 1, SHRT_MAX)))
569         return False; 
570
571     return True;
572 }
573
574 static void
575 turnoff_changebars(
576     AB_PROP_TYPE type
577 )
578 {
579     PropPanedWinSettingsRec   *pws = &(prop_pw_settings_rec[type]);
580
581     prop_set_changebar(pws->name.changebar,             PROP_CB_OFF);
582     prop_set_changebar(pws->init_state.changebar,       PROP_CB_OFF);
583     prop_set_changebar(pws->min_max_geo.changebar,      PROP_CB_OFF);
584
585     prop_changebars_cleared(pws->prop_sheet);
586 }
587
588
589 /* This routine is called when an item in the "Panes" list is
590  * selected.  It takes care of loading in the pane child width/
591  * height and pane min/max values.
592  */
593 static void
594 pw_panelist_selectCB(
595     Widget      widget,
596     XtPointer   client_data,
597     XmListCallbackStruct *listdata
598 )
599 {
600     ABObj               module = NULL;
601     ABObj               selected_obj = NULL;
602     STRING              name = NULL;
603     int                 ret = 0;
604     AB_PROP_TYPE        type;
605     PropPanedWinSettingsRec   *pws;
606
607     type = (AB_PROP_TYPE) client_data;
608     pws = &(prop_pw_settings_rec[type]);
609     name = objxm_xmstr_to_str(listdata->item);
610     if (name)
611     {
612         ret = abobj_moduled_name_extract(name, &module, &selected_obj);
613         pws->current_pane_obj = selected_obj;
614         panedwin_pane_prop_load(selected_obj, type);
615         util_free(name);
616     }
617 }
618
619 /* Test whether the object is a module and if so test
620  * if it is mapped (showing).
621  */
622 static BOOL
623 module_test_func(
624     ABObj test_obj
625 )
626 {
627     if (!obj_is_module(test_obj))
628         return(False);
629
630     if (obj_has_flag(test_obj, MappedFlag))
631     {
632         return(True);
633     }
634     else
635         return(False);
636 }
637
638 /*
639  * Test whether an object should be loaded into the
640  * list of panes in the Paned Window Editor.
641  */
642 static BOOL
643 pw_child_test_func(
644     ABObj test_obj
645 )
646 {
647     ABObj       module = NULL;
648     ABObj       parent = NULL;
649
650     if ((module = obj_get_module(test_obj)) == NULL)
651         return(False);
652
653     parent = obj_get_parent(test_obj);
654     if ( (obj_is_pane(test_obj) || obj_is_layers(test_obj))
655         && obj_is_paned_win(parent) && obj_has_flag(module, MappedFlag))
656     {
657         return(True);
658     }
659     else
660         return(False);
661 }
662
663 /*
664  * obj-callback: object is being destroyed - remove from Paned
665  *               Window Editor object list.
666  */
667 static int
668 pw_obj_destroyedOCB(
669     ObjEvDestroyInfo    info
670 )
671 {
672     ABObj       parent = NULL;
673     int         ret = 0, i;
674     PropPanedWinSettingsRec   *pws;
675                      
676     if ( !obj_is_pane(info->obj) && !obj_is_layers(info->obj) )
677             return 0;
678  
679     parent = obj_get_parent(info->obj);
680     if ( ((parent = obj_get_parent(info->obj)) != NULL) &&
681         obj_is_paned_win(parent))
682     {
683         for (i = 0; i < AB_PROP_TYPE_NUM_VALUES; ++i)
684         {
685             pws = &(prop_pw_settings_rec[i]);
686                 
687             if (pws->current_pane_obj == info->obj)
688             {
689                 panedwin_prop_clear_geom((AB_PROP_TYPE) i);
690                 pws->current_pane_obj = NULL;
691             }
692             ret = abobj_list_obj_destroyed(pws->panelist, info->obj, 
693                         pw_child_test_func);
694         }
695     }
696     return (ret);
697 }
698
699 static int
700 pw_obj_renamedOCB(
701     ObjEvAttChangeInfo    info
702 )
703 {
704     ABObj       parent = NULL;
705     STRING      mod_name = NULL;
706     int         ret = 0, i;
707     PropPanedWinSettingsRec   *pws;
708
709     if (!obj_is_module(info->obj) && !obj_is_pane(info->obj) 
710         && !obj_is_layers(info->obj))
711         return 0;
712
713     if (obj_is_module(info->obj))
714     {
715         mod_name = obj_get_name(info->obj);
716         if (mod_name == NULL)
717             return -1;
718      
719         if (info->old_name != NULL)
720         {
721             /* Change the module prefix in the panes list */
722             for (i = 0; i < AB_PROP_TYPE_NUM_VALUES; ++i)
723             {
724                 pws = &(prop_pw_settings_rec[i]);
725                 abobj_list_obj_renamed(pws->panelist, info->obj, 
726                 istr_string(info->old_name), module_test_func);
727             }
728         }
729     }
730     else        /* obj is a pane OR a layer */
731     {
732         if (info->old_name == NULL)
733         {
734             /* This is a new pane dropped on an existing
735              * paned window object OR this is a new layer
736              * being created.  To make sure, check the 
737              * obj's parent.
738              */  
739             parent = obj_get_parent(info->obj);
740             if ( (parent != NULL) && obj_is_paned_win(parent) )
741             {
742                 for (i = 0; i < AB_PROP_TYPE_NUM_VALUES; ++i)
743                 {
744                     pws = &(prop_pw_settings_rec[i]);
745                     if (parent == pws->current_pw_obj)
746                     {
747                         ret = abobj_list_update(pws->panelist, parent,
748                                 pw_child_test_func);
749                     }
750                 }
751             }
752         }
753         /* The pane's name has changed */
754         else
755             for (i = 0; i < AB_PROP_TYPE_NUM_VALUES; ++i)
756             {
757                 pws = &(prop_pw_settings_rec[i]);
758                 ret = abobj_list_obj_renamed(pws->panelist, info->obj,
759                 istr_string(info->old_name), pw_child_test_func);
760             }
761     }
762     return (ret);
763 }
764
765 /* This callback gets called when a pane child is being
766  * parented to a different object, as when "Unmake Paned
767  * Window" or "Make Paned Window" is chosen from the floating 
768  * menu.
769  */
770 static int
771 pw_obj_reparentedOCB(
772     ObjEvReparentInfo     info
773 )
774 {
775     ABObj       parent = NULL;
776     int         ret = 0, i;
777     PropPanedWinSettingsRec   *pws;
778
779     if (!obj_is_pane(info->obj) && !obj_is_layers(info->obj))
780         return 0;
781
782     /* If the pane name is NULL, then that means it is a 
783      * new pane, one which was dragged from the palette 
784      * onto an existing paned window. In that case, let 
785      * the pw_obj_renamedOCB callback handle it (i.e. add 
786      * it to the pane list).
787      */
788     parent = obj_get_parent(info->obj);
789     if (obj_get_name(info->obj) != NULL)
790     {
791         /* Either a new paned window obj was created (via
792          * the "Make Paned Window" popup menu OR a paned
793          * window obj is being destroyed (via the "Unmake
794          * Paned Window" popup menu) and therefore its
795          * children are being reparented to the paned window's
796          * parent.  If a new paned window was created, we don't
797          * need to update the panes list because that will happen
798          * when the new paned window obj is selected. 
799          */
800         if ((info->old_parent != NULL) && 
801             obj_is_paned_win(info->old_parent))
802         {
803             for (i = 0; i < AB_PROP_TYPE_NUM_VALUES; ++i)
804             {
805                 pws = &(prop_pw_settings_rec[i]);
806                 if (pws->current_pane_obj == info->obj)
807                     panedwin_prop_clear_geom((AB_PROP_TYPE) i);
808                     ret = abobj_list_obj_reparented(pws->panelist, info,
809                                 pw_child_test_func);
810             }
811         }
812     }
813     return (ret);
814 }
815
816 static void
817 panedwinEdP_init()
818 {
819     obj_add_reparent_callback(pw_obj_reparentedOCB, "panedwinEdP_init");
820     obj_add_rename_callback(pw_obj_renamedOCB, "panedwinEdP_init");
821     obj_add_destroy_callback(pw_obj_destroyedOCB, "panedwinEdP_init");
822 }
823
824
825 /*
826  * Create a paned window out of the selected group of objects.
827  */
828 void
829 abobj_make_panedwin(
830 )
831 {
832     ABObj               project = proj_get_project();
833     ABObj               obj = (ABObj) NULL;
834     ABObj               pw_obj = (ABObj) NULL;
835     ABObj               obj_parent = (ABObj) NULL;
836     ABSelectedRec       sel;
837     int                 i, xpos = 0, ypos = 0;
838     AB_ATTACH_TYPE      attach_type = AB_ATTACH_UNDEF,
839                         next_attach_type = AB_ATTACH_UNDEF;
840     void                *attach_val = NULL,
841                         *next_attach_val = NULL;
842     int                 attach_offset = 0;
843     BOOL                AttachTypesEqual;
844
845     /* Creation may take awhile, so set busy cursor */
846     ab_set_busy_cursor(True);
847
848     /* Get handle to the selected objects */
849     abobj_get_selected(project, False, False, &sel);
850
851     /* Get the parent for all the selected objects */
852     obj_parent = obj_get_parent(sel.list[0]);
853
854     /* Set the SaveNeeded flag on the module */
855     abobj_set_save_needed(obj_get_module(obj_parent), TRUE);
856
857     /* Deselect any objects that happen to be selected */
858     abobj_deselect_all(project);
859     aob_deselect_all_objects(project);
860
861     /* Create a new panedWindow obj as a child of the
862      * parent of the selected objects.
863      */
864     pw_obj = obj_create(AB_TYPE_CONTAINER, obj_parent);
865     obj_set_subtype(pw_obj, AB_CONT_PANED);
866
867     pal_initialize_obj(pw_obj);
868
869     /* Sort the selected object list in the order in
870      * which the panes will be placed once they are part
871      * of a panedWindow (order is based on y coordinate).
872      */
873     qsort(sel.list, sel.count, sizeof(ABObj *), position_compare);
874
875     /* Set the paned window object's NORTH and SOUTH attachments */
876     attach_type = obj_get_attach_type(sel.list[0], AB_CP_NORTH);
877     attach_val = obj_get_attach_value(sel.list[0], AB_CP_NORTH);
878     attach_offset = obj_get_attach_offset(sel.list[0], AB_CP_NORTH);
879     obj_set_attachment(pw_obj,
880                         AB_CP_NORTH,
881                         attach_type,
882                         attach_val,
883                         attach_offset);
884  
885     attach_type = obj_get_attach_type(sel.list[sel.count-1], AB_CP_SOUTH);
886     attach_val = obj_get_attach_value(sel.list[sel.count-1], AB_CP_SOUTH);
887     attach_offset = obj_get_attach_offset(sel.list[sel.count-1], AB_CP_SOUTH);
888     obj_set_attachment(pw_obj,
889                         AB_CP_SOUTH,
890                         attach_type,
891                         attach_val,
892                         attach_offset);
893
894     /* Reparent the selected objects to be children of the
895      * new panedWindow obj, in the *correct* order.
896      */
897     for (i = 0; i < sel.count; i++)
898     {
899         obj = sel.list[i];
900         obj_reparent(obj, pw_obj);
901     }
902
903     /* Sort the selected object list from rightmost object
904      * to leftmost object.
905      */
906     qsort(sel.list, sel.count, sizeof(ABObj *), east_compare);
907
908     /* Set the paned window object's EAST attachments */
909     attach_type = obj_get_attach_type(sel.list[sel.count-1], AB_CP_EAST);
910     attach_val = obj_get_attach_value(sel.list[sel.count-1], AB_CP_EAST);
911     attach_offset = obj_get_attach_offset(sel.list[sel.count-1], AB_CP_EAST);
912     obj_set_attachment(pw_obj,
913                         AB_CP_EAST,
914                         attach_type,
915                         attach_val,
916                         attach_offset);
917
918     /* Sort the selected object list from leftmost object
919      * to rightmost object. Have to do this because it is
920      * possible that the leftmost and rightmost objects are
921      * in fact one and the same (if it spans the entire window,
922      * for example and the other pane does not).
923      */
924     qsort(sel.list, sel.count, sizeof(ABObj *), west_compare);
925
926     /* Set the paned window object's WEST attachment */
927     attach_type = obj_get_attach_type(sel.list[0],AB_CP_WEST);
928     attach_val = obj_get_attach_value(sel.list[0],AB_CP_WEST);
929     attach_offset = obj_get_attach_offset(sel.list[0],AB_CP_WEST);
930     obj_set_attachment(pw_obj,
931                         AB_CP_WEST,
932                         attach_type,
933                         attach_val,
934                         attach_offset);
935
936     /* Check whether or not the paned window's children's
937      * EAST/WEST attachment types are equal.  If not, then post
938      * a message saying that the attachments may not be correct
939      * and that the user should use the Attachments Editor
940      * to correct them. 
941      */
942     AttachTypesEqual = TRUE;
943     attach_type = obj_get_attach_type(sel.list[0], AB_CP_EAST);
944     for (i = 1; ((i < sel.count) && AttachTypesEqual); i++)
945     {
946         next_attach_type = obj_get_attach_type(sel.list[i], AB_CP_EAST);
947         if (attach_type != next_attach_type)
948         {
949             AttachTypesEqual = FALSE;
950             /* Post Message */
951             dtb_panedwin_ed_pw_east_attach_msg_initialize(
952                         &dtb_panedwin_ed_pw_east_attach_msg);
953             dtb_show_message((Widget)obj_parent->ui_handle,
954                         &dtb_panedwin_ed_pw_east_attach_msg, NULL,NULL);
955         }
956     }
957     /* If all of the paned window's children EAST attachment
958      * types are equal, then check the EAST attachment values.
959      */
960     if (AttachTypesEqual)
961     {
962         attach_val = obj_get_attach_value(sel.list[0], AB_CP_EAST);
963         for (i = 1; i < sel.count; i++)
964         {
965             next_attach_val = obj_get_attach_value(sel.list[i], AB_CP_EAST);
966             if (attach_val != next_attach_val)
967             {
968                 /* Post Message */
969                 dtb_panedwin_ed_pw_east_attach_msg_initialize(
970                         &dtb_panedwin_ed_pw_east_attach_msg);
971                 dtb_show_message((Widget)obj_parent->ui_handle,
972                         &dtb_panedwin_ed_pw_east_attach_msg, NULL,NULL);
973                 break;
974             }
975         }
976     }
977
978     AttachTypesEqual = TRUE;
979     attach_type = obj_get_attach_type(sel.list[0], AB_CP_WEST);
980     for (i = 1; ((i < sel.count) && AttachTypesEqual); i++)
981     {
982         next_attach_type = obj_get_attach_type(sel.list[i], AB_CP_WEST);
983         if (attach_type != next_attach_type)
984         {
985             AttachTypesEqual = FALSE;
986             /* Post Message */
987             dtb_panedwin_ed_pw_west_attach_msg_initialize(
988                         &dtb_panedwin_ed_pw_west_attach_msg);
989             dtb_show_message((Widget)obj_parent->ui_handle,
990                         &dtb_panedwin_ed_pw_west_attach_msg, NULL,NULL); 
991         }
992     }  
993     /* If all of the paned window's children WEST attachment
994      * types are equal, then check the WEST attachment values.
995      */
996     if (AttachTypesEqual)
997     {  
998         attach_val = obj_get_attach_value(sel.list[0], AB_CP_WEST);
999         for (i = 1; i < sel.count; i++) 
1000         {
1001             next_attach_val = obj_get_attach_value(sel.list[i], AB_CP_WEST);
1002             if (attach_val != next_attach_val)
1003             {
1004                 /* Post Message */ 
1005                 dtb_panedwin_ed_pw_west_attach_msg_initialize(
1006                         &dtb_panedwin_ed_pw_west_attach_msg);
1007                 dtb_show_message((Widget)obj_parent->ui_handle,
1008                         &dtb_panedwin_ed_pw_west_attach_msg, NULL,NULL); 
1009                 break;
1010             } 
1011         }
1012     }
1013
1014     obj_tree_clear_flag(pw_obj, InstantiatedFlag);
1015     abobj_show_tree(pw_obj, True);
1016  
1017     /* Make the new obj selected */
1018     abobj_select(pw_obj);
1019
1020     ab_set_busy_cursor(False);
1021 }
1022
1023 static int
1024 position_compare(
1025     const void *leftEntry,
1026     const void *rightEntry
1027 )
1028 {
1029     ABObj *left_obj = (ABObj *)leftEntry;
1030     ABObj *right_obj = (ABObj *)rightEntry;
1031
1032     int   left_xpos = obj_get_x(*left_obj);
1033     int   left_ypos = obj_get_y(*left_obj);
1034     int   right_xpos = obj_get_x(*right_obj);
1035     int   right_ypos = obj_get_y(*right_obj);
1036
1037     if (left_ypos - right_ypos != 0)
1038         return (left_ypos - right_ypos);
1039     else
1040         return (left_xpos - right_xpos);
1041 }
1042
1043 static int
1044 east_compare(
1045     const void *leftEntry,
1046     const void *rightEntry
1047 )
1048 {
1049     ABObj *left_obj = (ABObj *)leftEntry;
1050     ABObj *right_obj = (ABObj *)rightEntry;
1051  
1052     int   left_xpos = obj_get_x(*left_obj) + 
1053                         abobj_get_actual_width(*left_obj);
1054     int   right_xpos = obj_get_x(*right_obj) +
1055                         abobj_get_actual_width(*right_obj);
1056     return (left_xpos - right_xpos);
1057 }
1058
1059 static int
1060 west_compare(
1061     const void *leftEntry,
1062     const void *rightEntry
1063 )
1064 {
1065     ABObj *left_obj = (ABObj *)leftEntry;
1066     ABObj *right_obj = (ABObj *)rightEntry;
1067
1068     int   left_xpos = obj_get_x(*left_obj);
1069     int   right_xpos = obj_get_x(*right_obj);
1070
1071     return (left_xpos - right_xpos);
1072 }
1073
1074 /*
1075  * Take the selected group of objects out of the
1076  * paned window and delete the paned window object.
1077  */
1078 void
1079 abobj_unmake_panedwin(
1080 )
1081 {
1082     ABObj               project = proj_get_project();
1083     ABObj               pw_obj = NULL;
1084     ABObj               obj_parent = NULL;
1085     ABObj               obj = NULL;
1086     ABObj               *list = NULL;
1087     ABSelectedRec       sel;
1088     int                 i, x_orig = 0, y_orig = 0, ypos = 0;
1089     int                 j, numChildren = 0, tree_pos = 0;
1090     int                 list_items = 0; 
1091     Boolean             parent_exists = True;
1092  
1093     /* Undo may take awhile, so set busy cursor */
1094     ab_set_busy_cursor(True);
1095
1096     /* Set the SaveNeeded flag */
1097     abobj_set_save_needed(project, TRUE);
1098
1099     /* Get handle to the paned window objects */
1100     abobj_get_selected(project, False, False, &sel);
1101
1102     /* Go through each paned window object and move
1103      * its children to the paned window's parent.
1104      */
1105     for (i = 0; i < sel.count; i++)
1106     {
1107         pw_obj = sel.list[i];
1108
1109         /* Deselect the paned window */
1110         abobj_deselect(pw_obj);
1111
1112         /* Get the parent for all the selected objects */
1113         obj_parent = obj_get_parent(pw_obj);
1114
1115         /* Set the SaveNeeded flag on the module */
1116         abobj_set_save_needed(obj_get_module(pw_obj), TRUE);
1117
1118         /* Get the child position of the paned window
1119          * object in its parent hierarchy.
1120          */ 
1121         tree_pos = obj_get_child_num(pw_obj);
1122
1123         /* Get the x,y position of the paned window */
1124         x_orig = obj_get_x(pw_obj);
1125         y_orig = obj_get_y(pw_obj);
1126         ypos = y_orig;
1127
1128         numChildren = obj_get_num_salient_children(pw_obj);
1129         for (j = 0; j < numChildren; j++, tree_pos++)
1130         {
1131             /* The first child really is the next
1132              * child because the previous child has
1133              * been reparented to the paned window's
1134              * parent.
1135              */
1136             obj = obj_get_salient_child(pw_obj, 0);
1137             obj_unparent(obj);
1138             obj_insert_child(obj_parent, obj, tree_pos);
1139
1140             abobj_set_xy(obj, x_orig, ypos);
1141             ypos = ypos + abobj_get_actual_height(obj);
1142
1143             objxm_tree_uninstantiate(obj, True);
1144             abobj_instantiate_changes(obj);
1145         }
1146         
1147         /* Destroy the paned window object */
1148         obj_destroy(pw_obj);
1149
1150         /* REMIND: Not sure if we need this code.
1151          *      Paned windows should all have the
1152          *      same parent, given the constraint
1153          *      that multiple paned windows cannot
1154          *      be selected across different modules.
1155          */
1156         /*                   
1157          * Keep a list of parents that need to be 
1158          * updated after all paned windows are unpaned.
1159          */
1160         if (list == NULL)
1161         { 
1162             list = (ABObj*)XtMalloc(sizeof(ABObj));
1163             list[0] = obj_parent;
1164             list_items = 1;
1165         }
1166         else
1167         for (j = 0; j < list_items; j++)
1168         {
1169             if (list[j] == obj_parent)
1170             {
1171                 parent_exists = True;
1172                 break;
1173             }
1174         }
1175         if (parent_exists == False)
1176         {
1177             XtRealloc((char*)list, sizeof(ABObj));
1178             list[list_items++] = obj_parent;
1179         }
1180         parent_exists = False;
1181     }
1182
1183     ab_set_busy_cursor(False);
1184