a1630caad103cf589d2c9109aa8c0a0c2541c994
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / Agents / MapAgentMotif.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 libraries 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 /*      Copyright (c) 1994,1995,1996 FUJITSU LIMITED    */
24 /*      All Rights Reserved                             */
25
26 /*
27  * $TOG: MapAgentMotif.C /main/16 1998/04/17 11:33:40 mgreess $
28  *
29  * Copyright (c) 1992 HaL Computer Systems, Inc.  All rights reserved.
30  * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
31  * States.  Use of a copyright notice is precautionary only and does not
32  * imply publication or disclosure.
33  * 
34  * This software contains confidential information and trade secrets of HaL
35  * Computer Systems, Inc.  Use, disclosure, or reproduction is prohibited
36  * without the prior express written permission of HaL Computer Systems, Inc.
37  * 
38  *                         RESTRICTED RIGHTS LEGEND
39  * Use, duplication, or disclosure by the Government is subject to
40  * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
41  * Technical Data and Computer Software clause at DFARS 252.227-7013.
42  *                        HaL Computer Systems, Inc.
43  *                  1315 Dell Avenue, Campbell, CA  95008
44  * 
45  */
46
47 #include "UAS.hh"
48
49 #define C_TOC_Element
50 #define L_Basic
51
52 #define C_WindowSystem
53 #define L_Other
54
55 #define C_HelpAgent
56 #define C_Agent
57 #define C_MapAgent
58 #define L_Agents
59
60 #define C_WindowGeometryPref
61 #define L_Preferences
62
63 #define C_PrefMgr
64 #define C_MessageMgr
65 #define L_Managers
66
67 #include "Prelude.h"
68
69 #include "Other/XmStringLocalized.hh"
70 #include "Managers/CatMgr.hh"
71
72 #include "Registration.hh"
73
74 #include <WWL/WTopLevelShell.h>
75 #include <WWL/WXmForm.h>
76 #include <WWL/WXmPushButton.h>
77 #include <WWL/WXmPanedWindow.h>
78 #include <WWL/WXmFrame.h>
79 #include <WWL/WXmPushButton.h>
80 #include <WWL/WXmToggleButton.h>
81 #include <WWL/WXmArrowButton.h>
82
83 #include "Widgets/WXawPorthole.h"
84 #include "Widgets/WXawPanner.h"
85 #include "Widgets/WXawTree.h"
86
87 #define CLASS MapButton
88 #include "create_macros.hh"
89
90 class MapButton : public WWL
91 {
92 public:
93   MapButton (WComposite &parent, const UAS_Pointer<UAS_Common> &doc_ptr,
94              MapButton *ancestor);
95   virtual ~MapButton() {}
96
97   void activate();
98   void expand();
99   void destroy();
100
101   WXmForm        f_form;
102   WXmPushButton  f_button;
103   WXmArrowButton f_arrow;
104   UAS_Pointer<UAS_Common> f_doc_ptr;
105   bool           f_expanded;
106
107   static void ManageKids();
108   static Widget *f_kids;
109   static int     f_num_kids;
110   static int     f_kids_size;
111 };
112
113 Widget *MapButton::f_kids;
114 int MapButton::f_num_kids;
115 int MapButton::f_kids_size;
116
117 MapButton::MapButton (WComposite &parent,
118                       const UAS_Pointer<UAS_Common> &doc_ptr,
119                       MapButton *ancestor)
120 : f_form (parent, "form"),
121   f_doc_ptr (doc_ptr),
122   f_expanded (FALSE)
123 {
124   ON_DEBUG (printf ("MapButton::MapButton (%s)\n", (char*)f_doc_ptr->title()));
125   static bool expandable_tree =
126     window_system().get_boolean_default ("ExpandableMap");
127   UAS_List<UAS_Common> kids (f_doc_ptr->children());
128   UAS_String t = f_doc_ptr->title();
129   if (kids.length() > 0 && expandable_tree)
130     {
131       f_arrow = WXmArrowButton (f_form, "expand", WAutoManage);
132       ON_ACTIVATE (f_arrow,expand);
133       f_button =
134         WXmPushButton (f_form, t, WAutoManage,
135                        WArgList (XmNrightWidget, (XtArgVal) ((Widget) f_arrow),
136                                  XmNrightAttachment, XmATTACH_WIDGET,
137                                  NULL));
138     }
139   else
140     {
141       f_button = WXmPushButton (f_form, t, WAutoManage);
142     }
143
144   ON_ACTIVATE (f_button,activate);
145   SET_CALLBACK (f_form,Destroy,destroy);
146
147   f_form.ShadowThickness (0);
148   // f_form.Realize();
149
150   // Add to the list so that we can manage 'em all at once. 
151   if (f_num_kids + 1 > f_kids_size)
152     {
153       f_kids_size *= 2;
154       f_kids = (Widget *) realloc (f_kids, sizeof (Widget) * f_kids_size);
155     }
156   f_kids[f_num_kids++] = (Widget) f_form;
157   ON_DEBUG (printf ("Form managed = %d\n", XtIsManaged (f_form)));
158     
159   if (ancestor != NULL)
160     {
161       CXawTree form (f_form);
162       WArgList args;
163
164       form.TreeParent (ancestor->f_form, args);
165       form.Set (args.Args(), args.NumArgs());
166     }
167 }
168
169 void
170 MapButton::ManageKids()
171 {
172   XtManageChildren (f_kids, f_num_kids);
173   f_num_kids = 0;
174 }
175
176 void
177 MapButton::activate()
178 {
179   f_doc_ptr->retrieve();
180 }
181
182 void
183 MapButton::expand()
184 {
185   if (f_expanded)
186     {
187       f_arrow.ArrowDirection (XmARROW_RIGHT);
188       f_expanded = FALSE;
189     }
190   else
191     {
192       f_arrow.ArrowDirection (XmARROW_DOWN);
193       f_expanded = TRUE;
194       // Create a button for each child.
195       UAS_List<UAS_Common> kids (f_doc_ptr->children());
196       WXawTree tree (XtParent (f_form));
197       for (unsigned int i = 0; i < kids.length(); i++)
198         new MapButton (tree, kids[i], this);
199       ON_DEBUG (puts ("managing kids"));
200       MapButton::ManageKids();
201       ON_DEBUG (puts ("calling force layout"));
202       tree.ForceLayout();
203       ON_DEBUG (puts ("called force layout"));
204     }
205 }
206
207
208 void
209 MapButton::destroy()
210 {
211   // Free object memory when the widget is destroyed.
212   // Assumes heap allocation of MapButton objects. 
213   delete this;
214 }
215
216
217 // /////////////////////////////////////////////////////////////////
218 // class constructor
219 // /////////////////////////////////////////////////////////////////
220
221 MapAgent::MapAgent()
222 : f_shell (NULL),
223   f_onscreen (FALSE),
224   f_locked(FALSE),
225   f_map_mode(LOCAL_MODE),
226   f_porthole(NULL),
227   f_panner(NULL),
228   f_tree(NULL),
229   f_wm_delete_callback(NULL),
230   f_lock(NULL),
231   f_min_tree_width(0),
232   f_min_tree_height(0)
233 {
234 }
235
236
237 // /////////////////////////////////////////////////////////////////
238 // mode - return the current map mode
239 // /////////////////////////////////////////////////////////////////
240
241 MapAgent::map_mode_t
242 MapAgent::mode() const
243 {
244   return (f_map_mode);
245 }
246
247
248 // /////////////////////////////////////////////////////////////////
249 // set_mode - set the map mode
250 // /////////////////////////////////////////////////////////////////
251
252 void
253 MapAgent::set_mode (const map_mode_t mode)
254 {
255   Xassert (mode == LOCAL_MODE || mode == GLOBAL_MODE);
256
257   f_map_mode = mode;
258 }
259
260
261 // /////////////////////////////////////////////////////////////////
262 // can_display - return true if this agent is willing to display
263 // /////////////////////////////////////////////////////////////////
264
265 bool
266 MapAgent::can_display (UAS_Pointer<UAS_Common> &) const
267 {
268   return (TRUE);
269 }
270
271
272 // /////////////////////////////////////////////////////////////////
273 // display - dislay a map localized around the specified document
274 // /////////////////////////////////////////////////////////////////
275
276 void
277 MapAgent::display (UAS_Pointer<UAS_Common> &doc_ptr, bool popup)
278 {
279   static bool first_time = True;
280   u_int i, num_children;
281   MapButton *parent_button, *child_button, *this_button = NULL;
282
283   if (f_shell == NULL)
284     create_ui();
285
286   // Just pop up the window if the map has already been created
287   // for the specified document.
288   if (doc_ptr == f_doc_ptr)
289     {
290       if (popup) {
291         f_shell->Popup();
292         XMapRaised(XtDisplay(*f_shell), XtWindow(*f_shell));
293       }
294       f_onscreen = TRUE;
295       return;
296     }
297
298   // Must have to create a new tree, so start by wiping out the old one. 
299   if (f_tree != NULL)
300     {
301       f_tree->Destroy();
302       delete f_tree;
303     }
304   f_tree = new WXawTree (*f_porthole, "tree");
305   //  f_tree->Realize();
306
307   // Tree gravity should be a preference that is retrieved right here.
308   // (Or better yet stored in the class record.) 
309
310   /* -------- Start the local map at this node's parent. -------- */
311
312   UAS_Pointer<UAS_Common> toc_this = doc_ptr;
313   UAS_Pointer<UAS_Common> toc_parent =
314       (doc_ptr != (UAS_Pointer<UAS_Common>)0)
315           ? doc_ptr->parent() : (UAS_Pointer<UAS_Common>)0;
316
317   // If the entry has a parent, create a button for it and each of
318   // the entry's siblings. 
319   if (toc_parent != (UAS_Pointer<UAS_Common>)NULL)
320     {
321       parent_button = new MapButton (*f_tree, toc_parent, NULL);
322       //  parent_button->expand();
323
324       /* -------- Create a button for each sibling. -------- */
325
326       UAS_List<UAS_Common> kids = toc_parent->children();
327       num_children = kids.length();
328       UAS_Pointer<UAS_Common> toc_kid;
329       for (i = 0; i < num_children; i++)
330         {
331           toc_kid = kids[i];
332           child_button = new MapButton (*f_tree, toc_kid, parent_button);
333           if (toc_kid == doc_ptr)
334             {
335               f_doc_ptr = doc_ptr;
336               this_button = child_button;
337             }
338         }
339     }
340   else // No TOC parent -- SWM: Also may be no TOC!!!
341     {
342       f_doc_ptr = doc_ptr;
343       this_button = new MapButton (*f_tree, toc_this, NULL);
344     }
345
346   if (this_button == NULL)
347     {
348       message_mgr().
349         error_dialog (CATGETS(Set_Messages, 7, "File a Bug"));
350       return;
351     }
352   else
353     {
354       static bool first_time = TRUE;
355       static Pixel highlight_bg, highlight_fg;
356       if (first_time)
357         {
358           const char *s;
359           unsigned long status;
360           s = window_system().get_string_default ("MapHighlightBackground");
361           if (s == NULL || *s == '\0')
362             {
363               highlight_bg = this_button->f_button.Foreground();
364             }
365           else
366             {
367               status = window_system().get_color (s, highlight_bg);
368               // On failure to allocate, just invert. 
369               if (status == 0)
370                 {
371                   highlight_bg = this_button->f_button.Foreground();
372                   highlight_fg = this_button->f_button.Background();
373                 }
374               // Got bg, so now try for fg. 
375               else
376                 {
377                   s = window_system().
378                         get_string_default ("MapHighlightForeground");
379                   if (s == NULL || *s == '\0')
380                     {
381                       highlight_fg =this_button->f_button.Background();
382                     }
383                   else
384                     {
385                       status = window_system().get_color (s, highlight_fg);
386                       // If we cant get both colors, just invert the button. 
387                       if (status == 0)
388                         {
389                           Display *dpy = window_system().display();
390                           XFreeColors (dpy,
391                                        DefaultColormap(dpy,DefaultScreen(dpy)),
392                                        &highlight_bg, 1, 0);
393                           highlight_bg = this_button->f_button.Foreground();
394                           highlight_fg = this_button->f_button.Background();
395                         }
396                     }
397                 }
398             }
399           if (highlight_fg == this_button->f_button.Foreground() ||
400               highlight_bg == this_button->f_button.Background() ||
401               highlight_fg == highlight_bg)
402             {
403               highlight_bg = this_button->f_button.Foreground();
404               highlight_fg = this_button->f_button.Background();
405             }
406           first_time = FALSE;
407         }
408       this_button->f_button.Background (highlight_bg);
409       this_button->f_button.Foreground (highlight_fg);
410       //  this_button->expand();
411     }
412
413   /* -------- Create a button for each child. -------- */
414
415   if (toc_this != (UAS_Pointer<UAS_Common>)NULL)
416     {
417       UAS_List<UAS_Common> myKids = toc_this->children();
418       num_children = myKids.length();
419       for (i = 0; i < num_children; i++)
420         child_button =
421           new MapButton (*f_tree, myKids[i], this_button);
422
423 #if 0
424   if (!XtIsRealized(*f_shell))
425     {
426       f_tree->Manage();
427       f_shell->Realize();
428     }
429 #endif
430
431     }
432   // Manage all the children.
433   MapButton::ManageKids();
434
435   UAS_String buffer = CATGETS(Set_MapAgent, 2, "Dtinfo: ");
436   buffer = buffer + doc_ptr->title();
437   f_shell->Title ((char*)buffer);
438
439   if (!XtIsRealized (*f_shell))
440     f_shell->Realize();
441
442   f_tree->Realize();
443   f_tree->ForceLayout();
444
445   f_min_tree_width = f_tree->Width();
446   f_min_tree_height = f_tree->Height();
447   ON_DEBUG (printf ("+++++ Tree min dims: %d x %d\n",
448                     f_min_tree_width, f_min_tree_height));
449
450   center_on (this_button);
451   f_tree->Manage();
452
453   if (popup)
454     {
455       if (first_time)
456         {
457           WXmForm form (XtParent (XtParent (*f_panner)));
458           form.Height (50);
459           first_time = False;
460         }
461       f_shell->Popup();
462       XMapRaised(XtDisplay(*f_shell), XtWindow(*f_shell));
463     }
464
465   f_onscreen = TRUE;
466 }
467
468
469 // /////////////////////////////////////////////////////////////////
470 // create_ui - create the map user interface
471 // /////////////////////////////////////////////////////////////////
472
473 void
474 MapAgent::create_ui()
475 {
476   MapButton::f_kids_size = 8;
477   MapButton::f_kids = (Widget *)
478                       malloc (sizeof (Widget) * MapButton::f_kids_size);
479   
480   f_shell = new WTopLevelShell (toplevel(), WPopup, "map");
481   window_system().register_shell (f_shell);
482
483   XtVaSetValues(*f_shell, XmNtitle,
484                 CATGETS(Set_MapAgent, 1, "Dtinfo: Local Map"), NULL);
485   WindowGeometry wg = pref_mgr().get_geometry (PrefMgr::MapGeometry);
486   f_shell->Set(WArgList(XmNwidth, wg.width,
487                         XmNheight, wg.height,
488                         NULL));
489
490   // rtp - added new code 8/27/92
491   WXmForm rootform (*f_shell, "rootform");
492
493   WXmForm bottomform (rootform, "bottomform");
494   WXmPushButton close (bottomform, "close", WAutoManage);
495   WXmPushButton help (bottomform, "help", WAutoManage);
496   help_agent().add_activate_help (help, (char*)"map_help");
497
498   XtVaSetValues(close, XmNlabelString,
499         (XmString)XmStringLocalized(CATGETS(Set_AgentLabel, 12, "Close")), NULL);
500   XtVaSetValues(help, XmNlabelString,
501         (XmString)XmStringLocalized(CATGETS(Set_AgentLabel, 48, "Help")), NULL);
502
503   WXmPanedWindow pane (rootform, "pane");
504   WXmForm topform (pane, "topform");
505   XtVaSetValues(topform, XmNheight, 75, NULL);
506   XtVaSetValues(pane, XmNpaneMinimum, 75, XmNpositionIndex, 1, NULL);
507
508   WXmFrame panner_frame (topform, "pframe", WAutoManage);
509   f_panner = new WXawPanner (panner_frame, "panner", WAutoManage);
510   WXmFrame tree_frame (pane, "tframe", WAutoManage);
511   f_porthole = new WXawPorthole (tree_frame, "porthole");
512
513   f_lock = new WXmToggleButton (topform, "lock", WAutoManage);
514   XtVaSetValues(*f_lock, XmNlabelString,
515      (XmString)XmStringLocalized(CATGETS(Set_AgentLabel, 196, "Auto Update")),
516                          XmNindicatorSize, 15, NULL);
517   bool lock_status = pref_mgr().get_boolean (PrefMgr::MapAutoUpdate);
518   f_lock->Set(lock_status);
519   f_locked = lock_status ;
520   // NOTE: Should have a way to remove displayer so that receive function
521   // isn't called every time a node is displayed.  14:08 12-Oct-93 DJB 
522   UAS_Common::request ((UAS_Receiver<UAS_DocumentRetrievedMsg> *) this);
523
524   f_lock->SetValueChangedCallback(this, (WWL_FUN) &MapAgent::lock_toggle);
525   f_porthole->SetReportCallback (this, (WWL_FUN) &MapAgent::porthole_resize);
526   f_panner->SetReportCallback (this, (WWL_FUN) &MapAgent::panner_movement);
527
528   bottomform.Manage();
529   
530   Dimension height;
531   f_lock->Get (WArgList (XmNheight, (XtArgVal)&height, NULL));
532   topform.Set(WArgList(XmNpaneMinimum, height, NULL));
533
534   topform.Manage();
535   f_porthole->Manage();
536   pane.Manage();
537
538   /* -------- Callbacks -------- */
539   f_wm_delete_callback =
540     new WCallback (*f_shell, window_system().WM_DELETE_WINDOW(),
541                    this, (WWL_FUN) &MapAgent::close_window);
542   close.SetActivateCallback (this, (WWL_FUN) &MapAgent::close_window);
543
544   rootform.Manage();
545
546   //  f_shell->Realize();
547
548   f_tree = NULL;
549 }
550
551
552 // /////////////////////////////////////////////////////////////////
553 // porthole_resize
554 // /////////////////////////////////////////////////////////////////
555
556 void
557 MapAgent::porthole_resize (WCallback *wcb)
558 {
559   WArgList args;
560   XawPannerReport *rep = (XawPannerReport *) wcb->CallData();
561
562   ON_DEBUG (printf (">>> Porthole resize, mtw = %d x %d\n",
563                     f_min_tree_width, f_min_tree_height));
564
565   // Don't let the tree widget get bigger that the space needed
566   // to hold the tree when it can't fit in the porthole.  If we
567   // allow this, the user could grow the tree to a large size
568   // by enlarging the map window, then shrink the map window and
569   // keep the tree at the large size and pan to empty space. 
570   if (rep->changed & ~(XawPRSliderX | XawPRSliderY))
571     {
572       Dimension twidth, theight;
573
574       twidth = f_tree->Width();
575       theight = f_tree->Height();
576       ON_DEBUG (printf ("Tree attempts width = %d, height = %d\n",
577                         twidth, theight));
578       if ((twidth > f_min_tree_width && twidth > f_porthole->Width()) ||
579           (theight > f_min_tree_height && theight > f_porthole->Height()))
580         {
581           f_tree->Width(f_min_tree_width, args);
582           f_tree->Height(f_min_tree_height, args);
583           ON_DEBUG (puts ("Adjusting tree"));
584           f_tree->Set (args);
585           ON_DEBUG (puts ("... Done adjusting tree"));
586           return;
587         }
588     }
589      
590   ON_DEBUG (printf (">>> Porthole resize (%d, %d, %d, %d, %d, %d)\n",
591                     rep->slider_x, rep->slider_y,
592                     rep->slider_width, rep->slider_height,
593                     rep->canvas_width, rep->canvas_height));
594   f_panner->SliderX (rep->slider_x, args);
595   f_panner->SliderY (rep->slider_y, args);
596   if (rep->changed & ~(XawPRSliderX | XawPRSliderY))
597     {
598       ON_DEBUG (printf (".....width & height change\n"));
599       f_panner->SliderWidth (rep->slider_width, args);
600       f_panner->SliderHeight (rep->slider_height, args);
601       f_panner->CanvasWidth (rep->canvas_width, args);
602       f_panner->CanvasHeight (rep->canvas_height, args);
603     }
604   f_panner->Set (args);
605 }
606
607
608 // /////////////////////////////////////////////////////////////////
609 // panner_movement
610 // /////////////////////////////////////////////////////////////////
611
612 void
613 MapAgent::panner_movement (WCallback *wcb)
614 {
615   WArgList args;
616   XawPannerReport *rep = (XawPannerReport *) wcb->CallData();
617
618   f_tree->X (-rep->slider_x, args);
619   f_tree->Y (-rep->slider_y, args);
620   f_tree->Set (args);
621 }
622
623
624 // /////////////////////////////////////////////////////////////////
625 // close_window
626 // /////////////////////////////////////////////////////////////////
627
628 void
629 MapAgent::close_window (WCallback *)
630 {
631   f_shell->Popdown();
632   f_onscreen = FALSE;
633 }
634
635 // /////////////////////////////////////////////////////////////////
636 // lock_toggle - callback for lock button
637 // /////////////////////////////////////////////////////////////////
638
639 void 
640 MapAgent::lock_toggle (WCallback *wcb)
641 {
642   ON_DEBUG(cerr << "lock toggle callback" << endl);
643
644   XmToggleButtonCallbackStruct &cbs =
645     *(XmToggleButtonCallbackStruct*) wcb->CallData();
646
647   f_locked = cbs.set;
648 }
649
650 // /////////////////////////////////////////////////////////////////
651 // can_update - return true if this agent is willing to update
652 // /////////////////////////////////////////////////////////////////
653
654 bool
655 MapAgent::can_update()
656 {
657   return (f_onscreen);
658 }
659
660 // /////////////////////////////////////////////////////////////////////////
661 // lock - set the lock
662 // /////////////////////////////////////////////////////////////////////////
663
664 void
665 MapAgent::lock()
666 {
667   f_locked = TRUE;
668   f_lock->Set(TRUE);
669 }
670
671 // /////////////////////////////////////////////////////////////////////////
672 // unlock - unset the lock
673 // /////////////////////////////////////////////////////////////////////////
674 void
675 MapAgent::unlock()
676 {
677   f_locked = FALSE ;
678   f_lock->Set(False);
679 }
680
681 // /////////////////////////////////////////////////////////////////
682 // center_on - center current node in tree view
683 // /////////////////////////////////////////////////////////////////
684
685 void
686 MapAgent::center_on (MapButton *map_button)
687 {
688   // WXmPushButton button = map_button->f_button;
689   WXmForm &button = map_button->f_form;
690   WArgList args;
691   Position bcenter_x, bcenter_y;
692   Position pcenter_x, pcenter_y;
693   Dimension pwidth, pheight;
694   Dimension twidth, theight;
695   Position off_x = 0, off_y = 0;
696
697   bcenter_x = button.X() + button.Width() / 2;
698   bcenter_y = button.Y() + button.Height() / 2;
699   ON_DEBUG (printf ("Form widget id = %p\n", (Widget) button));
700   ON_DEBUG (printf ("Button realized = %d\n", XtIsRealized (button)));
701   ON_DEBUG (printf ("Button coords = (%d,%d)\n", button.X(), button.Y()));
702   ON_DEBUG (printf("Button dims = (%d,%d)\n", button.Width(),button.Height()));
703   ON_DEBUG (printf ("Button center = (%d,%d)\n", bcenter_x, bcenter_y));
704
705   pwidth = f_porthole->Width();
706   pheight = f_porthole->Height();
707   twidth = f_tree->Width();
708   theight = f_tree->Height();
709   ON_DEBUG (printf ("Porthole dimensions = (%d,%d)\n", pwidth, pheight));
710   ON_DEBUG (printf ("Tree dimensions = (%d,%d)\n", twidth, theight));
711
712   pcenter_x = f_porthole->X() + pwidth / 2;
713   pcenter_y = f_porthole->Y() + pheight / 2;
714   ON_DEBUG (printf ("Porthole center = (%d,%d)\n", pcenter_x, pcenter_y));
715
716   if (bcenter_x > pcenter_x)
717     off_x = pcenter_x - bcenter_x;
718
719   if (bcenter_y > pcenter_y)
720     off_y = pcenter_y - bcenter_y;
721
722   if (off_x + twidth < pwidth)
723     off_x = pwidth - twidth;
724
725   if (off_y + theight < pheight)
726     off_y = pheight - theight;
727
728   ON_DEBUG (printf ("Button center offset = (%d,%d)\n", off_x, off_y));
729
730   if (off_x < 0)
731     {
732       f_tree->X (off_x, args);
733       ON_DEBUG (printf ("Setting Tree X to %d\n", off_x));
734     }
735
736   if (off_y < 0)
737     {
738       f_tree->Y (off_y, args);
739       ON_DEBUG (printf ("Setting Tree Y to %d\n", off_y));
740     }
741
742   if (args.NumArgs() > 0)
743     f_tree->Set (args);
744 }
745
746
747 // /////////////////////////////////////////////////////////////////
748 // receive - handle node display messages
749 // /////////////////////////////////////////////////////////////////
750
751 void
752 MapAgent::receive (UAS_DocumentRetrievedMsg &message, void* /*client_data*/)
753 {
754   extern bool g_style_sheet_update ;
755   ON_DEBUG (printf ("MapAgent::receive - updating the map!\n"));
756   if (f_locked && f_onscreen && !g_style_sheet_update)
757     {
758       // MapAgent::receive is just for automatic self-update, so
759       // there's no need for mapping/raising the window.
760       display (message.fDoc, FALSE);
761     }
762 }
763
764 void
765 MapAgent::clear_map(UAS_Pointer<UAS_Common> &lib)
766 {
767   if(lib->lid() == f_doc_ptr->lid())
768   {
769     clear_it();
770     f_doc_ptr = NULL;
771   }
772 }
773
774 void
775 MapAgent::clear_it()
776 {
777   if ((f_tree != NULL) && f_onscreen)
778   {
779     f_tree->Destroy();
780     delete f_tree;
781     f_tree = NULL;
782   }
783 }