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 // ----------------------------------------------------------------------------
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
31 #include "wx/menuitem.h"
36 #include "wx/settings.h"
39 #pragma message disable nosimpint
40 #define XtDisplay XTDISPLAY
41 #define XtWindow XTWINDOW
44 #include <Xm/LabelG.h>
45 #include <Xm/CascadeBG.h>
46 #include <Xm/CascadeB.h>
47 #include <Xm/SeparatoG.h>
48 #include <Xm/PushBG.h>
49 #include <Xm/ToggleB.h>
50 #include <Xm/ToggleBG.h>
51 #include <Xm/RowColumn.h>
53 #pragma message enable nosimpint
56 #include "wx/motif/private.h"
58 // other standard headers
61 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
62 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxEvtHandler
)
64 // ============================================================================
66 // ============================================================================
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
72 // Construct a menu with optional title (then use append)
75 // Motif-specific members
77 m_menuWidget
= (WXWidget
) NULL
;
78 m_popupShell
= (WXWidget
) NULL
;
79 m_buttonWidget
= (WXWidget
) NULL
;
81 m_topLevelMenu
= (wxMenu
*) NULL
;
82 m_ownedByMenuBar
= false;
84 if ( !m_title
.empty() )
90 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENU
);
91 m_foregroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT
);
92 m_font
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
95 // The wxWindow destructor will take care of deleting the submenus.
106 // Not sure if this is right
107 if (m_menuParent
&& m_menuBar
)
119 // function appends a new item or submenu to the menu
120 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*pItem
)
124 // this is a dynamic Append
125 pItem
->CreateItem(m_menuWidget
, GetMenuBar(), m_topLevelMenu
);
128 if ( pItem
->IsSubMenu() )
130 pItem
->GetSubMenu()->m_topLevelMenu
= m_topLevelMenu
;
133 return wxMenuBase::DoAppend(pItem
);
136 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
138 item
->DestroyItem(true);
140 return wxMenuBase::DoRemove(item
);
143 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
145 if ( wxMenuBase::DoInsert(pos
, item
) )
148 wxFAIL_MSG(wxT("DoInsert not implemented; or error in wxMenuBase::DoInsert"));
153 void wxMenu::SetTitle(const wxString
& label
)
157 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
161 wxMenuItem
*item
= node
->GetData ();
162 Widget widget
= (Widget
) item
->GetButtonWidget();
166 wxXmString
title_str(label
);
167 XtVaSetValues(widget
,
168 XmNlabelString
, title_str(),
172 bool wxMenu::ProcessCommand(wxCommandEvent
& event
)
174 bool processed
= false;
176 // Try the menu's event handler
177 if ( !processed
&& GetEventHandler())
179 processed
= GetEventHandler()->ProcessEvent(event
);
181 // Try the window the menu was popped up from (and up
182 // through the hierarchy)
183 if ( !processed
&& GetInvokingWindow())
184 processed
= GetInvokingWindow()->ProcessEvent(event
);
189 // ----------------------------------------------------------------------------
191 // ----------------------------------------------------------------------------
193 void wxMenuBar::Init()
195 m_eventHandler
= this;
196 m_menuBarFrame
= NULL
;
197 m_mainWidget
= (WXWidget
) NULL
;
198 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENU
);
199 m_foregroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT
);
200 m_font
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
203 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxArrayString
& titles
, long WXUNUSED(style
))
205 wxASSERT( n
== titles
.GetCount() );
210 for ( size_t i
= 0; i
< n
; i
++ )
211 m_menus
.Append(menus
[i
]);
214 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
218 for ( size_t i
= 0; i
< n
; i
++ )
220 m_menus
.Append(menus
[i
]);
221 m_titles
.Add(titles
[i
]);
225 wxMenuBar::~wxMenuBar()
227 // nothing to do: wxMenuBarBase will delete the menus
230 void wxMenuBar::EnableTop(size_t WXUNUSED(pos
), bool WXUNUSED(flag
))
232 // wxFAIL_MSG("TODO");
233 // wxLogWarning("wxMenuBar::EnableTop not yet implemented.");
236 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
238 wxMenu
*menu
= GetMenu(pos
);
242 Widget w
= (Widget
)menu
->GetButtonWidget();
245 wxXmString
label_str(label
);
248 XmNlabelString
, label_str(),
253 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
255 wxMenu
*menu
= GetMenu(pos
);
258 Widget w
= (Widget
)menu
->GetButtonWidget();
263 XmNlabelString
, &text
,
266 return wxXmStringToString( text
);
270 return wxEmptyString
;
273 bool wxMenuBar::Append(wxMenu
* menu
, const wxString
& title
)
275 wxCHECK_MSG( menu
, false, wxT("invalid menu") );
276 wxCHECK_MSG( !menu
->GetParent() && !menu
->GetButtonWidget(), false,
277 wxT("menu already appended") );
279 if ( m_menuBarFrame
)
281 WXWidget w
= menu
->CreateMenu(this, GetMainWidget(), menu
, title
, true);
282 wxCHECK_MSG( w
, false, wxT("failed to create menu") );
283 menu
->SetButtonWidget(w
);
288 return wxMenuBarBase::Append(menu
, title
);
291 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
293 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
296 wxFAIL_MSG(wxT("TODO"));
301 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
303 if ( !wxMenuBarBase::Replace(pos
, menu
, title
) )
306 wxFAIL_MSG(wxT("TODO"));
311 wxMenu
*wxMenuBar::Remove(size_t pos
)
313 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
317 if ( m_menuBarFrame
)
318 menu
->DestroyMenu(true);
320 menu
->SetMenuBar(NULL
);
322 m_titles
.RemoveAt(pos
);
327 // Find the menu menuString, item itemString, and return the item id.
328 // Returns -1 if none found.
329 int wxMenuBar::FindMenuItem (const wxString
& menuString
, const wxString
& itemString
) const
333 wxStripMenuCodes (wxConstCast(menuString
.c_str(), char), buf1
);
335 size_t menuCount
= GetMenuCount();
336 for (size_t i
= 0; i
< menuCount
; i
++)
338 wxStripMenuCodes (wxConstCast(m_titles
[i
].c_str(), char), buf2
);
339 if (strcmp (buf1
, buf2
) == 0)
340 return m_menus
.Item(i
)->GetData()->FindItem (itemString
);
345 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
** itemMenu
) const
350 wxMenuItem
*item
= NULL
;
351 size_t menuCount
= GetMenuCount();
352 for (size_t i
= 0; i
< menuCount
; i
++)
353 if ((item
= m_menus
.Item(i
)->GetData()->FindItem(id
, itemMenu
)))
359 bool wxMenuBar::CreateMenuBar(wxFrame
* parent
)
363 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
365 if (!XtIsManaged((Widget) m_mainWidget))
366 XtManageChild((Widget) m_mainWidget);
368 XtMapWidget((Widget
) m_mainWidget
);
372 Widget menuBarW
= XmCreateMenuBar ((Widget
) parent
->GetMainWidget(),
373 wxMOTIF_STR("MenuBar"), NULL
, 0);
374 m_mainWidget
= (WXWidget
) menuBarW
;
376 size_t menuCount
= GetMenuCount();
377 for (size_t i
= 0; i
< menuCount
; i
++)
379 wxMenu
*menu
= GetMenu(i
);
380 wxString
title(m_titles
[i
]);
381 menu
->SetButtonWidget(menu
->CreateMenu (this, menuBarW
, menu
, title
, true));
383 if (strcmp (wxStripMenuCodes(title
), "Help") == 0)
384 XtVaSetValues ((Widget
) menuBarW
, XmNmenuHelpWidget
, (Widget
) menu
->GetButtonWidget(), NULL
);
386 // tear off menu support
387 #if (XmVersion >= 1002)
388 if ( menu
->IsTearOff() )
390 XtVaSetValues(GetWidget(menu
),
391 XmNtearOffModel
, XmTEAR_OFF_ENABLED
,
393 Widget tearOff
= XmGetTearOffControl(GetWidget(menu
));
394 wxDoChangeForegroundColour((Widget
) tearOff
, m_foregroundColour
);
395 wxDoChangeBackgroundColour((Widget
) tearOff
, m_backgroundColour
, true);
400 SetBackgroundColour(m_backgroundColour
);
401 SetForegroundColour(m_foregroundColour
);
404 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
405 XtRealizeWidget ((Widget
) menuBarW
);
406 XtManageChild ((Widget
) menuBarW
);
407 SetMenuBarFrame(parent
);
412 // Destroy menubar, but keep data structures intact so we can recreate it.
413 bool wxMenuBar::DestroyMenuBar()
417 SetMenuBarFrame((wxFrame
*) NULL
);
421 XtUnmanageChild ((Widget
) m_mainWidget
);
422 XtUnrealizeWidget ((Widget
) m_mainWidget
);
424 size_t menuCount
= GetMenuCount();
425 for (size_t i
= 0; i
< menuCount
; i
++)
427 wxMenu
*menu
= GetMenu(i
);
428 menu
->DestroyMenu(true);
431 XtDestroyWidget((Widget
) m_mainWidget
);
432 m_mainWidget
= (WXWidget
) 0;
434 SetMenuBarFrame((wxFrame
*) NULL
);
439 // Since PopupMenu under Motif stills grab right mouse button events
440 // after it was closed, we need to delete the associated widgets to
441 // allow next PopUpMenu to appear...
442 void wxMenu::DestroyWidgetAndDetach()
446 wxMenu
*menuParent
= GetParent();
449 wxMenuItemList::compatibility_iterator node
= menuParent
->GetMenuItems().GetFirst();
452 if ( node
->GetData()->GetSubMenu() == this )
454 delete node
->GetData();
455 menuParent
->GetMenuItems().Erase(node
);
460 node
= node
->GetNext();
467 // Mark as no longer popped up
472 * Create a popup or pulldown menu.
473 * Submenus of a popup will be pulldown.
477 WXWidget
wxMenu::CreateMenu (wxMenuBar
* menuBar
, WXWidget parent
, wxMenu
* topMenu
, const wxString
& title
, bool pullDown
)
479 Widget menu
= (Widget
) 0;
480 Widget buttonWidget
= (Widget
) 0;
482 XtSetArg (args
[0], XmNnumColumns
, m_numColumns
);
483 XtSetArg (args
[1], XmNpacking
, (m_numColumns
> 1) ? XmPACK_COLUMN
: XmPACK_TIGHT
);
487 menu
= XmCreatePopupMenu ((Widget
) parent
, wxMOTIF_STR("popup"), args
, 2);
491 (XtCallbackProc
)wxMenuPopdownCallback
,
497 char mnem
= wxFindMnemonic (title
);
498 menu
= XmCreatePulldownMenu ((Widget
) parent
, wxMOTIF_STR("pulldown"), args
, 2);
500 wxString
title2(wxStripMenuCodes(title
));
501 wxXmString
label_str(title2
);
502 buttonWidget
= XtVaCreateManagedWidget(title2
,
504 xmCascadeButtonGadgetClass
, (Widget
) parent
,
506 xmCascadeButtonWidgetClass
, (Widget
) parent
,
508 XmNlabelString
, label_str(),
513 XtVaSetValues (buttonWidget
, XmNmnemonic
, mnem
, NULL
);
516 m_menuWidget
= (WXWidget
) menu
;
518 m_topLevelMenu
= topMenu
;
520 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
522 node
= node
->GetNext() )
524 wxMenuItem
*item
= node
->GetData();
526 item
->CreateItem(menu
, menuBar
, topMenu
);
529 SetBackgroundColour(m_backgroundColour
);
530 SetForegroundColour(m_foregroundColour
);
536 // Destroys the Motif implementation of the menu,
537 // but maintains the wxWidgets data structures so we can
538 // do a CreateMenu again.
539 void wxMenu::DestroyMenu (bool full
)
541 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
543 node
= node
->GetNext() )
545 wxMenuItem
*item
= node
->GetData();
546 item
->SetMenuBar((wxMenuBar
*) NULL
);
548 item
->DestroyItem(full
);
555 XtVaSetValues((Widget
) m_buttonWidget
, XmNsubMenuId
, NULL
, NULL
);
556 XtDestroyWidget ((Widget
) m_buttonWidget
);
557 m_buttonWidget
= (WXWidget
) 0;
560 if (m_menuWidget
&& full
)
562 XtDestroyWidget((Widget
) m_menuWidget
);
563 m_menuWidget
= (WXWidget
) NULL
;
567 WXWidget
wxMenu::FindMenuItem (int id
, wxMenuItem
** it
) const
572 *it
= (wxMenuItem
*) NULL
;
573 return m_buttonWidget
;
576 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
578 node
= node
->GetNext() )
580 wxMenuItem
*item
= node
->GetData ();
581 if (item
->GetId() == id
)
585 return item
->GetButtonWidget();
588 if (item
->GetSubMenu())
590 WXWidget w
= item
->GetSubMenu()->FindMenuItem (id
, it
);
599 *it
= (wxMenuItem
*) NULL
;
600 return (WXWidget
) NULL
;
603 void wxMenu::SetBackgroundColour(const wxColour
& col
)
605 m_backgroundColour
= col
;
607 wxDoChangeBackgroundColour(m_menuWidget
, (wxColour
&) col
);
609 wxDoChangeBackgroundColour(m_buttonWidget
, (wxColour
&) col
, true);
611 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
613 node
= node
->GetNext() )
615 wxMenuItem
* item
= node
->GetData();
616 if (item
->GetButtonWidget())
618 // This crashes because it uses gadgets
619 // wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, true);
621 if (item
->GetSubMenu())
622 item
->GetSubMenu()->SetBackgroundColour((wxColour
&) col
);
626 void wxMenu::SetForegroundColour(const wxColour
& col
)
628 m_foregroundColour
= col
;
630 wxDoChangeForegroundColour(m_menuWidget
, (wxColour
&) col
);
632 wxDoChangeForegroundColour(m_buttonWidget
, (wxColour
&) col
);
634 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
636 node
= node
->GetNext() )
638 wxMenuItem
* item
= node
->GetData();
639 if (item
->GetButtonWidget())
641 // This crashes because it uses gadgets
642 // wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
644 if (item
->GetSubMenu())
645 item
->GetSubMenu()->SetForegroundColour((wxColour
&) col
);
649 void wxMenu::ChangeFont(bool keepOriginalSize
)
651 // Lesstif 0.87 hangs here, but 0.93 does not; MBN: sometimes it does
652 #if !wxCHECK_LESSTIF() // || wxCHECK_LESSTIF_VERSION( 0, 93 )
653 if (!m_font
.Ok() || !m_menuWidget
)
656 Display
* dpy
= XtDisplay((Widget
) m_menuWidget
);
658 XtVaSetValues ((Widget
) m_menuWidget
,
659 wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
),
663 XtVaSetValues ((Widget
) m_buttonWidget
,
664 wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
),
668 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
670 node
= node
->GetNext() )
672 wxMenuItem
* item
= node
->GetData();
673 if (m_menuWidget
&& item
->GetButtonWidget() && m_font
.Ok())
675 XtVaSetValues ((Widget
) item
->GetButtonWidget(),
676 wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
),
679 if (item
->GetSubMenu())
680 item
->GetSubMenu()->ChangeFont(keepOriginalSize
);
685 void wxMenu::SetFont(const wxFont
& font
)
691 bool wxMenuBar::SetBackgroundColour(const wxColour
& col
)
693 m_backgroundColour
= col
;
695 wxDoChangeBackgroundColour(m_mainWidget
, (wxColour
&) col
);
697 size_t menuCount
= GetMenuCount();
698 for (size_t i
= 0; i
< menuCount
; i
++)
699 m_menus
.Item(i
)->GetData()->SetBackgroundColour((wxColour
&) col
);
704 bool wxMenuBar::SetForegroundColour(const wxColour
& col
)
706 m_foregroundColour
= col
;
708 wxDoChangeForegroundColour(m_mainWidget
, (wxColour
&) col
);
710 size_t menuCount
= GetMenuCount();
711 for (size_t i
= 0; i
< menuCount
; i
++)
712 m_menus
.Item(i
)->GetData()->SetForegroundColour((wxColour
&) col
);
717 void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize
))
719 // Nothing to do for menubar, fonts are kept in wxMenus
722 bool wxMenuBar::SetFont(const wxFont
& font
)
727 size_t menuCount
= GetMenuCount();
728 for (size_t i
= 0; i
< menuCount
; i
++)
729 m_menus
.Item(i
)->GetData()->SetFont(font
);