home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / ui / menu.cxx < prev    next >
C/C++ Source or Header  |  1995-04-07  |  26KB  |  877 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6. /*
  7.  *
  8.  *          Copyright (C) 1994, M. A. Sridhar
  9.  *  
  10.  *
  11.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  12.  *     to copy, modify or distribute this software  as you see fit,
  13.  *     and to use  it  for  any  purpose, provided   this copyright
  14.  *     notice and the following   disclaimer are included  with all
  15.  *     copies.
  16.  *
  17.  *                        DISCLAIMER
  18.  *
  19.  *     The author makes no warranties, either expressed or implied,
  20.  *     with respect  to  this  software, its  quality, performance,
  21.  *     merchantability, or fitness for any particular purpose. This
  22.  *     software is distributed  AS IS.  The  user of this  software
  23.  *     assumes all risks  as to its quality  and performance. In no
  24.  *     event shall the author be liable for any direct, indirect or
  25.  *     consequential damages, even if the  author has been  advised
  26.  *     as to the possibility of such damages.
  27.  *
  28.  */
  29.  
  30. #if defined(__GNUC__)
  31. #pragma implementation
  32. #endif
  33.  
  34.  
  35. #define MNEMONIC_CHAR '&'  // For alt- functions
  36.  
  37. #if defined(__MS_WINDOWS__)
  38. #include <windows.h>
  39.  
  40. #elif defined(__X_MOTIF__)
  41. #include <Xm/RowColumn.h>
  42. #include <Xm/CascadeB.h>
  43. #include <Xm/PushB.h>
  44. #include <Xm/CascadeBG.h>
  45. #include <Xm/PushBG.h>
  46. #include <Xm/Separator.h>
  47. #endif
  48.  
  49. #include "ui/menu.h"
  50. #include "ui/cntroler.h"
  51. #include "ui/composit.h"
  52.  
  53. #include "base/binding.h"
  54. #include "base/treewalk.h"
  55.  
  56. #if defined(__GNUC__) && __GNUC_MINOR__ >= 6
  57. template class CL_Binding<UI_Menu>;
  58. #endif
  59.  
  60.  
  61. UI_MenuItem::UI_MenuItem (UI_Menu* container, const char*
  62.                           label, UI_ViewID id)
  63. : UI_SimpleVObject ((UI_CompositeVObject*) container->Parent(),
  64.     // --------------^^^^^^^^^^^^^^^^^^^^
  65.     // We can safely cast down, because the constructor of UI_Menu insists
  66.     // on a Composite for its parent.
  67.                     UI_Rectangle (), id,  -1),                    
  68.     _container (*container)
  69. {
  70.     _SetTitle (label);
  71.     _ownModel  = FALSE;
  72. #if defined(__MS_WINDOWS__)
  73.     _handle    = 0;
  74. #elif defined(__OS2__)
  75.     _handle    = 0;
  76. #elif defined(__X_MOTIF__)
  77.     _xitemw = NULL;
  78. #endif
  79. }
  80.  
  81.  
  82. UI_WindowClass UI_MenuItem::WindowClass () const
  83. {
  84.     // This method is not used for widget creation, only for run-time type
  85.     // identification
  86. #if defined(__MS_WINDOWS__)
  87.     return "";
  88. #elif defined(__OS2__)
  89.     return NULL;
  90. #elif defined (__X_MOTIF__)
  91.     return NULL; 
  92. #endif
  93. }
  94.  
  95.  
  96.  
  97.  
  98. bool UI_MenuItem::MakeVisualElement ()
  99. {
  100. #if defined(__MS_WINDOWS__)
  101.     // The actual visual element for a popup menu is created by the UI_Menu
  102.     // object, so if we are a popup, our handle is already set
  103.     return FALSE; // We don't register menu items under Windows 
  104. #elif defined(__OS2__)
  105.     return _handle ? TRUE : FALSE;
  106.     // Only non-leaf items have non-zero handles, and those are the ones we
  107.     // register.
  108. #elif defined (__X_MOTIF__)
  109.     return TRUE; // We register all menu items under X
  110. #endif
  111. }
  112.  
  113. void UI_MenuItem::_PrivateInitialize ()
  114. {
  115.     UI_SimpleVObject::_PrivateInitialize();
  116. #if defined(__MS_WINDOWS__)
  117.     // Under Windows,  the Controller maintains a map of menu id's
  118.     // for each window, and the MenuItemCreated method updates this map.
  119.     if (_id > 0 && !_Controller->MenuItemCreated (this))
  120.         CL_Error::Warning ("MenuItem constructor: duplicate view id %ld",
  121.                            _id);
  122. #endif
  123. }
  124.  
  125.  
  126. bool UI_MenuItem::DestroyVisualElement ()
  127. {
  128. #if defined (__MS_WINDOWS__)
  129.     if (_handle > 0) {
  130.         DestroyMenu (_handle);
  131.         return TRUE;
  132.     }
  133.     return FALSE;
  134. #elif defined(__OS2__)
  135.     return UI_SimpleVObject::DestroyVisualElement ();
  136.     
  137. #elif defined (__X_MOTIF__)
  138.     if (_xwidget)
  139.         XtDestroyWidget (_xwidget);
  140.     if (_xitemw)
  141.         XtDestroyWidget (_xitemw);
  142.     _xitemw = _xwidget = 0; // So that the controller does not attempt
  143.                             // destruction again
  144. #endif
  145. }
  146.  
  147.  
  148.  
  149. bool UI_MenuItem::Enable ()
  150. {
  151.     _enabled = TRUE;
  152. #if defined(__MS_WINDOWS__)
  153.     _SetState ();
  154.     return TRUE;
  155. #elif defined(__OS2__)
  156.     WinSendMsg (_container.ViewHandle(), MM_SETITEMATTR,
  157.                 MPFROM2SHORT (_id, TRUE), MPFROM2SHORT (MIA_DISABLED, 0));
  158.     return TRUE;
  159. #elif defined(__X_MOTIF__)
  160.     if (_xitemw)
  161.         XtSetSensitive (_xitemw, TRUE);
  162.     return TRUE;
  163. #endif
  164. }
  165.  
  166.  
  167.  
  168. bool UI_MenuItem::Disable ()
  169. {
  170.     _enabled = FALSE;
  171. #if defined(__MS_WINDOWS__)
  172.     _SetState ();
  173.     return TRUE;
  174. #elif defined(__OS2__)
  175.     WinSendMsg (_parentHandle, MM_SETITEMATTR,
  176.                 MPFROM2SHORT (_id, TRUE),
  177.                 MPFROM2SHORT (MIA_DISABLED, MIA_DISABLED));
  178.     return TRUE;
  179. #elif defined(__X_MOTIF__)
  180.     if (_xitemw)
  181.         XtSetSensitive (_xitemw, FALSE);
  182.     return TRUE;
  183. #endif
  184. }
  185.  
  186. #if defined (__MS_WINDOWS__)
  187. void UI_MenuItem::_SetState ()
  188. {
  189.     if (!_parentHandle)
  190.         return;
  191.     short pos =  _container.Index(_id);
  192.     UINT state = MF_STRING;
  193.     if (_handle)
  194.         state |= MF_POPUP;
  195.     if (IsEnabled())
  196.         state |= MF_ENABLED;
  197.     else
  198.         state |= MF_GRAYED;
  199.     if (state & MF_POPUP) {
  200.         short count = GetMenuItemCount (_parentHandle);
  201.         for (short i = 0; i < count; i++)
  202.             if (_handle == GetSubMenu (_parentHandle, i)) {
  203.                 ModifyMenu (_parentHandle, pos, state | MF_BYPOSITION,
  204.                             _handle, _title);
  205.                 break;
  206.             }
  207.         SetWindowPos  (_container.Parent()->ViewHandle(),
  208.                        NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | 
  209.                        SWP_NOSIZE | SWP_NOMOVE | 
  210.                        SWP_NOACTIVATE | SWP_NOZORDER); // Force re-draw
  211.     }
  212.     else
  213.         ModifyMenu (_parentHandle, _id, state, _id, _title);
  214.     DrawMenuBar (_container.ViewHandle());
  215. }
  216. #endif
  217.  
  218. bool UI_MenuItem::_TitleChanged (CL_Object&, long)
  219. {
  220. #if defined (__MS_WINDOWS__)
  221.     _SetState ();
  222.     return TRUE;
  223. #elif defined(__OS2__)
  224.     CL_String title = _title;
  225.     title.Replace ("&", "~");
  226.     WinSendMsg (_container.ViewHandle(), MM_SETITEMTEXT, MPFROMSHORT (_id),
  227.                 MPFROMP (title.AsPtr()));
  228.     return TRUE;
  229. #elif defined (__X_MOTIF__)
  230.     if (!_xitemw)
  231.         return TRUE; // Not yet set up
  232.     SetLabel ();
  233.     XmUpdateDisplay (_xitemw);
  234.     return TRUE;
  235. #endif
  236. }
  237.  
  238.  
  239. UI_ViewHandle UI_MenuItem::ViewHandle () const
  240. {
  241. #if defined (__MS_WINDOWS__)
  242.     return UI_VisualObject::ViewHandle ();
  243.  
  244. #elif defined(__OS2__)
  245.     return _handle;
  246.     
  247. #elif defined (__X_MOTIF__)
  248.     return UI_ViewHandle (_xitemw);
  249.  
  250. #endif
  251. }
  252.  
  253.  
  254. UI_MenuItem::~UI_MenuItem ()
  255. {
  256. #if defined(__MS_WINDOWS__)
  257.     _Controller->MenuItemDestroyed (this);
  258. #endif
  259. }
  260.  
  261.  
  262. #if defined (__X_MOTIF__)
  263. void UI_MenuItem::SetLabel ()
  264. {
  265.     CL_String label = _title;
  266.     if (label == UIMenu_Separator)
  267.         return;
  268.     short mnemonic_pos = label.CharIndex (MNEMONIC_CHAR);
  269.     if (mnemonic_pos >= 0 && mnemonic_pos < label.Size()-1) {
  270.         label(mnemonic_pos,1) = ""; // Remove the mnemonic char
  271.         if (label[mnemonic_pos] == MNEMONIC_CHAR) // Two consecutive?
  272.             mnemonic_pos = -1;
  273.     }
  274.     XmString xmlabel = XmStringCreate ((char*) label.AsPtr(),
  275.                                        XmSTRING_DEFAULT_CHARSET);
  276.     Arg arg[2];
  277.     short argn = 0;
  278.     XtSetArg (arg[0], XmNlabelString, xmlabel); argn++;
  279.     if (mnemonic_pos >= 0) {
  280.         XtSetArg (arg[1], XmNmnemonic, label[mnemonic_pos]);  argn++;
  281.     }
  282.     XtSetValues (_xitemw, arg, argn);
  283.     XmStringFree (xmlabel);
  284. }
  285.  
  286. void UI_MenuItem::GetFocusCallback (Widget w, void *client, void *call)
  287. {
  288.     UI_MenuItem *mi = (UI_MenuItem *) client;
  289.     _Controller->AddEvent (new UI_Event (Event_GetFocus, mi, mi));
  290. }
  291.  
  292.  
  293.  
  294. void UI_MenuItem::LoseFocusCallback (Widget w, void *client, void *call)
  295. {
  296.     UI_MenuItem *mi = (UI_MenuItem *) client;
  297.     _Controller->AddEvent (new UI_Event (Event_LoseFocus, mi, mi));
  298. }
  299.  
  300.  
  301. #include <iostream.h> // DEBUG
  302. void UI_MenuItem::SelectionCallback (Widget w, void *client, void *call)
  303. {
  304.     UI_MenuItem* mi = (UI_MenuItem *) client;
  305.     _Controller->AddEvent (new UI_Event (Event_Select, mi, mi));
  306. }
  307.  
  308. #endif
  309.  
  310. // --------------------- UI_Menu methods -----------------------
  311.  
  312.  
  313. #if defined(__OS2__)
  314. #define ROOT_ID FID_MENU
  315. #else
  316. #define ROOT_ID 0
  317. #endif
  318.  
  319. UI_Menu::UI_Menu (UI_CompositeVObject* parent, UI_MenuItemDescriptor* items)
  320. : UI_VisualObject (parent, UI_Rectangle (), -1)
  321. {
  322.     UI_MenuItem* root_item = new UI_MenuItem (this, "", ROOT_ID);
  323.     if (!root_item)
  324.         return;
  325.     _menuTree.NewRoot (ROOT_ID);
  326.     _menuTree.Root()->Content() = (long) root_item;
  327.     if (_BuildMenuSubtree (items, ROOT_ID) <= 0)
  328.         CL_Error::Warning ("UI_Menu constructor: no menu items to build!");
  329.     _focusItem = NULL;
  330. }
  331.  
  332.  
  333. UI_ViewID UI_Menu::RootID () const
  334. {
  335.     return ROOT_ID;
  336. }
  337.  
  338.  
  339. static long _SeparatorIdCount = -3; // Hack to support separators
  340.  
  341. short UI_Menu::_BuildMenuSubtree (UI_MenuItemDescriptor* items,
  342.                                  UI_ViewID subtree_root)
  343. {
  344.     if (!items)
  345.         return 0;
  346.     CL_IntegerTreeNode* root = _menuTree.Node (subtree_root);
  347.     if (!root)
  348.         return 0;
  349.     for (short n = 0; items[n].label != NULL; n++) {
  350.         UI_ViewID id;
  351.         if (CL_String (UIMenu_Separator) == items[n].label)
  352.             id = _SeparatorIdCount--;
  353.         else
  354.             id = items[n].id;
  355.         UI_MenuItem* new_itm = new UI_MenuItem
  356.             (this, items[n].label, id);
  357.         CL_IntegerTreeNode* node = _menuTree.AddChild (id, subtree_root);
  358.         if (node) {
  359.             node->Content() = (long) new_itm;
  360.             _BuildMenuSubtree (items[n].submenu, items[n].id);
  361.         }
  362.         else
  363.             CL_Error::Warning ("YACL: UI_Menu: invalid (duplicate?) "
  364.                                "menu item id %ld", id);
  365.     }
  366.     return n;
  367. }
  368.  
  369.  
  370. bool UI_Menu::Add (UI_ViewID id, const char* label,
  371.                    UI_ViewID parent_id, short rank)
  372. {
  373.     if (id <= 0)
  374.         return FALSE; // Cannot add new root
  375.     CL_IntegerTreeNode* subtree_root = _menuTree.Node (parent_id);
  376.     if (!subtree_root)
  377.         return FALSE;
  378.     UI_MenuItem* new_itm = new UI_MenuItem (this, label, id);
  379.     CL_IntegerTreeNode* node = _menuTree.AddChild (id, parent_id, rank);
  380.     if (node) {
  381.         node->Content() = (long) new_itm;
  382.         if (ViewHandle())
  383.             _CreateMenuItemVisual (*node);
  384.         return TRUE;
  385.     }
  386.     return FALSE;
  387. }
  388.  
  389.  
  390.  
  391. bool UI_Menu::AddSeparator (UI_ViewID parent_id, short rank)
  392. {
  393.     CL_IntegerTreeNode* subtree_root = _menuTree.Node (parent_id);
  394.     if (!subtree_root)
  395.         return FALSE;
  396.     UI_ViewID id =  _SeparatorIdCount--;
  397.     UI_MenuItem* new_itm = new UI_MenuItem (this, UIMenu_Separator, id);
  398.     CL_IntegerTreeNode* node = _menuTree.AddChild (id, parent_id, rank);
  399.     if (node) {
  400.         node->Content() = (long) new_itm;
  401.         if (ViewHandle())
  402.             _CreateMenuItemVisual (*node);
  403.         return TRUE;
  404.     }
  405.     return FALSE;
  406. }
  407.  
  408.  
  409. bool UI_Menu::Remove (UI_ViewID id)
  410. {
  411.     
  412.     CL_IntegerTreeNode* node = _menuTree.Node (id);
  413.     if (!node)
  414.         return FALSE;
  415.     UI_MenuItem* itm = (UI_MenuItem*) node->Content();
  416. #if defined(__MS_WINDOWS__)
  417.     if (!node->IsLeaf()) {
  418.         short count = GetMenuItemCount (itm->_parentHandle);
  419.         for (short i = 0; i < count; i++)
  420.             if (itm->_handle == GetSubMenu (itm->_parentHandle, i)) {
  421.                 RemoveMenu (itm->_parentHandle, i, MF_BYPOSITION);
  422.                 break;
  423.             }
  424.     }
  425.     else
  426.         RemoveMenu (itm->_parentHandle, itm->_id, MF_BYCOMMAND);
  427.     DrawMenuBar (Parent()->ViewHandle());
  428.     CL_IntegerTreePostWalker walker (_menuTree.Node (id));
  429.     while (walker.More()) {
  430.         CL_IntegerTreeNode* node = walker.Next();
  431.         UI_MenuItem* itm = (UI_MenuItem*) node->Content();
  432.         if (itm) {
  433.             itm->Finalize ();
  434.             itm->DestroyVisualElement();
  435.             delete itm;
  436.             node->Content() = NULL; // Better safe than sorry
  437.         }
  438.     }
  439.     _menuTree.DestroySubtree (id);
  440.     // Don't use Application->Destroy because, under Windows, menu items are
  441.     // not registered with the Controller.
  442.  
  443. #elif defined(__X_MOTIF__)
  444.     _Application->Destroy (itm);
  445.     _menuTree.DestroySubtree (id);
  446. #elif defined(__OS2__)
  447.     WinSendMsg (itm->_parentHandle, MM_DELETEITEM, MPFROM2SHORT (id, TRUE),
  448.                 0);
  449.     CL_IntegerTreePostWalker walker (_menuTree.Node (id));
  450.     while (walker.More()) {
  451.         CL_IntegerTreeNode* node = walker.Next();
  452.         UI_MenuItem* itm = (UI_MenuItem*) node->Content();
  453.         if (itm) {
  454.             itm->Finalize ();
  455.             itm->DestroyVisualElement();
  456.             delete itm;
  457.             node->Content() = NULL; // Better safe than sorry
  458.         }
  459.     }
  460.     _menuTree.DestroySubtree (id);
  461. #endif
  462.     return TRUE;
  463. }
  464.  
  465.  
  466. short UI_Menu::ChildCount (UI_ViewID id) const
  467. {
  468.     CL_IntegerTreeNode* node = _menuTree.Node (id);
  469.     return node ? node->ChildCount() : -1;
  470. }
  471.  
  472.  
  473. UI_MenuItem* UI_Menu::Child (UI_ViewID id, short i) const
  474. {
  475.     CL_IntegerTreeNode* node = _menuTree.Node (id);
  476.     if (!node)
  477.         return (UI_MenuItem*) NULL;
  478.     node = node->Child(i);
  479.     return (node ? (UI_MenuItem*) node->Content () : (UI_MenuItem*) NULL);
  480. }
  481.  
  482.  
  483.  
  484. short UI_Menu::Index (UI_ViewID id) const
  485. {
  486.     CL_IntegerTreeNode* node = _menuTree.Node (id);
  487.     return node ? node->IndexInParent() : -1;
  488. }
  489.  
  490. UI_MenuItem* UI_Menu::operator [] (UI_ViewID id)
  491. {
  492.     CL_IntegerTreeNode* node = _menuTree.Node (id);
  493.     return node ? ((UI_MenuItem*) node->Content()) : (UI_MenuItem*) NULL;
  494. }
  495.  
  496.  
  497. UI_WindowClass UI_Menu::WindowClass () const
  498. {
  499.     // This method is not used for widget creation, only for run-time type
  500.     // identification
  501. #if defined(__MS_WINDOWS__)
  502.     return "menu";
  503. #elif defined(__OS2__)
  504.     return WC_MENU;
  505. #elif defined (__X_MOTIF__)
  506.     return NULL; 
  507. #endif
  508. }
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520. #if defined(__MS_WINDOWS__)
  521. bool UI_Menu::_CreateMenuItemVisual (CL_IntegerTreeNode& node)
  522. {
  523.     UI_MenuItem*         itm   = (UI_MenuItem *) node.Content ();
  524.     CL_IntegerTreeNode* parent = node.Parent();
  525.     UI_MenuItem*        parentItem = parent ? (UI_MenuItem*)
  526.         parent->Content() : 0;
  527.     if (parentItem && !parentItem->_handle) {
  528.         UI_MenuItem* gpItem = (UI_MenuItem*) parent->Parent()->Content();
  529.         UI_ViewHandle gpHandle = gpItem->_handle;
  530.         parentItem->_handle = CreatePopupMenu ();
  531.         ModifyMenu (gpHandle, parentItem->ViewID(),
  532.                     MF_BYCOMMAND | MF_STRING | MF_POPUP,
  533.                     parentItem->_handle, parentItem->Title());
  534.         DrawMenuBar (Parent()->ViewHandle());
  535.     }
  536.  
  537.     UI_ViewHandle h = parent ? parentItem->ViewHandle() : 0;
  538.     itm->_parentHandle = h;
  539.  
  540.     short position = node.IndexInParent();
  541.     if ( !node.IsLeaf () ) {
  542.         if (parent) {
  543.             // This is not the root. The root's handle is set by the
  544.             // MakeVisualElement method that is calling us.
  545.             itm->_handle = CreatePopupMenu ();
  546.             InsertMenu (h, position, MF_STRING | MF_POPUP | MF_BYPOSITION,
  547.                         itm->_handle, itm->_title.AsPtr());
  548.         }
  549.     }
  550.     else {
  551.         if ( h ) {
  552.             if (CL_String (UIMenu_Separator) == itm->_title)
  553.                 InsertMenu (h, position, MF_SEPARATOR, -1, 0);
  554.             else
  555.                 InsertMenu (h, position, MF_STRING  | MF_BYPOSITION,
  556.                             itm->_id, itm->_title.AsPtr());
  557.         }
  558.     }
  559.     return TRUE;
  560. }
  561. #endif
  562.  
  563.  
  564.  
  565. #if defined(__OS2__)
  566. bool UI_Menu::_CreateMenuItemVisual (CL_IntegerTreeNode& node)
  567. {
  568.     UI_MenuItem*         itm   = (UI_MenuItem *) node.Content ();
  569.     CL_IntegerTreeNode* parent = node.Parent();
  570.     UI_MenuItem*        parentItem = parent ? (UI_MenuItem*)
  571.         parent->Content() : 0;
  572.     HWND frame = WinQueryWindow (_parent->ViewHandle(), QW_PARENT);
  573.     HWND parentHandle = parentItem ? parentItem->ViewHandle() : frame;
  574.     if (!parent) {
  575.         itm->_handle = _handle;
  576.         itm->_parentHandle = 0;
  577.     }
  578.     short position = node.IndexInParent();
  579.     if (parent && position >= parent->ChildCount())
  580.         position = MIT_END;
  581.     MENUITEM menuItemStruct;
  582.     menuItemStruct.iPosition = position;
  583.     CL_String title = itm->Title();
  584.     if (title == UIMenu_Separator)
  585.         menuItemStruct.afStyle = MIS_SEPARATOR;
  586.     else {
  587.         title.Replace ("&",  "~");
  588.         menuItemStruct.afStyle = MIS_TEXT;
  589.         if (!parentItem) {
  590.             menuItemStruct.afStyle |= MIS_SUBMENU;
  591.             menuItemStruct.hwndSubMenu = _handle;
  592.         }
  593.         else if (node.ChildCount()) {
  594.             menuItemStruct.afStyle |= MIS_SUBMENU;
  595.             menuItemStruct.hwndSubMenu = WinCreateWindow
  596.                 (parentHandle, WC_MENU, title.AsPtr(),
  597.                  WS_VISIBLE, 0, 0, 0, 0, parentHandle,
  598.                  HWND_BOTTOM, _id, NULL, NULL);
  599.         }
  600.         else
  601.             menuItemStruct.hwndSubMenu = 0;
  602.     }
  603.     menuItemStruct.afAttribute = 0;
  604.     menuItemStruct.id = itm->ViewID();
  605.     menuItemStruct.hItem = 0;
  606.     WinSendMsg (parentHandle, MM_INSERTITEM, (MPARAM) &menuItemStruct,
  607.                 (MPARAM) title.AsPtr());
  608.     itm->_handle = menuItemStruct.hwndSubMenu;
  609.     itm->_parentHandle = parentHandle;
  610.     WinSendMsg (frame, WM_UPDATEFRAME, (MPARAM) FCF_MENU, 0);
  611.     return TRUE;
  612. }
  613. #endif
  614.  
  615.  
  616.  
  617. #if defined(__X_MOTIF__)
  618. bool UI_Menu::_CreateMenuItemVisual (CL_IntegerTreeNode& node)
  619. {
  620.     UI_MenuItem*         itm   = (UI_MenuItem *) node.Content ();
  621.     CL_IntegerTreeNode* parent = node.Parent();
  622.     UI_MenuItem*        parentItem = parent ? (UI_MenuItem*)
  623.         parent->Content() : 0;
  624.     if (parentItem && !parentItem->_xwidget) {
  625.         // This can happen if "node" is a newly-added leaf
  626.         Widget gpWidget = ((UI_MenuItem *)
  627.                            parent->Parent()->Content())->_xwidget;
  628.         char *title    = "menuitems";
  629.         parentItem->_xwidget = XmCreatePulldownMenu (gpWidget, title, 
  630.                                                      NULL, 0);
  631.         XtRealizeWidget (parentItem->_xwidget);
  632.     }
  633.  
  634.  
  635.     if ( !node.IsLeaf () ) {
  636.         if (parent) {
  637.             // This is not the root. The root's handle is set by the
  638.             // MakeVisualElement method that is calling us.
  639.             Widget parentw = ((UI_MenuItem *)
  640.                               parent->Content())->_xwidget;
  641.             char *title    = "menuitems";
  642.             itm->_xwidget = XmCreatePulldownMenu (parentw, title, 
  643.                                                   NULL, 0);
  644.             itm->_xitemw = XtVaCreateManagedWidget
  645.                 ((char*) itm->_title.AsPtr(),
  646.                  xmCascadeButtonGadgetClass, parentw,
  647.                  XmNsubMenuId,  itm->_xwidget,
  648.                  NULL);
  649.             itm->SetLabel ();
  650.             XtAddCallback (itm->_xitemw, XmNactivateCallback, 
  651.                            &(UI_MenuItem::GetFocusCallback), itm);
  652.  
  653.             XtRealizeWidget (itm->_xwidget);
  654.             XtRealizeWidget (itm->_xitemw);
  655.         }
  656.     }
  657.     else {
  658.         Widget parentw = ((UI_MenuItem *) parent->Content ())->_xwidget;
  659.         CL_String instance_name = itm->InstanceName();
  660.         char* label    = (char *) instance_name.AsPtr ();
  661.         UI_MenuItem* root_item = (UI_MenuItem *)  
  662.                                   _menuTree.Node (ROOT_ID)->Content();
  663.         UI_MenuItem* parent_item = (UI_MenuItem *) parent->Content ();
  664.  
  665.         struct _WidgetClassRec* wclass;
  666.         if (CL_String (UIMenu_Separator) != itm->_title)
  667.             wclass = (parent_item == root_item ? xmCascadeButtonGadgetClass:
  668.                       xmPushButtonGadgetClass);
  669.         else
  670.             wclass = xmSeparatorWidgetClass;
  671.         parentw = (parent_item == root_item ? _xwidget : parentw);
  672.  
  673.         if ( parent_item == root_item ) {
  674.             itm->_xitemw = XtVaCreateManagedWidget
  675.                 (label, wclass, parentw,  NULL);
  676.             if (wclass != xmSeparatorWidgetClass) {
  677.                 XtAddCallback (itm->_xitemw, XmNactivateCallback, 
  678.                                &(UI_MenuItem::SelectionCallback), itm);
  679.                 itm->SetLabel ();
  680.             }
  681.             XtRealizeWidget (itm->_xitemw);
  682.         }
  683.         else {
  684.             itm->_xitemw = XtCreateManagedWidget
  685.                 (label, wclass, parentw, NULL, 0);
  686.             if (wclass != xmSeparatorWidgetClass) {
  687.                 XtAddCallback (itm->_xitemw, XmNarmCallback, 
  688.                                &(UI_MenuItem::GetFocusCallback), itm);
  689.                 XtAddCallback (itm->_xitemw, XmNdisarmCallback, 
  690.                                &(UI_MenuItem::LoseFocusCallback), itm);
  691.                 XtAddCallback (itm->_xitemw, XmNactivateCallback, 
  692.                                &(UI_MenuItem::SelectionCallback), itm);
  693.  
  694.                 itm->SetLabel ();
  695.             }
  696.             XtRealizeWidget (itm->_xitemw);
  697.         }
  698.     }
  699.     return TRUE;
  700. }
  701. #endif
  702.  
  703.  
  704.  
  705. bool UI_Menu::HandleEvent (UI_Event* e)
  706. {
  707.     if (e->Type() == Event_LoseFocus)
  708.         _focusItem = NULL;
  709.     return ProcessEvent (e);
  710. }
  711.  
  712.  
  713.     
  714. bool UI_Menu::MakeVisualElement ()
  715. {
  716.     return UI_VisualObject::MakeVisualElement ();
  717. }
  718.  
  719. bool UI_Menu::DestroyVisualElement ()
  720. {
  721. #if defined(__MS_WINDOWS__)
  722.     // We need to walk the tree and destroy the menu items explicitly here;
  723.     // Under MS-Windows, this is 
  724.     // because menu items are not registered with the Controller.
  725.     CL_IntegerTreePostWalker walker (_menuTree.Root());
  726.     for (walker.Reset(); walker.More(); ) {
  727.         UI_MenuItem* m = (UI_MenuItem*) walker.Next()->Content();
  728.         m->DestroyVisualElement();
  729.         delete m;
  730.     }
  731. #elif defined(__OS2__)
  732.     // Non-leaf menu items will be destroyed by the Controller, but we do
  733.     // need to destroy the menu bar or popup menu.
  734.     WinDestroyWindow (_handle);
  735. #endif
  736.     return FALSE;
  737. }
  738.  
  739.  
  740. UI_Menu::~UI_Menu()
  741. {
  742. }
  743.  
  744. #if defined(__MS_WINDOWS__) || defined(__OS2__)
  745. void UI_Menu::MoveFocusTo (UI_MenuItem* itm)
  746. {
  747.     if (_focusItem != itm)
  748.         _focusItem = itm;
  749. }
  750. #endif
  751.  
  752.  
  753. // ----------------- UI_MenuBar methods -------------------------
  754.  
  755.  
  756.  
  757. UI_MenuBar::UI_MenuBar (UI_CompositeVObject* parent,
  758.                         UI_MenuItemDescriptor* item)
  759. : UI_Menu (parent, item)
  760. {
  761. #if defined(__OS2__)
  762.     _style = MS_ACTIONBAR | WS_VISIBLE;
  763. #endif
  764.     parent->UseMenuBar (this);
  765. }
  766.  
  767.  
  768. bool UI_MenuBar::MakeVisualElement ()
  769. {
  770. #if defined (__MS_WINDOWS__)
  771.     UI_MenuItem* root_item = (UI_MenuItem*)
  772.         _menuTree.Node (ROOT_ID)->Content();
  773.     root_item->_handle = CreateMenu ();
  774.     _handle = root_item->_handle;
  775.  
  776. #elif defined(__OS2__)
  777.     _id = FID_MENU;
  778.     HWND frame = WinQueryWindow (_parent->ViewHandle(), QW_PARENT);
  779.     WinSendMsg (frame, WM_UPDATEFRAME, (MPARAM) FCF_MENU, 0);
  780.     _handle = WinCreateWindow
  781.         (frame, WC_MENU, "", _style,
  782.          0, 0, 0, 0, frame, HWND_TOP, _id, NULL, NULL);
  783. #elif defined (__X_MOTIF__)
  784.     UI_MenuItem* root_item = (UI_MenuItem*)
  785.         _menuTree.Node (ROOT_ID)->Content();
  786.     root_item->_xwidget = XmCreateMenuBar ((Widget)_parent->ViewHandle (), 
  787.                                            "menubar", NULL, 0);
  788.     root_item->_xitemw = 0;
  789.     _xwidget = root_item->_xwidget;
  790.  
  791.     XtManageChild   (root_item->_xwidget);
  792.     XtRealizeWidget (root_item->_xwidget);
  793. #endif
  794.     CL_IntegerTreePreWalker walk (_menuTree.Root());
  795.     while (walk.More()) {
  796.         CL_IntegerTreeNode* node = walk.Next();
  797.         _CreateMenuItemVisual (*node);
  798.     }
  799.     _created = TRUE;
  800. #if defined(__OS2__)
  801.     WinSendMsg (frame, WM_UPDATEFRAME, (MPARAM) FCF_MENU, 0);
  802. #endif    
  803.     return TRUE;
  804. }
  805.  
  806.  
  807. UI_PopupMenu::UI_PopupMenu (UI_CompositeVObject* parent,
  808.                             UI_MenuItemDescriptor* item)
  809. : UI_Menu (parent, item)
  810. {
  811.     _visible = FALSE; // Initially invisible
  812. }
  813.  
  814.  
  815. UI_PopupMenu::~UI_PopupMenu ()
  816. {
  817. }
  818.  
  819.  
  820.  
  821. bool UI_PopupMenu::MakeVisualElement ()
  822. {
  823.     UI_MenuItem* root_item = (UI_MenuItem*)
  824.         _menuTree.Node (ROOT_ID)->Content();
  825. #if defined (__MS_WINDOWS__)
  826.     root_item->_handle = CreatePopupMenu ();
  827.     _handle = root_item->_handle;
  828. #elif defined(__OS2__)
  829.     _style = WS_VISIBLE;
  830.     UI_ViewHandle parentHandle = _parent->ViewHandle();
  831.     _handle = WinCreateWindow
  832.         (parentHandle, WC_MENU, "", _style,
  833.          0, 0, 0, 0, parentHandle, HWND_TOP, _id, NULL, NULL);
  834.     root_item->_handle = _handle;
  835. #elif defined (__X_MOTIF__)
  836.     root_item->_visible = FALSE;
  837.     root_item->_xwidget = XmCreatePopupMenu ((Widget)_parent->ViewHandle (), 
  838.                                              NULL, NULL, 0); 
  839.     root_item->_xitemw = 0;
  840.     _xwidget = root_item->_xwidget;
  841.     XtRealizeWidget (root_item->_xwidget);
  842. #endif
  843.     CL_IntegerTreePreWalker walk (_menuTree.Root());
  844.     while (walk.More()) {
  845.         CL_IntegerTreeNode* node = walk.Next();
  846.         _CreateMenuItemVisual (*node);
  847.     }
  848.     _created = TRUE;
  849.     return TRUE;
  850. }
  851.  
  852. bool UI_PopupMenu::ShowAt (const UI_Point& p)
  853. {
  854.     UI_ViewHandle parentHandle = _parent->ViewHandle();
  855. #if defined(__MS_WINDOWS__)
  856.     UI_Point q = p + _parent->ClientArea().Origin();
  857.     return TrackPopupMenu (_handle, TPM_LEFTALIGN, q.XCoord(), q.YCoord(), 0,
  858.                            parentHandle, NULL);
  859.  
  860. #elif defined(__OS2__)
  861.     UI_Point q = p; // + _parent->ClientArea().Origin();
  862.     WinPopupMenu (parentHandle, parentHandle, _handle, q.XCoord(),
  863.                   _YACLWindowHeight (parentHandle) - q.YCoord() - 1,
  864.                   0, PU_MOUSEBUTTON2 | PU_KEYBOARD | PU_MOUSEBUTTON1);
  865.     return TRUE;
  866. #elif defined(__X_MOTIF__)
  867.     Position x, y;
  868.     XtTranslateCoords (parentHandle, p.XCoord(), p.YCoord(), &x, &y);
  869.     XtVaSetValues (_xwidget, XtNx, x, XtNy, y, NULL);
  870.     XtManageChild (_xwidget);
  871.     return TRUE;
  872. #endif
  873. }
  874.  
  875.  
  876.  
  877.