1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/motif/menuitem.cpp 
   3 // Purpose:     wxMenuItem implementation 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  23 #include "wx/menuitem.h" 
  24 #include "wx/stockitem.h" 
  33 #pragma message disable nosimpint 
  36 #include <Xm/LabelG.h> 
  37 #include <Xm/CascadeBG.h> 
  38 #include <Xm/CascadeB.h> 
  39 #include <Xm/SeparatoG.h> 
  40 #include <Xm/PushBG.h> 
  41 #include <Xm/ToggleB.h> 
  42 #include <Xm/ToggleBG.h> 
  43 #include <Xm/RowColumn.h> 
  45 #pragma message enable nosimpint 
  48 #include "wx/motif/private.h" 
  50 // ---------------------------------------------------------------------------- 
  51 // functions prototypes 
  52 // ---------------------------------------------------------------------------- 
  54 static void wxMenuItemCallback(Widget w
, XtPointer clientData
, XtPointer ptr
); 
  55 static void wxMenuItemArmCallback(Widget w
, XtPointer clientData
, XtPointer ptr
); 
  56 static void wxMenuItemDisarmCallback(Widget w
, XtPointer clientData
, XtPointer ptr
); 
  58 // ============================================================================ 
  60 // ============================================================================ 
  62 // ---------------------------------------------------------------------------- 
  63 // dynamic classes implementation 
  64 // ---------------------------------------------------------------------------- 
  66 IMPLEMENT_DYNAMIC_CLASS(wxMenuItem
, wxObject
) 
  68 // ---------------------------------------------------------------------------- 
  70 // ---------------------------------------------------------------------------- 
  75 wxMenuItem::wxMenuItem(wxMenu 
*pParentMenu
, 
  77                        const wxString
& strName
, 
  78                        const wxString
& strHelp
, 
  81           : wxMenuItemBase(pParentMenu
, id
, strName
, strHelp
, kind
, pSubMenu
) 
  85     m_buttonWidget 
= (WXWidget
) NULL
; 
  89 wxMenuItem::~wxMenuItem() 
  96 void wxMenuItem::Enable(bool bDoEnable
) 
  98     if ( m_isEnabled 
!= bDoEnable 
) 
 104                 XtSetSensitive( (Widget
) m_buttonWidget
, (Boolean
) bDoEnable
); 
 108             // Maybe we should apply this to all items in the submenu? 
 109             // Or perhaps it works anyway. 
 111                 XtSetSensitive( (Widget
) m_buttonWidget
, (Boolean
) bDoEnable
); 
 114         wxMenuItemBase::Enable(bDoEnable
); 
 118 void wxMenuItem::Check(bool bDoCheck
) 
 120     wxCHECK_RET( IsCheckable(), "only checkable items may be checked" ); 
 122     if ( m_isChecked 
!= bDoCheck 
) 
 124         if ( m_buttonWidget 
) 
 126             wxASSERT_MSG( XtIsSubclass((Widget
)m_buttonWidget
, 
 127                                        xmToggleButtonGadgetClass
), 
 128                           wxT("checkable menu item must be a toggle button") ); 
 130             XtVaSetValues((Widget
)m_buttonWidget
, 
 131                           XmNset
, (Boolean
)bDoCheck
, 
 135         wxMenuItemBase::Check(bDoCheck
); 
 140 wxString 
wxMenuItemBase::GetLabelText(const wxString
& text
) 
 142     return wxStripMenuCodes(text
); 
 145 // ---------------------------------------------------------------------------- 
 147 // ---------------------------------------------------------------------------- 
 149 wxMenuItem 
*wxMenuItemBase::New(wxMenu 
*parentMenu
, 
 151                                 const wxString
& name
, 
 152                                 const wxString
& help
, 
 156     return new wxMenuItem(parentMenu
, id
, name
, help
, kind
, subMenu
); 
 159 // ---------------------------------------------------------------------------- 
 161 // ---------------------------------------------------------------------------- 
 163 void wxMenuItem::CreateItem (WXWidget menu
, wxMenuBar 
* menuBar
, 
 164                              wxMenu 
* topMenu
, size_t index
) 
 171         // Id=-3 identifies a Title item. 
 172         m_buttonWidget 
= (WXWidget
) XtVaCreateManagedWidget
 
 173             (wxStripMenuCodes(m_text
), 
 174             xmLabelGadgetClass
, (Widget
) menu
, NULL
); 
 176     else if (!IsSeparator() && !m_subMenu
) 
 178         wxString txt 
= m_text
; 
 180         if (m_text
.IsEmpty()) 
 182             wxASSERT_MSG(wxIsStockID(GetId()), wxT("A non-stock menu item with an empty label?")); 
 183             txt 
= wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR
|wxSTOCK_WITH_MNEMONIC
); 
 186         wxString strName 
= wxStripMenuCodes(txt
); 
 189             m_buttonWidget 
= (WXWidget
) XtVaCreateManagedWidget (strName
, 
 190                 xmToggleButtonGadgetClass
, (Widget
) menu
, 
 191 #ifdef XmNpositionIndex 
 192                 XmNpositionIndex
, index
, 
 195             XtVaSetValues ((Widget
) m_buttonWidget
, XmNset
, (Boolean
) IsChecked(), NULL
); 
 198             m_buttonWidget 
= (WXWidget
) XtVaCreateManagedWidget (strName
, 
 199             xmPushButtonGadgetClass
, (Widget
) menu
, 
 200 #ifdef XmNpositionIndex 
 201             XmNpositionIndex
, index
, 
 204         char mnem 
= wxFindMnemonic (m_text
); 
 206             XtVaSetValues ((Widget
) m_buttonWidget
, XmNmnemonic
, mnem
, NULL
); 
 208         //// TODO: proper accelerator treatment. What does wxFindAccelerator 
 211         char *accel 
= wxFindAccelerator (strName
); 
 213             XtVaSetValues ((Widget
) m_buttonWidget
, XmNaccelerator
, accel
, NULL
); 
 215         // TODO: What does this do? 
 216         XmString accel_str 
= wxFindAcceleratorText (strName
); 
 219             XtVaSetValues ((Widget
) m_buttonWidget
, XmNacceleratorText
, accel_str
, NULL
); 
 220             XmStringFree (accel_str
); 
 224             XtAddCallback ((Widget
) m_buttonWidget
, 
 225             XmNvalueChangedCallback
, 
 226             (XtCallbackProc
) wxMenuItemCallback
, 
 229             XtAddCallback ((Widget
) m_buttonWidget
, 
 231             (XtCallbackProc
) wxMenuItemCallback
, 
 233         XtAddCallback ((Widget
) m_buttonWidget
, 
 235             (XtCallbackProc
) wxMenuItemArmCallback
, 
 237         XtAddCallback ((Widget
) m_buttonWidget
, 
 239             (XtCallbackProc
) wxMenuItemDisarmCallback
, 
 242     else if (IsSeparator()) 
 244         m_buttonWidget 
= (WXWidget
) XtVaCreateManagedWidget ("separator", 
 245             xmSeparatorGadgetClass
, (Widget
) menu
, 
 246 #ifndef XmNpositionIndex 
 247             XmNpositionIndex
, index
, 
 253         m_buttonWidget 
= m_subMenu
->CreateMenu (menuBar
, menu
, topMenu
, index
, m_text
, true); 
 254         m_subMenu
->SetButtonWidget(m_buttonWidget
); 
 255         XtAddCallback ((Widget
) m_buttonWidget
, 
 256             XmNcascadingCallback
, 
 257             (XtCallbackProc
) wxMenuItemArmCallback
, 
 261         XtSetSensitive ((Widget
) m_buttonWidget
, (Boolean
) IsEnabled()); 
 264 void wxMenuItem::DestroyItem(bool full
) 
 271     else if (!m_text
.empty() && !m_subMenu
) 
 276                 XtRemoveCallback ((Widget
) m_buttonWidget
, XmNvalueChangedCallback
, 
 277                 wxMenuItemCallback
, (XtPointer
) this); 
 279                 XtRemoveCallback ((Widget
) m_buttonWidget
, XmNactivateCallback
, 
 280                 wxMenuItemCallback
, (XtPointer
) this); 
 281             XtRemoveCallback ((Widget
) m_buttonWidget
, XmNarmCallback
, 
 282                 wxMenuItemArmCallback
, (XtPointer
) this); 
 283             XtRemoveCallback ((Widget
) m_buttonWidget
, XmNdisarmCallback
, 
 284                 wxMenuItemDisarmCallback
, (XtPointer
) this); 
 287     else if (GetId() == wxID_SEPARATOR
) 
 292     else if (GetSubMenu()) 
 296             XtRemoveCallback ((Widget
) m_buttonWidget
, XmNcascadingCallback
, 
 297                 wxMenuItemArmCallback
, (XtPointer
) this); 
 299         m_subMenu
->DestroyMenu(full
); 
 301             m_buttonWidget 
= NULL
; 
 304     if (m_buttonWidget 
&& full
) 
 306         XtDestroyWidget ((Widget
) m_buttonWidget
); 
 307         m_buttonWidget 
= (WXWidget
) 0; 
 311 void wxMenuItem::SetItemLabel(const wxString
& label
) 
 313     char mnem 
= wxFindMnemonic (label
); 
 314     wxString label2 
= wxStripMenuCodes(label
); 
 320         wxXmString 
label_str(label2
); 
 321         XtVaSetValues ((Widget
) m_buttonWidget
, 
 322             XmNlabelString
, label_str(), 
 325             XtVaSetValues ((Widget
) m_buttonWidget
, XmNmnemonic
, mnem
, NULL
); 
 326         char *accel 
= wxFindAccelerator (label2
); 
 328             XtVaSetValues ((Widget
) m_buttonWidget
, XmNaccelerator
, accel
, NULL
); 
 330         XmString accel_str 
= wxFindAcceleratorText (label2
); 
 333             XtVaSetValues ((Widget
) m_buttonWidget
, XmNacceleratorText
, accel_str
, NULL
); 
 334             XmStringFree (accel_str
); 
 339 // ---------------------------------------------------------------------------- 
 341 // ---------------------------------------------------------------------------- 
 343 void wxMenuItemCallback (Widget 
WXUNUSED(w
), XtPointer clientData
, 
 344                          XtPointer 
WXUNUSED(ptr
)) 
 346     wxMenuItem 
*item 
= (wxMenuItem 
*) clientData
; 
 349         wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED
, item
->GetId()); 
 350         event
.SetInt( item
->GetId() ); 
 352         if (item
->IsCheckable()) 
 354             Boolean isChecked 
= false; 
 355             XtVaGetValues ((Widget
) item
->GetButtonWidget(), 
 359             // only set the flag, don't actually check anything 
 360             item
->wxMenuItemBase::Check(isChecked
); 
 361             event
.SetInt(isChecked
); 
 364         if (item
->GetMenuBar() && item
->GetMenuBar()->GetMenuBarFrame()) 
 366             event
.SetEventObject(item
->GetMenuBar()->GetMenuBarFrame()); 
 368             item
->GetMenuBar()->GetMenuBarFrame() 
 369                 ->HandleWindowEvent(event
); 
 371         // this is the child of a popup menu 
 372         else if (item
->GetTopMenu()) 
 374             event
.SetEventObject(item
->GetTopMenu()); 
 376             item
->GetTopMenu()->ProcessCommand (event
); 
 378             // Since PopupMenu under Motif still grab right mouse 
 379             // button events after it was closed, we need to delete 
 380             // the associated widgets to allow next PopUpMenu to 
 381             // appear; this needs to be done there because doing it in 
 382             // a WorkProc as before may cause crashes if a menu item causes 
 383             // the parent window of the menu to be destroyed 
 384             item
->GetTopMenu()->DestroyWidgetAndDetach(); 
 389 void wxMenuItemArmCallback (Widget 
WXUNUSED(w
), XtPointer clientData
, 
 390                        XtPointer 
WXUNUSED(ptr
)) 
 392     wxMenuItem 
*item 
= (wxMenuItem 
*) clientData
; 
 395         if (item
->GetMenuBar() && item
->GetMenuBar()->GetMenuBarFrame()) 
 397             wxMenuEvent 
menuEvent(wxEVT_MENU_HIGHLIGHT
, item
->GetId()); 
 398             menuEvent
.SetEventObject(item
->GetMenuBar()->GetMenuBarFrame()); 
 400             item
->GetMenuBar()->GetMenuBarFrame() 
 401                 ->HandleWindowEvent(menuEvent
); 
 407 wxMenuItemDisarmCallback (Widget 
WXUNUSED(w
), XtPointer clientData
, 
 408                           XtPointer 
WXUNUSED(ptr
)) 
 410     wxMenuItem 
*item 
= (wxMenuItem 
*) clientData
; 
 413         if (item
->GetMenuBar() && item
->GetMenuBar()->GetMenuBarFrame()) 
 415             // TODO: not sure this is correct, since -1 means something 
 416             // special to event system 
 417             wxMenuEvent 
menuEvent(wxEVT_MENU_HIGHLIGHT
, -1); 
 418             menuEvent
.SetEventObject(item
->GetMenuBar()->GetMenuBarFrame()); 
 420             item
->GetMenuBar()->GetMenuBarFrame() 
 421                 ->HandleWindowEvent(menuEvent
);