1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxMenu, wxMenuBar, wxMenuItem 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 // ============================================================================ 
  15 // ============================================================================ 
  17 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  18     #pragma implementation "menu.h" 
  21 // ---------------------------------------------------------------------------- 
  23 // ---------------------------------------------------------------------------- 
  28 #include "wx/menuitem.h" 
  33 #include "wx/settings.h" 
  36 #pragma message disable nosimpint 
  37 #define XtDisplay XTDISPLAY 
  38 #define XtWindow XTWINDOW 
  41 #include <Xm/LabelG.h> 
  42 #include <Xm/CascadeBG.h> 
  43 #include <Xm/CascadeB.h> 
  44 #include <Xm/SeparatoG.h> 
  45 #include <Xm/PushBG.h> 
  46 #include <Xm/ToggleB.h> 
  47 #include <Xm/ToggleBG.h> 
  48 #include <Xm/RowColumn.h> 
  50 #pragma message enable nosimpint 
  53 #include "wx/motif/private.h" 
  55 // other standard headers 
  58 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
) 
  59 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxEvtHandler
) 
  61 // ============================================================================ 
  63 // ============================================================================ 
  65 // ---------------------------------------------------------------------------- 
  67 // ---------------------------------------------------------------------------- 
  69 // Construct a menu with optional title (then use append) 
  72     // Motif-specific members 
  74     m_menuWidget 
= (WXWidget
) NULL
; 
  75     m_popupShell 
= (WXWidget
) NULL
; 
  76     m_buttonWidget 
= (WXWidget
) NULL
; 
  78     m_topLevelMenu  
= (wxMenu
*) NULL
; 
  79     m_ownedByMenuBar 
= FALSE
; 
  83         Append(wxID_SEPARATOR
, m_title
) ; 
  87     m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENU
); 
  88     m_foregroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT
); 
  89     m_font 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
  92 // The wxWindow destructor will take care of deleting the submenus. 
 103     // Not sure if this is right 
 104     if (m_menuParent 
&& m_menuBar
) 
 116 // function appends a new item or submenu to the menu 
 117 bool wxMenu::DoAppend(wxMenuItem 
*pItem
) 
 121         // this is a dynamic Append 
 122         pItem
->CreateItem(m_menuWidget
, m_menuBar
, m_topLevelMenu
); 
 125     if ( pItem
->IsSubMenu() ) 
 127         pItem
->GetSubMenu()->m_topLevelMenu 
= m_topLevelMenu
; 
 130     return wxMenuBase::DoAppend(pItem
); 
 133 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
 135     item
->DestroyItem(TRUE
); 
 137     return wxMenuBase::DoRemove(item
); 
 140 bool wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
 142     if ( wxMenuBase::DoInsert(pos
, item
) ) 
 145     wxFAIL_MSG(wxT("DoInsert not implemented; or error in wxMenuBase::DoInsert")); 
 150 void wxMenu::SetTitle(const wxString
& label
) 
 154     wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 158     wxMenuItem 
*item 
= node
->GetData (); 
 159     Widget widget 
= (Widget
) item
->GetButtonWidget(); 
 163     wxXmString 
title_str(label
); 
 164     XtVaSetValues(widget
, 
 165                   XmNlabelString
, title_str(), 
 169 bool wxMenu::ProcessCommand(wxCommandEvent 
& event
) 
 171     bool processed 
= FALSE
; 
 173 #if wxUSE_MENU_CALLBACK 
 177         (void) (*(m_callback
)) (*this, event
); 
 180 #endif // wxUSE_MENU_CALLBACK 
 182     // Try the menu's event handler 
 183     if ( !processed 
&& GetEventHandler()) 
 185         processed 
= GetEventHandler()->ProcessEvent(event
); 
 187     // Try the window the menu was popped up from (and up 
 188     // through the hierarchy) 
 189     if ( !processed 
&& GetInvokingWindow()) 
 190         processed 
= GetInvokingWindow()->ProcessEvent(event
); 
 195 // ---------------------------------------------------------------------------- 
 197 // ---------------------------------------------------------------------------- 
 199 void wxMenuBar::Init() 
 201     m_eventHandler 
= this; 
 202     m_menuBarFrame 
= NULL
; 
 203     m_mainWidget 
= (WXWidget
) NULL
; 
 204     m_backgroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENU
); 
 205     m_foregroundColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT
); 
 206     m_font 
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
); 
 209 wxMenuBar::wxMenuBar(int n
, wxMenu 
*menus
[], const wxString titles
[]) 
 213     for ( int i 
= 0; i 
< n
; i
++ ) 
 215         m_menus
.Append(menus
[i
]); 
 216         m_titles
