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

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name:        menuitem.cpp
  3. // Purpose:     wxMenuItem implementation
  4. // Author:      David Webster
  5. // Modified by:
  6. // Created:     10/10/98
  7. // RCS-ID:      $Id: MENUITEM.CPP,v 1.25.2.1 2002/12/16 18:34:26 DW Exp $
  8. // Copyright:   (c) David Webster
  9. // Licence:     wxWindows licence
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // headers & declarations
  14. // ============================================================================
  15.  
  16. #ifdef __GNUG__
  17.     #pragma implementation "menuitem.h"
  18. #endif
  19.  
  20. // For compilers that support precompilation, includes "wx.h".
  21. #include "wx/wxprec.h"
  22.  
  23. #ifndef WX_PRECOMP
  24.     #include "wx/font.h"
  25.     #include "wx/bitmap.h"
  26.     #include "wx/settings.h"
  27.     #include "wx/font.h"
  28.     #include "wx/window.h"
  29.     #include "wx/accel.h"
  30.     #include "wx/menu.h"
  31.     #include "wx/string.h"
  32. #endif
  33.  
  34. #include "wx/menuitem.h"
  35. #include "wx/log.h"
  36.  
  37. #if wxUSE_ACCEL
  38.     #include "wx/accel.h"
  39. #endif // wxUSE_ACCEL
  40.  
  41. #include "wx/os2/private.h"
  42.  
  43. // ---------------------------------------------------------------------------
  44. // macro
  45. // ---------------------------------------------------------------------------
  46.  
  47. // hide the ugly cast
  48. #define GetHMenuOf(menu)    ((HMENU)menu->GetHMenu())
  49.  
  50. // conditional compilation
  51. #if wxUSE_OWNER_DRAWN
  52.     #define OWNER_DRAWN_ONLY( code ) if ( IsOwnerDrawn() ) code
  53. #else // !wxUSE_OWNER_DRAWN
  54.     #define OWNER_DRAWN_ONLY( code )
  55. #endif // wxUSE_OWNER_DRAWN/!wxUSE_OWNER_DRAWN
  56.  
  57. // ----------------------------------------------------------------------------
  58. // static function for translating menu labels
  59. // ----------------------------------------------------------------------------
  60.  
  61. static wxString TextToLabel(
  62.   const wxString&                   rsTitle
  63. )
  64. {
  65.     wxString                        sTitle;
  66.     const wxChar*                   zPc;
  67.  
  68.     if (rsTitle.IsEmpty())
  69.         return(sTitle);
  70.  
  71.     for (zPc = rsTitle.c_str(); *zPc != wxT('\0'); zPc++)
  72.     {
  73.         if (*zPc == wxT('&'))
  74.         {
  75.             if (*(zPc + 1) == wxT('&'))
  76.             {
  77.                 zPc++;
  78.                 sTitle << wxT('&');
  79.             }
  80.             else
  81.                 sTitle << wxT('~');
  82.         }
  83.         else
  84.         {
  85.             if ( *zPc == wxT('~'))
  86.             {
  87.                 //
  88.                 // Tildes must be doubled to prevent them from being
  89.                 // interpreted as accelerator character prefix by PM ???
  90.                 //
  91.                 sTitle << *zPc;
  92.             }
  93.             sTitle << *zPc;
  94.         }
  95.     }
  96.     return(sTitle);
  97. } // end of TextToLabel
  98.  
  99. // ============================================================================
  100. // implementation
  101. // ============================================================================
  102.  
  103. // ----------------------------------------------------------------------------
  104. // dynamic classes implementation
  105. // ----------------------------------------------------------------------------
  106.  
  107. IMPLEMENT_DYNAMIC_CLASS(wxMenuItem, wxObject)
  108.  
  109. // ----------------------------------------------------------------------------
  110. // wxMenuItem
  111. // ----------------------------------------------------------------------------
  112.  
  113. // ctor & dtor
  114. // -----------
  115.  
  116. wxMenuItem::wxMenuItem(
  117.   wxMenu*                           pParentMenu
  118. , int                               nId
  119. , const wxString&                   rsText
  120. , const wxString&                   rsHelp
  121. , wxItemKind                        eKind
  122. , wxMenu*                           pSubMenu
  123. )
  124. : wxMenuItemBase( pParentMenu
  125.                  ,nId
  126.                  ,TextToLabel(rsText)
  127.                  ,rsHelp
  128.                  ,eKind
  129.                  ,pSubMenu
  130.                 )
  131. #if wxUSE_OWNER_DRAWN
  132. ,  wxOwnerDrawn( TextToLabel(rsText)
  133.                 ,eKind == wxITEM_CHECK
  134.                )
  135. #endif // owner drawn
  136. {
  137.     wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
  138.     memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
  139.     m_vMenuData.id = (USHORT)nId;
  140.  
  141.     Init();
  142. } // end of wxMenuItem::wxMenuItem
  143.  
  144. wxMenuItem::wxMenuItem(
  145.   wxMenu*                           pParentMenu
  146. , int                               nId
  147. , const wxString&                   rsText
  148. , const wxString&                   rsHelp
  149. , bool                              bIsCheckable
  150. , wxMenu*                           pSubMenu
  151. )
  152. : wxMenuItemBase( pParentMenu
  153.                  ,nId
  154.                  ,TextToLabel(rsText)
  155.                  ,rsHelp
  156.                  ,bIsCheckable ? wxITEM_CHECK : wxITEM_NORMAL
  157.                  ,pSubMenu
  158.                 )
  159. #if wxUSE_OWNER_DRAWN
  160. ,  wxOwnerDrawn( TextToLabel(rsText)
  161.                 ,bIsCheckable
  162.                )
  163. #endif // owner drawn
  164. {
  165.     wxASSERT_MSG(pParentMenu != NULL, wxT("a menu item should have a parent"));
  166.     memset(&m_vMenuData, '\0', sizeof(m_vMenuData));
  167.     m_vMenuData.id = (USHORT)nId;
  168.  
  169.     Init();
  170. } // end of wxMenuItem::wxMenuItem
  171.  
  172. void wxMenuItem::Init()
  173. {
  174.     m_vRadioGroup.m_nStart = -1;
  175.     m_bIsRadioGroupStart = FALSE;
  176.  
  177. #if  wxUSE_OWNER_DRAWN
  178.     //
  179.     // Set default menu colors
  180.     //
  181.     #define SYS_COLOR(c) (wxSystemSettings::GetColour(wxSYS_COLOUR_##c))
  182.  
  183.     SetTextColour(SYS_COLOR(MENUTEXT));
  184.     SetBackgroundColour(SYS_COLOR(MENU));
  185.  
  186.     //
  187.     // We don't want normal items be owner-drawn
  188.     //
  189.     ResetOwnerDrawn();
  190.     #undef  SYS_COLOR
  191.  
  192.     //
  193.     // Tell the owner drawing code to to show the accel string as well
  194.     //
  195.     SetAccelString(m_text.AfterFirst(_T('\t')));
  196. #endif // wxUSE_OWNER_DRAWN
  197. } // end of wxMenuItem::Init
  198.  
  199. wxMenuItem::~wxMenuItem()
  200. {
  201. } // end of wxMenuItem::~wxMenuItem
  202.  
  203. //
  204. // Misc
  205. // ----
  206.  
  207. //
  208. // Return the id for calling Win32 API functions
  209. //
  210. int wxMenuItem::GetRealId() const
  211. {
  212.     return m_subMenu ? (int)m_subMenu->GetHMenu() : GetId();
  213. } // end of wxMenuItem::GetRealId
  214.  
  215. //
  216. // Get item state
  217. // --------------
  218. bool wxMenuItem::IsChecked() const
  219. {
  220.     USHORT                          uFlag = SHORT1FROMMR(::WinSendMsg( GetHMenuOf(m_parentMenu)
  221.                                                                       ,MM_QUERYITEMATTR
  222.                                                                       ,MPFROM2SHORT(GetId(), TRUE)
  223.                                                                       ,MPFROMSHORT(MIA_CHECKED)
  224.                                                                      ));
  225.  
  226.     return (uFlag & MIA_CHECKED);
  227. } // end of wxMenuItem::IsChecked
  228.  
  229. wxString wxMenuItemBase::GetLabelFromText(
  230.   const wxString&                   rsText
  231. )
  232. {
  233.     wxString                        sLabel;
  234.  
  235.     for (const char* zPc = rsText.c_str(); *zPc; zPc++)
  236.     {
  237.         if (*zPc == wxT('~') || *zPc == wxT('&'))
  238.         {
  239.             //
  240.             // '~' is the escape character for OS/2PM and '&' is the one for
  241.             // wxWindows - skip both of them
  242.             //
  243.             continue;
  244.         }
  245.         sLabel += *zPc;
  246.     }
  247.     return sLabel;
  248. } // end of wxMenuItemBase::GetLabelFromText
  249.  
  250. //
  251. // Radio group stuff
  252. // -----------------
  253. //
  254. void wxMenuItem::SetAsRadioGroupStart()
  255. {
  256.     m_bIsRadioGroupStart = TRUE;
  257. } // end of wxMenuItem::SetAsRadioGroupStart
  258.  
  259. void wxMenuItem::SetRadioGroupStart(
  260.   int                               nStart
  261. )
  262. {
  263.     wxASSERT_MSG( !m_bIsRadioGroupStart
  264.                  ,_T("should only be called for the next radio items")
  265.                 );
  266.  
  267.     m_vRadioGroup.m_nStart = nStart;
  268. } // wxMenuItem::SetRadioGroupStart
  269.  
  270. void wxMenuItem::SetRadioGroupEnd(
  271.   int                               nEnd
  272. )
  273. {
  274.     wxASSERT_MSG( m_bIsRadioGroupStart
  275.                  ,_T("should only be called for the first radio item")
  276.                 );
  277.     m_vRadioGroup.m_nEnd = nEnd;
  278. } // end of wxMenuItem::SetRadioGroupEnd
  279.  
  280. // change item state
  281. // -----------------
  282.  
  283. void wxMenuItem::Enable(
  284.   bool                              bEnable
  285. )
  286. {
  287.     bool                            bOk;
  288.  
  289.     if (m_isEnabled == bEnable)
  290.         return;
  291.     if (bEnable)
  292.         bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
  293.                                  ,MM_SETITEMATTR
  294.                                  ,MPFROM2SHORT(GetRealId(), TRUE)
  295.                                  ,MPFROM2SHORT(MIA_DISABLED, FALSE)
  296.                                 );
  297.     else
  298.         bOk = (bool)::WinSendMsg( GetHMenuOf(m_parentMenu)
  299.                                  ,MM_SETITEMATTR
  300.                                  ,MPFROM2SHORT(GetRealId(), TRUE)
  301.                                  ,MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)
  302.                                 );
  303.     if (!bOk)
  304.     {
  305.         wxLogLastError("EnableMenuItem");
  306.     }
  307.     wxMenuItemBase::Enable(bEnable);
  308. } // end of wxMenuItem::Enable
  309.  
  310. void wxMenuItem::Check(
  311.   bool                              bCheck
  312. )
  313. {
  314.     bool                            bOk;
  315.  
  316.     wxCHECK_RET( IsCheckable(), wxT("only checkable items may be checked") );
  317.     if (m_isChecked == bCheck)
  318.         return;
  319.  
  320.     HMENU                           hMenu = GetHmenuOf(m_parentMenu);
  321.  
  322.     if (GetKind() == wxITEM_RADIO)
  323.     {
  324.         //
  325.         // It doesn't make sense to uncheck a radio item - what would this do?
  326.         //
  327.         if (!bCheck)
  328.             return;
  329.  
  330.         //
  331.         // Get the index of this item in the menu
  332.         //
  333.         const wxMenuItemList&       rItems = m_parentMenu->GetMenuItems();
  334.         int                         nPos = rItems.IndexOf(this);
  335.  
  336.         wxCHECK_RET( nPos != wxNOT_FOUND
  337.                     ,_T("menuitem not found in the menu items list?")
  338.                    );
  339.  
  340.         //
  341.         // Get the radio group range
  342.         //
  343.         int                         nStart;
  344.         int                         nEnd;
  345.  
  346.         if (m_bIsRadioGroupStart)
  347.         {
  348.             //
  349.             // We already have all information we need
  350.             //
  351.             nStart = nPos;
  352.             nEnd   = m_vRadioGroup.m_nEnd;
  353.         }
  354.         else // next radio group item
  355.         {
  356.             //
  357.             // Get the radio group end from the start item
  358.             //
  359.             nStart = m_vRadioGroup.m_nStart;
  360.             nEnd = rItems.Item(nStart)->GetData()->m_vRadioGroup.m_nEnd;
  361.         }
  362.  
  363.         //
  364.         // Also uncheck all the other items in this radio group
  365.         //
  366.         wxMenuItemList::Node*       pNode = rItems.Item(nStart);
  367.  
  368.         for (int n = nStart; n <= nEnd && pNode; n++)
  369.         {
  370.             if (n == nPos)
  371.             {
  372.                 ::WinSendMsg( hMenu
  373.                              ,MM_SETITEMATTR
  374.                              ,MPFROM2SHORT(n, TRUE)
  375.                              ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
  376.                             );
  377.             }
  378.             if (n != nPos)
  379.             {
  380.                 pNode->GetData()->m_isChecked = FALSE;
  381.                 ::WinSendMsg( hMenu
  382.                              ,MM_SETITEMATTR
  383.                              ,MPFROM2SHORT(n, TRUE)
  384.                              ,MPFROM2SHORT(MIA_CHECKED, FALSE)
  385.                             );
  386.             }
  387.             pNode = pNode->GetNext();
  388.         }
  389.     }
  390.     else // check item
  391.     {
  392.         if (bCheck)
  393.             bOk = (bool)::WinSendMsg( hMenu
  394.                                      ,MM_SETITEMATTR
  395.                                      ,MPFROM2SHORT(GetRealId(), TRUE)
  396.                                      ,MPFROM2SHORT(MIA_CHECKED, MIA_CHECKED)
  397.                                     );
  398.         else
  399.             bOk = (bool)::WinSendMsg( hMenu
  400.                                      ,MM_SETITEMATTR
  401.                                      ,MPFROM2SHORT(GetRealId(), TRUE)
  402.                                      ,MPFROM2SHORT(MIA_CHECKED, FALSE)
  403.                                     );
  404.     }
  405.     if (!bOk)
  406.     {
  407.         wxLogLastError("CheckMenuItem");
  408.     }
  409.     wxMenuItemBase::Check(bCheck);
  410. } // end of wxMenuItem::Check
  411.  
  412. void wxMenuItem::SetText(
  413.   const wxString&                   rText
  414. )
  415. {
  416.     //
  417.     // Don't do anything if label didn't change
  418.     //
  419.  
  420.     wxString                        sText = TextToLabel(rText);
  421.     if (m_text == sText)
  422.         return;
  423.  
  424.     wxMenuItemBase::SetText(sText);
  425.     OWNER_DRAWN_ONLY(wxOwnerDrawn::SetName(sText));
  426. #if  wxUSE_OWNER_DRAWN
  427.     SetAccelString(rText.AfterFirst(_T('\t')));
  428. #endif // wxUSE_OWNER_DRAWN
  429.  
  430.     HWND                            hMenu = GetHmenuOf(m_parentMenu);
  431.  
  432.     wxCHECK_RET(hMenu, wxT("menuitem without menu"));
  433.  
  434. #if wxUSE_ACCEL
  435.     m_parentMenu->UpdateAccel(this);
  436. #endif // wxUSE_ACCEL
  437.  
  438.     USHORT                          uId = GetRealId();
  439.     MENUITEM                        vItem;
  440.     USHORT                          uFlagsOld;
  441.  
  442.     if (!::WinSendMsg( hMenu
  443.                       ,MM_QUERYITEM
  444.                       ,MPFROM2SHORT(uId, TRUE)
  445.                       ,(MPARAM)&vItem
  446.                      ))
  447.     {
  448.         wxLogLastError("GetMenuState");
  449.     }
  450.     else
  451.     {
  452.         uFlagsOld = vItem.afStyle;
  453.         if (IsSubMenu())
  454.         {
  455.             uFlagsOld |= MIS_SUBMENU;
  456.         }
  457.  
  458.         BYTE*                       pData;
  459.  
  460. #if wxUSE_OWNER_DRAWN
  461.         if (IsOwnerDrawn())
  462.         {
  463.             uFlagsOld |= MIS_OWNERDRAW;
  464.             pData = (BYTE*)this;
  465.         }
  466.         else
  467. #endif  //owner drawn
  468.         {
  469.             uFlagsOld |= MIS_TEXT;
  470.             pData = (BYTE*)sText.c_str();
  471.         }
  472.  
  473.         //
  474.         // Set the style
  475.         //
  476.         if (!::WinSendMsg( hMenu
  477.                           ,MM_SETITEM
  478.                           ,MPFROM2SHORT(uId, TRUE)
  479.                           ,(MPARAM)&vItem
  480.                          ))
  481.         {
  482.             wxLogLastError(wxT("ModifyMenu"));
  483.         }
  484.  
  485.         //
  486.         // Set the text
  487.         //
  488.         if (::WinSendMsg( hMenu
  489.                          ,MM_SETITEMTEXT
  490.                          ,MPFROMSHORT(uId)
  491.                          ,(MPARAM)pData
  492.                         ))
  493.         {
  494.             wxLogLastError(wxT("ModifyMenu"));
  495.         }
  496.     }
  497. } // end of wxMenuItem::SetText
  498.  
  499. void wxMenuItem::SetCheckable(
  500.   bool                              bCheckable
  501. )
  502. {
  503.     wxMenuItemBase::SetCheckable(bCheckable);
  504.     OWNER_DRAWN_ONLY(wxOwnerDrawn::SetCheckable(bCheckable));
  505. } // end of wxMenuItem::SetCheckable
  506.  
  507. // ----------------------------------------------------------------------------
  508. // wxMenuItemBase
  509. // ----------------------------------------------------------------------------
  510.  
  511. wxMenuItem* wxMenuItemBase::New(
  512.   wxMenu*                           pParentMenu
  513. , int                               nId
  514. , const wxString&                   rName
  515. , const wxString&                   rHelp
  516. , wxItemKind                        kind
  517. , wxMenu*                           pSubMenu
  518. )
  519. {
  520.     return new wxMenuItem( pParentMenu
  521.                           ,nId
  522.                           ,rName
  523.                           ,rHelp
  524.                           ,kind
  525.                           ,pSubMenu
  526.                          );
  527. } // end of wxMenuItemBase::New
  528.  
  529.