home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / os2 / menu.cpp < prev    next >
C/C++ Source or Header  |  2002-12-17  |  35KB  |  1,224 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        menu.cpp
  3. // Purpose:     wxMenu, wxMenuBar, wxMenuItem
  4. // Author:      David Webster
  5. // Modified by:
  6. // Created:     10/10/99
  7. // RCS-ID:      $Id: MENU.CPP,v 1.37.2.1 2002/12/16 18:34:26 DW Exp $
  8. // Copyright:   (c) David Webster
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13.     #pragma implementation "menu.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifndef WX_PRECOMP
  20.     #include "wx/app.h"
  21.     #include "wx/frame.h"
  22.     #include "wx/menu.h"
  23.     #include "wx/utils.h"
  24.     #include "wx/intl.h"
  25.     #include "wx/log.h"
  26. #endif
  27.  
  28. #if wxUSE_OWNER_DRAWN
  29.     #include "wx/ownerdrw.h"
  30. #endif
  31.  
  32. #include "wx/os2/private.h"
  33.  
  34. // other standard headers
  35. #include <string.h>
  36.  
  37. // ----------------------------------------------------------------------------
  38. // global variables
  39. // ----------------------------------------------------------------------------
  40.  
  41. extern wxMenu*                      wxCurrentPopupMenu;
  42.  
  43. // ----------------------------------------------------------------------------
  44. // constants
  45. // ----------------------------------------------------------------------------
  46.  
  47. //
  48. // The (popup) menu title has this special id
  49. //
  50. static const int                    idMenuTitle = -2;
  51.  
  52. //
  53. // The unique ID for Menus
  54. //
  55. #ifdef __VISAGECPP__
  56. USHORT                              wxMenu::m_nextMenuId = 0;
  57. #else
  58. static USHORT                       wxMenu::m_nextMenuId = 0;
  59. #endif
  60.  
  61. // ----------------------------------------------------------------------------
  62. // macros
  63. // ----------------------------------------------------------------------------
  64.  
  65.     IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
  66.     IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
  67.  
  68. // ----------------------------------------------------------------------------
  69. // static function for translating menu labels
  70. // ----------------------------------------------------------------------------
  71.  
  72. static wxString TextToLabel(
  73.   const wxString&                   rsTitle
  74. )
  75. {
  76.     wxString                        sTitle = "";
  77.     const wxChar*                   zPc;
  78.  
  79.     if (rsTitle.IsEmpty())
  80.         return sTitle;
  81.     for (zPc = rsTitle.c_str(); *zPc != wxT('\0'); zPc++ )
  82.     {
  83.         if (*zPc == wxT('&') )
  84.         {
  85.             if (*(zPc + 1) == wxT('&'))
  86.             {
  87.                 zPc++;
  88.                 sTitle << wxT('&');
  89.             }
  90.             else
  91.                 sTitle << wxT('~');
  92.         }
  93.         else
  94.         {
  95.             if ( *zPc == wxT('~') )
  96.             {
  97.                 //
  98.                 // Tildes must be doubled to prevent them from being
  99.                 // interpreted as accelerator character prefix by PM ???
  100.                 //
  101.                 sTitle << *zPc;
  102.             }
  103.             sTitle << *zPc;
  104.         }
  105.     }
  106.     return sTitle;
  107. } // end of TextToLabel
  108.  
  109. // ============================================================================
  110. // implementation
  111. // ============================================================================
  112.  
  113. // ---------------------------------------------------------------------------
  114. // wxMenu construction, adding and removing menu items
  115. // ---------------------------------------------------------------------------
  116.  
  117. //
  118. // Construct a menu with optional title (then use append)
  119. //
  120. void wxMenu::Init()
  121. {
  122.     m_bDoBreak = FALSE;
  123.     m_nStartRadioGroup = -1;
  124.  
  125.     //
  126.     // Create the menu (to be used as a submenu or a popup)
  127.     //
  128.     if ((m_hMenu =  ::WinCreateWindow( HWND_DESKTOP
  129.                                       ,WC_MENU
  130.                                       ,"Menu"
  131.                                       ,0L
  132.                                       ,0L
  133.                                       ,0L
  134.                                       ,0L
  135.                                       ,0L
  136.                                       ,NULLHANDLE
  137.                                       ,HWND_TOP
  138.                                       ,0L
  139.                                       ,NULL
  140.                                       ,NULL
  141.                                      )) == 0)
  142.     {
  143.         wxLogLastError("WinLoadMenu");
  144.     }
  145.     m_vMenuData.iPosition   = 0;
  146.     m_vMenuData.afStyle     = MIS_SUBMENU | MIS_TEXT;
  147.     m_vMenuData.afAttribute = (USHORT)0;
  148.     m_vMenuData.id          = m_nextMenuId++;
  149.     m_vMenuData.hwndSubMenu = m_hMenu;
  150.     m_vMenuData.hItem       = NULLHANDLE;
  151.  
  152.     //
  153.     // If we have a title, insert it in the beginning of the menu
  154.     //
  155.     if (!m_title.IsEmpty())
  156.     {
  157.         Append( idMenuTitle
  158.                ,m_title
  159.                ,wxEmptyString
  160.                ,wxITEM_NORMAL
  161.               );
  162.         AppendSeparator();
  163.     }
  164. } // end of wxMenu::Init
  165.  
  166. //
  167. // The wxWindow destructor will take care of deleting the submenus.
  168. //
  169. wxMenu::~wxMenu()
  170. {
  171.     //
  172.     // We should free PM resources only if PM doesn't do it for us
  173.     // which happens if we're attached to a menubar or a submenu of another
  174.     // menu
  175.     if (!IsAttached() && !GetParent())
  176.     {
  177.         if (!::WinDestroyWindow((HWND)GetHmenu()) )
  178.         {
  179.             wxLogLastError("WinDestroyWindow");
  180.         }
  181.     }
  182.  
  183. #if wxUSE_ACCEL
  184.     //
  185.     // Delete accels
  186.     //
  187.     WX_CLEAR_ARRAY(m_vAccels);
  188. #endif // wxUSE_ACCEL
  189. } // end of wxMenu::~wxMenu
  190.  
  191. void wxMenu::Break()
  192. {
  193.     // this will take effect during the next call to Append()
  194.     m_bDoBreak = TRUE;
  195. } // end of wxMenu::Break
  196.  
  197. void wxMenu::Attach(
  198.   wxMenuBarBase*                    pMenubar
  199. )
  200. {
  201.     wxMenuBase::Attach(pMenubar);
  202.     EndRadioGroup();
  203. } // end of wxMenu::Break;
  204.  
  205. #if wxUSE_ACCEL
  206.  
  207. int wxMenu::FindAccel(
  208.   int                               nId
  209. ) const
  210. {
  211.     size_t                          n;
  212.     size_t                          nCount = m_vAccels.GetCount();
  213.  
  214.     for (n = 0; n < nCount; n++)
  215.         if (m_vAccels[n]->m_command == nId)
  216.             return n;
  217.     return wxNOT_FOUND;
  218. } // end of wxMenu::FindAccel
  219.  
  220. void wxMenu::UpdateAccel(
  221.   wxMenuItem*                       pItem
  222. )
  223. {
  224.     if (pItem->IsSubMenu())
  225.     {
  226.         wxMenu*                     pSubmenu = pItem->GetSubMenu();
  227.         wxMenuItemList::Node*       pNode = pSubmenu->GetMenuItems().GetFirst();
  228.  
  229.         while (pNode)
  230.         {
  231.             UpdateAccel(pNode->GetData());
  232.             pNode = pNode->GetNext();
  233.         }
  234.     }
  235.     else if (!pItem->IsSeparator())
  236.     {
  237.         //
  238.         // Find the (new) accel for this item
  239.         //
  240.         wxAcceleratorEntry*         pAccel = wxGetAccelFromString(pItem->GetText());
  241.  
  242.         if (pAccel)
  243.             pAccel->m_command = pItem->GetId();
  244.  
  245.         //
  246.         // Find the old one
  247.         //
  248.         size_t                      n = FindAccel(pItem->GetId());
  249.  
  250.         if (n == wxNOT_FOUND)
  251.         {
  252.             //
  253.             // No old, add new if any
  254.             //
  255.             if (pAccel)
  256.                 m_vAccels.Add(pAccel);
  257.             else
  258.                 return;
  259.         }
  260.         else
  261.         {
  262.             //
  263.             // Replace old with new or just remove the old one if no new
  264.             //
  265.             delete m_vAccels[n];
  266.             if (pAccel)
  267.                 m_vAccels[n] = pAccel;
  268.             else
  269.                 m_vAccels.RemoveAt(n);
  270.         }
  271.  
  272.         if (IsAttached())
  273.         {
  274.             m_menuBar->RebuildAccelTable();
  275.         }
  276.     }
  277. } // wxMenu::UpdateAccel
  278.  
  279. #endif // wxUSE_ACCEL
  280.  
  281. //
  282. // Append a new item or submenu to the menu
  283. //
  284. bool wxMenu::DoInsertOrAppend(
  285.   wxMenuItem*                       pItem
  286. , size_t                            nPos
  287. )
  288. {
  289.     wxMenu*                         pSubmenu = pItem->GetSubMenu();
  290.     MENUITEM&                       rItem = (pSubmenu != NULL)?pSubmenu->m_vMenuData:
  291.                                             pItem->m_vMenuData;
  292.  
  293.     ERRORID                         vError;
  294.     wxString                        sError;
  295.     char                            zMsg[128];
  296.  
  297. #if wxUSE_ACCEL
  298.     UpdateAccel(pItem);
  299. #endif // wxUSE_ACCEL
  300.  
  301.     //
  302.     // If "Break" has just been called, insert a menu break before this item
  303.     // (and don't forget to reset the flag)
  304.     //
  305.     if (m_bDoBreak)
  306.     {
  307.         rItem.afStyle |= MIS_BREAK;
  308.         m_bDoBreak = FALSE;
  309.     }
  310.  
  311.     if (pItem->IsSeparator())
  312.     {
  313.         rItem.afStyle |= MIS_SEPARATOR;
  314.     }
  315.  
  316.     //
  317.     // Id is the numeric id for normal menu items and HMENU for submenus as
  318.     // required by ::MM_INSERTITEM message API
  319.     //
  320.  
  321.     if (pSubmenu != NULL)
  322.     {
  323.         wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
  324.         pSubmenu->SetParent(this);
  325.  
  326.         rItem.iPosition = 0; // submenus have a 0 position
  327.         rItem.id        = (USHORT)pSubmenu->GetHMenu();
  328.         rItem.afStyle  |= MIS_SUBMENU | MIS_TEXT;
  329.     }
  330.     else
  331.     {
  332.         rItem.id = pItem->GetId();
  333.     }
  334.  
  335.     BYTE*                           pData;
  336.  
  337. #if wxUSE_OWNER_DRAWN
  338.     if (pItem->IsOwnerDrawn())
  339.     {
  340.         //
  341.         // Want to get {Measure|Draw}Item messages?
  342.         // item draws itself, passing pointer to data doesn't work in OS/2
  343.         // Will eventually need to set the image handle somewhere into vItem.hItem
  344.         //
  345.         rItem.afStyle             |= MIS_OWNERDRAW;
  346.         pData                      = (BYTE*)NULL;
  347.         rItem.hItem                = (HBITMAP)pItem->GetBitmap().GetHBITMAP();
  348.         pItem->m_vMenuData.afStyle = rItem.afStyle;
  349.         pItem->m_vMenuData.hItem   = rItem.hItem;
  350.     }
  351.     else
  352. #endif
  353.     {
  354.         //
  355.         // Menu is just a normal string (passed in data parameter)
  356.         //
  357.         rItem.afStyle |= MIS_TEXT;
  358.         pData = (char*)pItem->GetText().c_str();
  359.     }
  360.  
  361.     if (nPos == (size_t)-1)
  362.     {
  363.         rItem.iPosition = MIT_END;
  364.     }
  365.     else
  366.     {
  367.         rItem.iPosition = nPos;
  368.     }
  369.  
  370.     APIRET                          rc;
  371.  
  372.     rc = (APIRET)::WinSendMsg( GetHmenu()
  373.                               ,MM_INSERTITEM
  374.                               ,(MPARAM)&rItem
  375.                               ,(MPARAM)pData
  376.                              );
  377. #if wxUSE_OWNER_DRAWN
  378.     if (pItem->IsOwnerDrawn())
  379.     {
  380.         BOOL                       rc;
  381.         MENUITEM                   vMenuItem;
  382.  
  383.         ::WinSendMsg( GetHmenu()
  384.                      ,MM_QUERYITEM
  385.                      ,MPFROM2SHORT( (USHORT)pItem->GetId()
  386.                                    ,(USHORT)(FALSE)
  387.                                   )
  388.                      ,&vMenuItem
  389.                     );
  390.     }
  391. #endif
  392.     if (rc == MIT_MEMERROR || rc == MIT_ERROR)
  393.     {
  394.         vError = ::WinGetLastError(vHabmain);
  395.         sError = wxPMErrorToStr(vError);
  396.         wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
  397.         wxLogLastError("Insert or AppendMenu");
  398.         return FALSE;
  399.     }
  400.     else
  401.     {
  402.         //
  403.         // If we're already attached to the menubar, we must update it
  404.         //
  405.         if (IsAttached() && m_menuBar->IsAttached())
  406.         {
  407.             m_menuBar->Refresh();
  408.         }
  409.         return TRUE;
  410.     }
  411.     return FALSE;
  412. } // end of wxMenu::DoInsertOrAppend
  413.  
  414. void wxMenu::EndRadioGroup()
  415. {
  416.     //
  417.     // We're not inside a radio group any longer
  418.     //
  419.     m_nStartRadioGroup = -1;
  420. } // end of wxMenu::EndRadioGroup
  421.  
  422. bool wxMenu::DoAppend(
  423.   wxMenuItem*                       pItem
  424. )
  425. {
  426.     wxCHECK_MSG( pItem, FALSE, _T("NULL item in wxMenu::DoAppend") );
  427.  
  428.     bool                            bCheck = FALSE;
  429.  
  430.     if (pItem->GetKind() == wxITEM_RADIO)
  431.     {
  432.         int                         nCount = GetMenuItemCount();
  433.  
  434.         if (m_nStartRadioGroup == -1)
  435.         {
  436.             //
  437.             // Start a new radio group
  438.             //
  439.             m_nStartRadioGroup = nCount;
  440.  
  441.             //
  442.             // For now it has just one element
  443.             //
  444.             pItem->SetAsRadioGroupStart();
  445.             pItem->SetRadioGroupEnd(m_nStartRadioGroup);
  446.  
  447.             //
  448.             // Ensure that we have a checked item in the radio group
  449.             //
  450.             bCheck = TRUE;
  451.         }
  452.         else // extend the current radio group
  453.         {
  454.             //
  455.             // We need to update its end item
  456.             //
  457.             pItem->SetRadioGroupStart(m_nStartRadioGroup);
  458.  
  459.             wxMenuItemList::Node*   pNode = GetMenuItems().Item(m_nStartRadioGroup);
  460.  
  461.             if (pNode)
  462.             {
  463.                 pNode->GetData()->SetRadioGroupEnd(nCount);
  464.             }
  465.             else
  466.             {
  467.                 wxFAIL_MSG( _T("where is the radio group start item?") );
  468.             }
  469.         }
  470.     }
  471.     else // not a radio item
  472.     {
  473.         EndRadioGroup();
  474.     }
  475.  
  476.     if (!wxMenuBase::DoAppend(pItem) || !DoInsertOrAppend(pItem))
  477.     {
  478.         return FALSE;
  479.     }
  480.     if (bCheck)
  481.     {
  482.         //
  483.         // Check the item initially
  484.         //
  485.         pItem->Check(TRUE);
  486.     }
  487.     return TRUE;
  488. } // end of wxMenu::DoAppend
  489.  
  490. bool wxMenu::DoInsert(
  491.   size_t                            nPos
  492. , wxMenuItem*                       pItem
  493. )
  494. {
  495.     return ( wxMenuBase::DoInsert( nPos
  496.                                   ,pItem) &&
  497.              DoInsertOrAppend( pItem
  498.                               ,nPos
  499.                              )
  500.            );
  501. } // end of wxMenu::DoInsert
  502.  
  503. wxMenuItem* wxMenu::DoRemove(
  504.   wxMenuItem*                       pItem
  505. )
  506. {
  507.     //
  508.     // We need to find the items position in the child list
  509.     //
  510.     size_t                          nPos;
  511.     wxMenuItemList::Node*           pNode = GetMenuItems().GetFirst();
  512.  
  513.     for (nPos = 0; pNode; nPos++)
  514.     {
  515.         if (pNode->GetData() == pItem)
  516.             break;
  517.         pNode = pNode->GetNext();
  518.     }
  519.  
  520.     //
  521.     // DoRemove() (unlike Remove) can only be called for existing item!
  522.     //
  523.     wxCHECK_MSG(pNode, NULL, wxT("bug in wxMenu::Remove logic"));
  524.  
  525. #if wxUSE_ACCEL
  526.     //
  527.     // Remove the corresponding accel from the accel table
  528.     //
  529.     int                             n = FindAccel(pItem->GetId());
  530.  
  531.     if (n != wxNOT_FOUND)
  532.     {
  533.         delete m_vAccels[n];
  534.         m_vAccels.RemoveAt(n);
  535.     }
  536.  
  537. #endif // wxUSE_ACCEL
  538.     //
  539.     // Remove the item from the menu
  540.     //
  541.     ::WinSendMsg( GetHmenu()
  542.                  ,MM_REMOVEITEM
  543.                  ,MPFROM2SHORT(pItem->GetId(), TRUE)
  544.                  ,(MPARAM)0
  545.                 );
  546.     if (IsAttached() && m_menuBar->IsAttached())
  547.     {
  548.         //
  549.         // Otherwise, the chane won't be visible
  550.         //
  551.         m_menuBar->Refresh();
  552.     }
  553.  
  554.     //
  555.     // And from internal data structures
  556.     //
  557.     return wxMenuBase::DoRemove(pItem);
  558. } // end of wxMenu::DoRemove
  559.  
  560. // ---------------------------------------------------------------------------
  561. // accelerator helpers
  562. // ---------------------------------------------------------------------------
  563.  
  564. #if wxUSE_ACCEL
  565.  
  566. //
  567. // Create the wxAcceleratorEntries for our accels and put them into provided
  568. // array - return the number of accels we have
  569. //
  570. size_t wxMenu::CopyAccels(
  571.   wxAcceleratorEntry*               pAccels
  572. ) const
  573. {
  574.     size_t                          nCount = GetAccelCount();
  575.  
  576.     for (size_t n = 0; n < nCount; n++)
  577.     {
  578.         *pAccels++ = *m_vAccels[n];
  579.     }
  580.     return nCount;
  581. } // end of wxMenu::CopyAccels
  582.  
  583. #endif // wxUSE_ACCEL
  584.  
  585. // ---------------------------------------------------------------------------
  586. // set wxMenu title
  587. // ---------------------------------------------------------------------------
  588.  
  589. void wxMenu::SetTitle(
  590.   const wxString&                   rLabel
  591. )
  592. {
  593.     bool                            bHasNoTitle = m_title.IsEmpty();
  594.     HWND                            hMenu = GetHmenu();
  595.  
  596.     m_title = rLabel;
  597.     if (bHasNoTitle)
  598.     {
  599.         if (!rLabel.IsEmpty())
  600.         {
  601.             if (!::WinSetWindowText(hMenu, rLabel.c_str()))
  602.             {
  603.                 wxLogLastError("SetMenuTitle");
  604.             }
  605.         }
  606.     }
  607.     else
  608.     {
  609.         if (rLabel.IsEmpty() )
  610.         {
  611.             ::WinSendMsg( GetHmenu()
  612.                          ,MM_REMOVEITEM
  613.                          ,MPFROM2SHORT(hMenu, TRUE)
  614.                          ,(MPARAM)0
  615.                         );
  616.         }
  617.         else
  618.         {
  619.             //
  620.             // Modify the title
  621.             //
  622.             if (!::WinSetWindowText(hMenu, rLabel.c_str()))
  623.             {
  624.                 wxLogLastError("SetMenuTitle");
  625.             }
  626.         }
  627.     }
  628. } // end of wxMenu::SetTitle
  629.  
  630. // ---------------------------------------------------------------------------
  631. // event processing
  632. // ---------------------------------------------------------------------------
  633.  
  634. bool wxMenu::OS2Command(
  635.   WXUINT                            WXUNUSED(uParam)
  636. , WXWORD                            vId
  637. )
  638. {
  639.     //
  640.     // Ignore commands from the menu title
  641.     //
  642.  
  643.     if (vId != (WXWORD)idMenuTitle)
  644.     {
  645.         SendEvent( vId
  646.                   ,(int)::WinSendMsg( GetHmenu()
  647.                                      ,MM_QUERYITEMATTR
  648.                                      ,(MPARAM)vId
  649.                                      ,(MPARAM)MIA_CHECKED
  650.                                     )
  651.                  );
  652.     }
  653.     return TRUE;
  654. } // end of wxMenu::OS2Command
  655.  
  656. // ---------------------------------------------------------------------------
  657. // other
  658. // ---------------------------------------------------------------------------
  659.  
  660. wxWindow* wxMenu::GetWindow() const
  661. {
  662.     if (m_invokingWindow != NULL)
  663.         return m_invokingWindow;
  664.     else if ( m_menuBar != NULL)
  665.         return m_menuBar->GetFrame();
  666.  
  667.     return NULL;
  668. } // end of wxMenu::GetWindow
  669.  
  670. // recursive search for item by id
  671. wxMenuItem* wxMenu::FindItem(
  672.   int                               nItemId
  673. , ULONG                             hItem
  674. , wxMenu**                          ppItemMenu
  675. ) const
  676. {
  677.     if ( ppItemMenu )
  678.         *ppItemMenu = NULL;
  679.  
  680.     wxMenuItem*                     pItem = NULL;
  681.  
  682.     for ( wxMenuItemList::Node *node = m_items.GetFirst();
  683.           node && !pItem;
  684.           node = node->GetNext() )
  685.     {
  686.         pItem = node->GetData();
  687.  
  688.         if ( pItem->GetId() == nItemId && pItem->m_vMenuData.hItem == hItem)
  689.         {
  690.             if ( ppItemMenu )
  691.                 *ppItemMenu = (wxMenu *)this;
  692.         }
  693.         else if ( pItem->IsSubMenu() )
  694.         {
  695.             pItem = pItem->GetSubMenu()->FindItem( nItemId
  696.                                                   ,hItem
  697.                                                   ,ppItemMenu
  698.                                                  );
  699.             if (pItem)
  700.                 break;
  701.         }
  702.         else
  703.         {
  704.             // don't exit the loop
  705.             pItem = NULL;
  706.         }
  707.     }
  708.     return pItem;
  709. } // end of wxMenu::FindItem
  710.  
  711. // ---------------------------------------------------------------------------
  712. // Menu Bar
  713. // ---------------------------------------------------------------------------
  714.  
  715. void wxMenuBar::Init()
  716. {
  717.     m_eventHandler = this;
  718.     m_menuBarFrame = NULL;
  719.     m_hMenu = 0;
  720. } // end of wxMenuBar::Init
  721.  
  722. wxMenuBar::wxMenuBar()
  723. {
  724.     Init();
  725. } // end of wxMenuBar::wxMenuBar
  726.  
  727. wxMenuBar::wxMenuBar(
  728.  long                               WXUNUSED(lStyle)
  729. )
  730. {
  731.     Init();
  732. } // end of wxMenuBar::wxMenuBar
  733.  
  734. wxMenuBar::wxMenuBar(
  735.   int                               nCount
  736. , wxMenu*                           vMenus[]
  737. , const wxString                    sTitles[]
  738. )
  739. {
  740.     Init();
  741.  
  742.     m_titles.Alloc(nCount);
  743.     for ( int i = 0; i < nCount; i++ )
  744.     {
  745.         m_menus.Append(vMenus[i]);
  746.         m_titles.Add(sTitles[i]);
  747.         vMenus[i]->Attach(this);
  748.     }
  749. } // end of wxMenuBar::wxMenuBar
  750.  
  751. wxMenuBar::~wxMenuBar()
  752. {
  753.     //
  754.     // We should free PM's resources only if PM doesn't do it for us
  755.     // which happens if we're attached to a frame
  756.     //
  757.     if (m_hMenu && !IsAttached())
  758.     {
  759.         ::WinDestroyWindow((HMENU)m_hMenu);
  760.         m_hMenu = (WXHMENU)NULL;
  761.     }
  762. } // end of wxMenuBar::~wxMenuBar
  763.  
  764. // ---------------------------------------------------------------------------
  765. // wxMenuBar helpers
  766. // ---------------------------------------------------------------------------
  767.  
  768. void wxMenuBar::Refresh()
  769. {
  770.     wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
  771.  
  772.     WinSendMsg(GetWinHwnd(m_menuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
  773. } // end of wxMenuBar::Refresh
  774.  
  775. WXHMENU wxMenuBar::Create()
  776. {
  777.     MENUITEM                        vItem;
  778.     HWND                            hFrame;
  779.  
  780.     if (m_hMenu != 0 )
  781.         return m_hMenu;
  782.  
  783.     wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
  784.  
  785.     //
  786.     // Menubars should be associated with a frame otherwise they are popups
  787.     //
  788.     if (m_menuBarFrame != NULL)
  789.         hFrame = GetWinHwnd(m_menuBarFrame);
  790.     else
  791.         hFrame = HWND_DESKTOP;
  792.     //
  793.     // Create an empty menu and then fill it with insertions
  794.     //
  795.     if ((m_hMenu =  ::WinCreateWindow( hFrame
  796.                                       ,WC_MENU
  797.                                       ,(PSZ)NULL
  798.                                       ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
  799.                                       ,0L
  800.                                       ,0L
  801.                                       ,0L
  802.                                       ,0L
  803.                                       ,hFrame
  804.                                       ,HWND_TOP
  805.                                       ,FID_MENU
  806.                                       ,NULL
  807.                                       ,NULL
  808.                                      )) == 0)
  809.     {
  810.         wxLogLastError("WinLoadMenu");
  811.     }
  812.     else
  813.     {
  814.         size_t                      nCount = GetMenuCount();
  815.  
  816.         for (size_t i = 0; i < nCount; i++)
  817.         {
  818.             APIRET                  rc;
  819.             ERRORID                 vError;
  820.             wxString                sError;
  821.             HWND                    hSubMenu;
  822.  
  823.             //
  824.             // Set the parent and owner of the submenues to be the menubar, not the desktop
  825.             //
  826.             hSubMenu = m_menus[i]->m_vMenuData.hwndSubMenu;
  827.             if (!::WinSetParent(m_menus[i]->m_vMenuData.hwndSubMenu, m_hMenu, FALSE))
  828.             {
  829.                 vError = ::WinGetLastError(vHabmain);
  830.                 sError = wxPMErrorToStr(vError);
  831.                 wxLogError("Error setting parent for submenu. Error: %s\n", sError);
  832.                 return NULLHANDLE;
  833.             }
  834.  
  835.             if (!::WinSetOwner(m_menus[i]->m_vMenuData.hwndSubMenu, m_hMenu))
  836.             {
  837.                 vError = ::WinGetLastError(vHabmain);
  838.                 sError = wxPMErrorToStr(vError);
  839.                 wxLogError("Error setting parent for submenu. Error: %s\n", sError);
  840.                 return NULLHANDLE;
  841.             }
  842.  
  843.             m_menus[i]->m_vMenuData.iPosition = i;
  844.  
  845.             rc = (APIRET)::WinSendMsg(m_hMenu, MM_INSERTITEM, (MPARAM)&m_menus[i]->m_vMenuData, (MPARAM)m_titles[i].c_str());
  846.             if (rc == MIT_MEMERROR || rc == MIT_ERROR)
  847.             {
  848.                 vError = ::WinGetLastError(vHabmain);
  849.                 sError = wxPMErrorToStr(vError);
  850.                 wxLogError("Error inserting or appending a menuitem. Error: %s\n", sError);
  851.                 return NULLHANDLE;
  852.             }
  853.         }
  854.     }
  855.     return m_hMenu;
  856. } // end of wxMenuBar::Create
  857.  
  858. // ---------------------------------------------------------------------------
  859. // wxMenuBar functions to work with the top level submenus
  860. // ---------------------------------------------------------------------------
  861.  
  862. //
  863. // NB: we don't support owner drawn top level items for now, if we do these
  864. //     functions would have to be changed to use wxMenuItem as well
  865. //
  866. void wxMenuBar::EnableTop(
  867.   size_t                            nPos
  868. , bool                              bEnable
  869. )
  870. {
  871.     wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
  872.     USHORT                          uFlag = 0;
  873.     SHORT                           nId;
  874.  
  875.     if(!bEnable)
  876.        uFlag = MIA_DISABLED;
  877.  
  878.     nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
  879.     if (nId == MIT_ERROR)
  880.     {
  881.         wxLogLastError("LogLastError");
  882.         return;
  883.     }
  884.     ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(MIA_DISABLED, uFlag));
  885.     Refresh();
  886. } // end of wxMenuBar::EnableTop
  887.  
  888. void wxMenuBar::SetLabelTop(
  889.   size_t                            nPos
  890. , const wxString&                   rLabel
  891. )
  892. {
  893.     SHORT                           nId;
  894.     MENUITEM                        vItem;
  895.  
  896.     wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
  897.     m_titles[nPos] = rLabel;
  898.  
  899.     if (!IsAttached())
  900.     {
  901.         return;
  902.     }
  903.  
  904.     nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
  905.     if (nId == MIT_ERROR)
  906.     {
  907.         wxLogLastError("LogLastError");
  908.         return;
  909.     }
  910.     if(!::WinSendMsg( (HWND)m_hMenu
  911.                      ,MM_QUERYITEM
  912.                      ,MPFROM2SHORT(nId, TRUE)
  913.                      ,MPARAM(&vItem)
  914.                     ))
  915.     {
  916.         wxLogLastError("QueryItem");
  917.     }
  918.     nId = vItem.id;
  919.  
  920.     if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.c_str()));
  921.     {
  922.         wxLogLastError("ModifyMenu");
  923.     }
  924.     Refresh();
  925. } // end of wxMenuBar::SetLabelTop
  926.  
  927. wxString wxMenuBar::GetLabelTop(
  928.   size_t                            nPos
  929. ) const
  930. {
  931.     wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
  932.                  wxT("invalid menu index in wxMenuBar::GetLabelTop") );
  933.     return m_titles[nPos];
  934. } // end of wxMenuBar::GetLabelTop
  935.  
  936. // ---------------------------------------------------------------------------
  937. // wxMenuBar construction
  938. // ---------------------------------------------------------------------------
  939.  
  940. wxMenu* wxMenuBar::Replace(
  941.   size_t                             nPos
  942. , wxMenu*                            pMenu
  943. , const wxString&                    rTitle
  944. )
  945. {
  946.     SHORT                            nId;
  947.     wxString                         sTitle = TextToLabel(rTitle);
  948.     wxMenu*                          pMenuOld = wxMenuBarBase::Replace( nPos
  949.                                                                        ,pMenu
  950.                                                                        ,sTitle
  951.                                                                       );
  952.  
  953.  
  954.     nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
  955.     if (nId == MIT_ERROR)
  956.     {
  957.         wxLogLastError("LogLastError");
  958.         return NULL;
  959.     }
  960.     if (!pMenuOld)
  961.         return NULL;
  962.     m_titles[nPos] = sTitle;
  963.     if (IsAttached())
  964.     {
  965.         ::WinSendMsg((HWND)m_hMenu, MM_REMOVEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
  966.         ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
  967.  
  968. #if wxUSE_ACCEL
  969.         if (pMenuOld->HasAccels() || pMenu->HasAccels())
  970.         {
  971.             //
  972.             // Need to rebuild accell table
  973.             //
  974.             RebuildAccelTable();
  975.         }
  976. #endif // wxUSE_ACCEL
  977.         Refresh();
  978.     }
  979.     return pMenuOld;
  980. } // end of wxMenuBar::Replace
  981.  
  982. bool wxMenuBar::Insert(
  983.   size_t                            nPos
  984. , wxMenu*                           pMenu
  985. , const wxString&                   rTitle
  986. )
  987. {
  988.     wxString                        sTitle = TextToLabel(rTitle);
  989.  
  990.     if (!wxMenuBarBase::Insert( nPos
  991.                                ,pMenu
  992.                                ,sTitle
  993.                               ))
  994.         return FALSE;
  995.  
  996.     m_titles.Insert( sTitle
  997.                     ,nPos
  998.                    );
  999.  
  1000.     if (IsAttached())
  1001.     {
  1002.         pMenu->m_vMenuData.iPosition = nPos;
  1003.         ::WinSendMsg( (HWND)m_hMenu
  1004.                      ,MM_INSERTITEM
  1005.                      ,(MPARAM)&pMenu->m_vMenuData
  1006.                      ,(MPARAM)sTitle.c_str()
  1007.                     );
  1008. #if wxUSE_ACCEL
  1009.         if (pMenu->HasAccels())
  1010.         {
  1011.             // need to rebuild accell table
  1012.             RebuildAccelTable();
  1013.         }
  1014. #endif // wxUSE_ACCEL
  1015.         Refresh();
  1016.     }
  1017.     return TRUE;
  1018. } // end of wxMenuBar::Insert
  1019.  
  1020. bool wxMenuBar::Append(
  1021.   wxMenu*                           pMenu
  1022. , const wxString&                   rsTitle
  1023. )
  1024. {
  1025.     WXHMENU                         hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
  1026.  
  1027.     wxCHECK_MSG(hSubmenu, FALSE, wxT("can't append invalid menu to menubar"));
  1028.  
  1029.     wxString                        sTitle = TextToLabel(rsTitle);
  1030.  
  1031.     if (!wxMenuBarBase::Append(pMenu, sTitle))
  1032.         return FALSE;
  1033.  
  1034.     m_titles.Add(sTitle);
  1035.  
  1036.     if ( IsAttached() )
  1037.     {
  1038.         pMenu->m_vMenuData.iPosition = MIT_END;
  1039.         ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.c_str());
  1040. #if wxUSE_ACCEL
  1041.         if (pMenu->HasAccels())
  1042.         {
  1043.             //
  1044.             // Need to rebuild accell table
  1045.             //
  1046.             RebuildAccelTable();
  1047.         }
  1048. #endif // wxUSE_ACCEL
  1049.         Refresh();
  1050.     }
  1051.     return TRUE;
  1052. } // end of wxMenuBar::Append
  1053.  
  1054. wxMenu* wxMenuBar::Remove(
  1055.   size_t                            nPos
  1056. )
  1057. {
  1058.     wxMenu*                         pMenu = wxMenuBarBase::Remove(nPos);
  1059.     SHORT                           nId;
  1060.  
  1061.     if (!pMenu)
  1062.         return NULL;
  1063.  
  1064.     nId = SHORT1FROMMR(::WinSendMsg( (HWND)GetHmenu()
  1065.                                     ,MM_ITEMIDFROMPOSITION
  1066.                                     ,MPFROMSHORT(nPos)
  1067.                                     ,(MPARAM)0)
  1068.                                    );
  1069.     if (nId == MIT_ERROR)
  1070.     {
  1071.         wxLogLastError("LogLastError");
  1072.         return NULL;
  1073.     }
  1074.     if (IsAttached())
  1075.     {
  1076.         ::WinSendMsg( (HWND)GetHmenu()
  1077.                      ,MM_REMOVEITEM
  1078.                      ,MPFROM2SHORT(nId, TRUE)
  1079.                      ,(MPARAM)0
  1080.                     );
  1081.  
  1082. #if wxUSE_ACCEL
  1083.         if (pMenu->HasAccels())
  1084.         {
  1085.             //
  1086.             // Need to rebuild accell table
  1087.             //
  1088.             RebuildAccelTable();
  1089.         }
  1090. #endif // wxUSE_ACCEL
  1091.         Refresh();
  1092.     }
  1093.     m_titles.Remove(nPos);
  1094.     return pMenu;
  1095. } // end of wxMenuBar::Remove
  1096.  
  1097. #if wxUSE_ACCEL
  1098.  
  1099. void wxMenuBar::RebuildAccelTable()
  1100. {
  1101.     //
  1102.     // Merge the accelerators of all menus into one accel table
  1103.     //
  1104.     size_t                          nAccelCount = 0;
  1105.     size_t                          i;
  1106.     size_t                          nCount = GetMenuCount();
  1107.  
  1108.     for (i = 0; i < nCount; i++)
  1109.     {
  1110.         nAccelCount += m_menus[i]->GetAccelCount();
  1111.     }
  1112.  
  1113.     if (nAccelCount)
  1114.     {
  1115.         wxAcceleratorEntry*         pAccelEntries = new wxAcceleratorEntry[nAccelCount];
  1116.  
  1117.         nAccelCount = 0;
  1118.         for (i = 0; i < nCount; i++)
  1119.         {
  1120.             nAccelCount += m_menus[i]->CopyAccels(&pAccelEntries[nAccelCount]);
  1121.         }
  1122.         m_vAccelTable = wxAcceleratorTable( nAccelCount
  1123.                                            ,pAccelEntries
  1124.                                           );
  1125.         delete [] pAccelEntries;
  1126.     }
  1127. } // end of wxMenuBar::RebuildAccelTable
  1128.  
  1129. #endif // wxUSE_ACCEL
  1130.  
  1131. void wxMenuBar::Attach(
  1132.   wxFrame*                          pFrame
  1133. )
  1134. {
  1135.     wxMenuBarBase::Attach(pFrame);
  1136.  
  1137. #if wxUSE_ACCEL
  1138.     RebuildAccelTable();
  1139.     //
  1140.     // Ensure the accelerator table is set to the frame (not the client!)
  1141.     //
  1142.     if (!::WinSetAccelTable( vHabmain
  1143.                             ,m_vAccelTable.GetHACCEL()
  1144.                             ,(HWND)pFrame->GetFrame()
  1145.                            ))
  1146.         wxLogLastError("WinSetAccelTable");
  1147. #endif // wxUSE_ACCEL
  1148. } // end of wxMenuBar::Attach
  1149.  
  1150. void wxMenuBar::Detach()
  1151. {
  1152.     ::WinDestroyWindow((HWND)m_hMenu);
  1153.     m_hMenu = (WXHMENU)NULL;
  1154.     m_menuBarFrame = NULL;
  1155. } // end of wxMenuBar::Detach
  1156.  
  1157. // ---------------------------------------------------------------------------
  1158. // wxMenuBar searching for menu items
  1159. // ---------------------------------------------------------------------------
  1160.  
  1161. //
  1162. // Find the itemString in menuString, and return the item id or wxNOT_FOUND
  1163. //
  1164. int wxMenuBar::FindMenuItem(
  1165.   const wxString&                   rMenuString
  1166. , const wxString&                   rItemString
  1167. ) const
  1168. {
  1169.     wxString                        sMenuLabel = wxStripMenuCodes(rMenuString);
  1170.     size_t                          nCount = GetMenuCount();
  1171.  
  1172.     for (size_t i = 0; i < nCount; i++)
  1173.     {
  1174.         wxString                    sTitle = wxStripMenuCodes(m_titles[i]);
  1175.  
  1176.         if (rMenuString == sTitle)
  1177.             return m_menus[i]->FindItem(rItemString);
  1178.     }
  1179.     return wxNOT_FOUND;
  1180. } // end of wxMenuBar::FindMenuItem
  1181.  
  1182. wxMenuItem* wxMenuBar::FindItem(
  1183.   int                               nId
  1184. , wxMenu**                          ppItemMenu
  1185. ) const
  1186. {
  1187.     if (ppItemMenu)
  1188.         *ppItemMenu = NULL;
  1189.  
  1190.     wxMenuItem*                     pItem = NULL;
  1191.     size_t                          nCount = GetMenuCount();
  1192.  
  1193.     for (size_t i = 0; !pItem && (i < nCount); i++)
  1194.     {
  1195.         pItem = m_menus[i]->FindItem( nId
  1196.                                      ,ppItemMenu
  1197.                                     );
  1198.     }
  1199.     return pItem;
  1200. } // end of wxMenuBar::FindItem
  1201.  
  1202. wxMenuItem* wxMenuBar::FindItem(
  1203.   int                               nId
  1204. , ULONG                             hItem
  1205. , wxMenu**                          ppItemMenu
  1206. ) const
  1207. {
  1208.     if (ppItemMenu)
  1209.         *ppItemMenu = NULL;
  1210.  
  1211.     wxMenuItem*                     pItem = NULL;
  1212.     size_t                          nCount = GetMenuCount();
  1213.  
  1214.     for (size_t i = 0; !pItem && (i < nCount); i++)
  1215.     {
  1216.         pItem = m_menus[i]->FindItem( nId
  1217.                                      ,hItem
  1218.                                      ,ppItemMenu
  1219.                                     );
  1220.     }
  1221.     return pItem;
  1222. } // end of wxMenuBar::FindItem
  1223.  
  1224.