.Add(titles
[i
]); 
 220 wxMenuBar::~wxMenuBar() 
 222     // nothing to do: wxMenuBarBase will delete the menus 
 225 void wxMenuBar::EnableTop(size_t WXUNUSED(pos
), bool WXUNUSED(flag
)) 
 227   //    wxFAIL_MSG("TODO"); 
 228 //  wxLogWarning("wxMenuBar::EnableTop not yet implemented."); 
 231 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
) 
 233     wxMenu 
*menu 
= GetMenu(pos
); 
 237     Widget w 
= (Widget
)menu
->GetButtonWidget(); 
 240         wxXmString 
label_str(label
); 
 243                       XmNlabelString
, label_str(), 
 248 wxString 
wxMenuBar::GetLabelTop(size_t pos
) const 
 250     wxMenu 
*menu 
= GetMenu(pos
); 
 253         Widget w 
= (Widget
)menu
->GetButtonWidget(); 
 258                           XmNlabelString
, &text
, 
 261             return wxXmStringToString( text 
); 
 265     return wxEmptyString
; 
 268 bool wxMenuBar::Append(wxMenu 
* menu
, const wxString
& title
) 
 270     wxCHECK_MSG( menu
, FALSE
, wxT("invalid menu") ); 
 271     wxCHECK_MSG( !menu
->GetParent() && !menu
->GetButtonWidget(), FALSE
, 
 272                  wxT("menu already appended") ); 
 274     if ( m_menuBarFrame 
) 
 276         WXWidget w 
= menu
->CreateMenu(this, GetMainWidget(), menu
, title
, TRUE
); 
 277         wxCHECK_MSG( w
, FALSE
, wxT("failed to create menu") ); 
 278         menu
->SetButtonWidget(w
); 
 281     //menu->SetMenuBar(this); 
 285     return wxMenuBarBase::Append(menu
, title
); 
 288 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 290     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 293     wxFAIL_MSG(wxT("TODO")); 
 298 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 300     if ( !wxMenuBarBase::Replace(pos
, menu
, title
) ) 
 303     wxFAIL_MSG(wxT("TODO")); 
 308 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
 310     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
 314     if ( m_menuBarFrame 
) 
 315         menu
->DestroyMenu(TRUE
); 
 317     menu
->SetMenuBar(NULL
); 
 319     m_titles
.RemoveAt(pos
); 
 324 // Find the menu menuString, item itemString, and return the item id. 
 325 // Returns -1 if none found. 
 326 int wxMenuBar::FindMenuItem (const wxString
& menuString
, const wxString
& itemString
) const 
 330     wxStripMenuCodes (wxConstCast(menuString
.c_str(), char), buf1
); 
 332     size_t menuCount 
= GetMenuCount(); 
 333     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 335         wxStripMenuCodes (wxConstCast(m_titles
[i
].c_str(), char), buf2
); 
 336         if (strcmp (buf1
, buf2
) == 0) 
 337             return m_menus
.Item(i
)->GetData()->FindItem (itemString
); 
 342 wxMenuItem 
*wxMenuBar::FindItem(int id
, wxMenu 
** itemMenu
) const 
 347     wxMenuItem 
*item 
= NULL
; 
 348     size_t menuCount 
= GetMenuCount(); 
 349     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 350         if ((item 
= m_menus
.Item(i
)->GetData()->FindItem(id
, itemMenu
))) 
 356 bool wxMenuBar::CreateMenuBar(wxFrame
* parent
) 
 360         XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
); 
 362         if (!XtIsManaged((Widget) m_mainWidget)) 
 363         XtManageChild((Widget) m_mainWidget); 
 365         XtMapWidget((Widget
) m_mainWidget
); 
 369     Widget menuBarW 
= XmCreateMenuBar ((Widget
) parent
->GetMainWidget(), "MenuBar", NULL
, 0); 
 370     m_mainWidget 
= (WXWidget
) menuBarW
; 
 372     size_t menuCount 
= GetMenuCount(); 
 373     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 375         wxMenu 
*menu 
= GetMenu(i
); 
 376         wxString 
title(m_titles
[i
]); 
 377         menu
->SetButtonWidget(menu
->CreateMenu (this, menuBarW
, menu
, title
, TRUE
)); 
 379         if (strcmp (wxStripMenuCodes(title
), "Help") == 0) 
 380             XtVaSetValues ((Widget
) menuBarW
, XmNmenuHelpWidget
, (Widget
) menu
->GetButtonWidget(), NULL
); 
 382         // tear off menu support 
 383 #if (XmVersion >= 1002) 
 384         if ( menu
->IsTearOff() ) 
 386             XtVaSetValues(GetWidget(menu
), 
 387                           XmNtearOffModel
, XmTEAR_OFF_ENABLED
, 
 389             Widget tearOff 
= XmGetTearOffControl(GetWidget(menu
)); 
 390             wxDoChangeForegroundColour((Widget
) tearOff
, m_foregroundColour
); 
 391             wxDoChangeBackgroundColour((Widget
) tearOff
, m_backgroundColour
, TRUE
); 
 396     SetBackgroundColour(m_backgroundColour
); 
 397     SetForegroundColour(m_foregroundColour
); 
 400     XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
); 
 401     XtRealizeWidget ((Widget
) menuBarW
); 
 402     XtManageChild ((Widget
) menuBarW
); 
 403     SetMenuBarFrame(parent
); 
 408 // Destroy menubar, but keep data structures intact so we can recreate it. 
 409 bool wxMenuBar::DestroyMenuBar() 
 413         SetMenuBarFrame((wxFrame
*) NULL
); 
 417     XtUnmanageChild ((Widget
) m_mainWidget
); 
 418     XtUnrealizeWidget ((Widget
) m_mainWidget
); 
 420     size_t menuCount 
= GetMenuCount(); 
 421     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 423         wxMenu 
*menu 
= GetMenu(i
); 
 424         menu
->DestroyMenu(TRUE
); 
 427     XtDestroyWidget((Widget
) m_mainWidget
); 
 428     m_mainWidget 
= (WXWidget
) 0; 
 430     SetMenuBarFrame((wxFrame
*) NULL
); 
 435 // Since PopupMenu under Motif stills grab right mouse button events 
 436 // after it was closed, we need to delete the associated widgets to 
 437 // allow next PopUpMenu to appear... 
 438 void wxMenu::DestroyWidgetAndDetach() 
 442         wxMenu 
*menuParent 
= GetParent(); 
 445             wxMenuItemList::compatibility_iterator node 
= menuParent
->GetMenuItems().GetFirst(); 
 448                 if ( node
->GetData()->GetSubMenu() == this ) 
 450                     delete node
->GetData(); 
 451                     menuParent
->GetMenuItems().Erase(node
); 
 456                 node 
= node
->GetNext(); 
 463     // Mark as no longer popped up 
 468 * Create a popup or pulldown menu. 
 469 * Submenus of a popup will be pulldown. 
 473 WXWidget 
wxMenu::CreateMenu (wxMenuBar 
* menuBar
, WXWidget parent
, wxMenu 
* topMenu
, const wxString
& title
, bool pullDown
) 
 475     Widget menu 
= (Widget
) 0; 
 476     Widget buttonWidget 
= (Widget
) 0; 
 478     XtSetArg (args
[0], XmNnumColumns
, m_numColumns
); 
 479     XtSetArg (args
[1], XmNpacking
, (m_numColumns 
> 1) ? XmPACK_COLUMN 
: XmPACK_TIGHT
); 
 483         menu 
= XmCreatePopupMenu ((Widget
) parent
, "popup", args
, 2); 
 487             (XtCallbackProc
)wxMenuPopdownCallback
, 
 493         char mnem 
= wxFindMnemonic (title
); 
 494         menu 
= XmCreatePulldownMenu ((Widget
) parent
, "pulldown", args
, 2); 
 496         wxString 
title2(wxStripMenuCodes(title
)); 
 497         wxXmString 
label_str(title2
); 
 498         buttonWidget 
= XtVaCreateManagedWidget(title2
, 
 500             xmCascadeButtonGadgetClass
, (Widget
) parent
, 
 502             xmCascadeButtonWidgetClass
, (Widget
) parent
, 
 504             XmNlabelString
, label_str(), 
 509             XtVaSetValues (buttonWidget
, XmNmnemonic
, mnem
, NULL
); 
 512     m_menuWidget 
= (WXWidget
) menu
; 
 515     m_topLevelMenu 
= topMenu
; 
 517     for ( wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 519           node 
= node
->GetNext() ) 
 521         wxMenuItem 
*item 
= node
->GetData(); 
 523         item
->CreateItem(menu
, menuBar
, topMenu
); 
 526     SetBackgroundColour(m_backgroundColour
); 
 527     SetForegroundColour(m_foregroundColour
); 
 533 // Destroys the Motif implementation of the menu, 
 534 // but maintains the wxWindows data structures so we can 
 535 // do a CreateMenu again. 
 536 void wxMenu::DestroyMenu (bool full
) 
 538     for ( wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 540           node 
= node
->GetNext() ) 
 542         wxMenuItem 
*item 
= node
->GetData(); 
 543         item
->SetMenuBar((wxMenuBar
*) NULL
); 
 545         item
->DestroyItem(full
); 
 552             XtVaSetValues((Widget
) m_buttonWidget
, XmNsubMenuId
, NULL
, NULL
); 
 553             XtDestroyWidget ((Widget
) m_buttonWidget
); 
 554             m_buttonWidget 
= (WXWidget
) 0; 
 557     if (m_menuWidget 
&& full
) 
 559         XtDestroyWidget((Widget
) m_menuWidget
); 
 560         m_menuWidget 
= (WXWidget
) NULL
; 
 564 WXWidget 
wxMenu::FindMenuItem (int id
, wxMenuItem 
** it
) const 
 569             *it 
= (wxMenuItem
*) NULL
; 
 570         return m_buttonWidget
; 
 573     for ( wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 575           node 
= node
->GetNext() ) 
 577         wxMenuItem 
*item 
= node
->GetData (); 
 578         if (item
->GetId() == id
) 
 582             return item
->GetButtonWidget(); 
 585         if (item
->GetSubMenu()) 
 587             WXWidget w 
= item
->GetSubMenu()->FindMenuItem (id
, it
); 
 596         *it 
= (wxMenuItem
*) NULL
; 
 597     return (WXWidget
) NULL
; 
 600 void wxMenu::SetBackgroundColour(const wxColour
& col
) 
 602     m_backgroundColour 
= col
; 
 604         wxDoChangeBackgroundColour(m_menuWidget
, (wxColour
&) col
); 
 606         wxDoChangeBackgroundColour(m_buttonWidget
, (wxColour
&) col
, TRUE
); 
 608     for ( wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 610           node 
= node
->GetNext() ) 
 612         wxMenuItem
* item 
= node
->GetData(); 
 613         if (item
->GetButtonWidget()) 
 615             // This crashes because it uses gadgets 
 616             //            wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, TRUE); 
 618         if (item
->GetSubMenu()) 
 619             item
->GetSubMenu()->SetBackgroundColour((wxColour
&) col
); 
 623 void wxMenu::SetForegroundColour(const wxColour
& col
) 
 625     m_foregroundColour 
= col
; 
 627         wxDoChangeForegroundColour(m_menuWidget
, (wxColour
&) col
); 
 629         wxDoChangeForegroundColour(m_buttonWidget
, (wxColour
&) col
); 
 631     for ( wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 633           node 
= node
->GetNext() ) 
 635         wxMenuItem
* item 
= node
->GetData(); 
 636         if (item
->GetButtonWidget()) 
 638             // This crashes because it uses gadgets 
 639             //            wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col); 
 641         if (item
->GetSubMenu()) 
 642             item
->GetSubMenu()->SetForegroundColour((wxColour
&) col
); 
 646 void wxMenu::ChangeFont(bool keepOriginalSize
) 
 648     // Lesstif 0.87 hangs here, but 0.93 does not 
 649 #if !wxCHECK_LESSTIF() || wxCHECK_LESSTIF_VERSION( 0, 93 ) 
 650     if (!m_font
.Ok() || !m_menuWidget
) 
 653     WXFontType fontType 
= m_font
.GetFontType(XtDisplay((Widget
) m_menuWidget
)); 
 655     XtVaSetValues ((Widget
) m_menuWidget
, 
 656                    wxFont::GetFontTag(), fontType
, 
 660         XtVaSetValues ((Widget
) m_buttonWidget
, 
 661                        wxFont::GetFontTag(), fontType
, 
 665     for ( wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 667           node 
= node
->GetNext() ) 
 669         wxMenuItem
* item 
= node
->GetData(); 
 670         if (m_menuWidget 
&& item
->GetButtonWidget() && m_font
.Ok()) 
 672             XtVaSetValues ((Widget
) item
->GetButtonWidget(), 
 673                            wxFont::GetFontTag(), fontType
, 
 676         if (item
->GetSubMenu()) 
 677             item
->GetSubMenu()->ChangeFont(keepOriginalSize
); 
 682 void wxMenu::SetFont(const wxFont
& font
) 
 688 bool wxMenuBar::SetBackgroundColour(const wxColour
& col
) 
 690     m_backgroundColour 
= col
; 
 692         wxDoChangeBackgroundColour(m_mainWidget
, (wxColour
&) col
); 
 694     size_t menuCount 
= GetMenuCount(); 
 695     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 696         m_menus
.Item(i
)->GetData()->SetBackgroundColour((wxColour
&) col
); 
 701 bool wxMenuBar::SetForegroundColour(const wxColour
& col
) 
 703     m_foregroundColour 
= col
; 
 705         wxDoChangeForegroundColour(m_mainWidget
, (wxColour
&) col
); 
 707     size_t menuCount 
= GetMenuCount(); 
 708     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 709         m_menus
.Item(i
)->GetData()->SetForegroundColour((wxColour
&) col
); 
 714 void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize
)) 
 716     // Nothing to do for menubar, fonts are kept in wxMenus 
 719 bool wxMenuBar::SetFont(const wxFont
& font
) 
 724     size_t menuCount 
= GetMenuCount(); 
 725     for (size_t i 
= 0; i 
< menuCount
; i
++) 
 726         m_menus
.Item(i
)->GetData()->SetFont(font
);