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 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*pItem
)
121 // this is a dynamic Append
122 pItem
->CreateItem(m_menuWidget
, GetMenuBar(), 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 wxMenuItem
* 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 wxArrayString
& titles
)
211 wxASSERT( size_t(n
) == titles
.GetCount() );
216 for ( int i
= 0; i
< n
; i
++ )
217 m_menus
.Append(menus
[i
]);
220 wxMenuBar::wxMenuBar(int n
, wxMenu
*menus
[], const wxString titles
[])
224 for ( int i
= 0; i
< n
; i
++ )
226 m_menus
.Append(menus
[i
]);
227 m_titles
.Add(titles
[i
]);
231 wxMenuBar::~wxMenuBar()
233 // nothing to do: wxMenuBarBase will delete the menus
236 void wxMenuBar::EnableTop(size_t WXUNUSED(pos
), bool WXUNUSED(flag
))
238 // wxFAIL_MSG("TODO");
239 // wxLogWarning("wxMenuBar::EnableTop not yet implemented.");
242 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
244 wxMenu
*menu
= GetMenu(pos
);
248 Widget w
= (Widget
)menu
->GetButtonWidget();
251 wxXmString
label_str(label
);
254 XmNlabelString
, label_str(),
259 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
261 wxMenu
*menu
= GetMenu(pos
);
264 Widget w
= (Widget
)menu
->GetButtonWidget();
269 XmNlabelString
, &text
,
272 return wxXmStringToString( text
);
276 return wxEmptyString
;
279 bool wxMenuBar::Append(wxMenu
* menu
, const wxString
& title
)
281 wxCHECK_MSG( menu
, FALSE
, wxT("invalid menu") );
282 wxCHECK_MSG( !menu
->GetParent() && !menu
->GetButtonWidget(), FALSE
,
283 wxT("menu already appended") );
285 if ( m_menuBarFrame
)
287 WXWidget w
= menu
->CreateMenu(this, GetMainWidget(), menu
, title
, TRUE
);
288 wxCHECK_MSG( w
, FALSE
, wxT("failed to create menu") );
289 menu
->SetButtonWidget(w
);
294 return wxMenuBarBase::Append(menu
, title
);
297 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
299 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
302 wxFAIL_MSG(wxT("TODO"));
307 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
309 if ( !wxMenuBarBase::Replace(pos
, menu
, title
) )
312 wxFAIL_MSG(wxT("TODO"));
317 wxMenu
*wxMenuBar::Remove(size_t pos
)
319 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
323 if ( m_menuBarFrame
)
324 menu
->DestroyMenu(TRUE
);
326 menu
->SetMenuBar(NULL
);
328 m_titles
.RemoveAt(pos
);
333 // Find the menu menuString, item itemString, and return the item id.
334 // Returns -1 if none found.
335 int wxMenuBar::FindMenuItem (const wxString
& menuString
, const wxString
& itemString
) const
339 wxStripMenuCodes (wxConstCast(menuString
.c_str(), char), buf1
);
341 size_t menuCount
= GetMenuCount();
342 for (size_t i
= 0; i
< menuCount
; i
++)
344 wxStripMenuCodes (wxConstCast(m_titles
[i
].c_str(), char), buf2
);
345 if (strcmp (buf1
, buf2
) == 0)
346 return m_menus
.Item(i
)->GetData()->FindItem (itemString
);
351 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
** itemMenu
) const
356 wxMenuItem
*item
= NULL
;
357 size_t menuCount
= GetMenuCount();
358 for (size_t i
= 0; i
< menuCount
; i
++)
359 if ((item
= m_menus
.Item(i
)->GetData()->FindItem(id
, itemMenu
)))
365 bool wxMenuBar::CreateMenuBar(wxFrame
* parent
)
369 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
371 if (!XtIsManaged((Widget) m_mainWidget))
372 XtManageChild((Widget) m_mainWidget);
374 XtMapWidget((Widget
) m_mainWidget
);
378 Widget menuBarW
= XmCreateMenuBar ((Widget
) parent
->GetMainWidget(), "MenuBar", NULL
, 0);
379 m_mainWidget
= (WXWidget
) menuBarW
;
381 size_t menuCount
= GetMenuCount();
382 for (size_t i
= 0; i
< menuCount
; i
++)
384 wxMenu
*menu
= GetMenu(i
);
385 wxString
title(m_titles
[i
]);
386 menu
->SetButtonWidget(menu
->CreateMenu (this, menuBarW
, menu
, title
, TRUE
));
388 if (strcmp (wxStripMenuCodes(title
), "Help") == 0)
389 XtVaSetValues ((Widget
) menuBarW
, XmNmenuHelpWidget
, (Widget
) menu
->GetButtonWidget(), NULL
);
391 // tear off menu support
392 #if (XmVersion >= 1002)
393 if ( menu
->IsTearOff() )
395 XtVaSetValues(GetWidget(menu
),
396 XmNtearOffModel
, XmTEAR_OFF_ENABLED
,
398 Widget tearOff
= XmGetTearOffControl(GetWidget(menu
));
399 wxDoChangeForegroundColour((Widget
) tearOff
, m_foregroundColour
);
400 wxDoChangeBackgroundColour((Widget
) tearOff
, m_backgroundColour
, TRUE
);
405 SetBackgroundColour(m_backgroundColour
);
406 SetForegroundColour(m_foregroundColour
);
409 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
410 XtRealizeWidget ((Widget
) menuBarW
);
411 XtManageChild ((Widget
) menuBarW
);
412 SetMenuBarFrame(parent
);
417 // Destroy menubar, but keep data structures intact so we can recreate it.
418 bool wxMenuBar::DestroyMenuBar()
422 SetMenuBarFrame((wxFrame
*) NULL
);
426 XtUnmanageChild ((Widget
) m_mainWidget
);
427 XtUnrealizeWidget ((Widget
) m_mainWidget
);
429 size_t menuCount
= GetMenuCount();
430 for (size_t i
= 0; i
< menuCount
; i
++)
432 wxMenu
*menu
= GetMenu(i
);
433 menu
->DestroyMenu(TRUE
);
436 XtDestroyWidget((Widget
) m_mainWidget
);
437 m_mainWidget
= (WXWidget
) 0;
439 SetMenuBarFrame((wxFrame
*) NULL
);
444 // Since PopupMenu under Motif stills grab right mouse button events
445 // after it was closed, we need to delete the associated widgets to
446 // allow next PopUpMenu to appear...
447 void wxMenu::DestroyWidgetAndDetach()
451 wxMenu
*menuParent
= GetParent();
454 wxMenuItemList::compatibility_iterator node
= menuParent
->GetMenuItems().GetFirst();
457 if ( node
->GetData()->GetSubMenu() == this )
459 delete node
->GetData();
460 menuParent
->GetMenuItems().Erase(node
);
465 node
= node
->GetNext();
472 // Mark as no longer popped up
477 * Create a popup or pulldown menu.
478 * Submenus of a popup will be pulldown.
482 WXWidget
wxMenu::CreateMenu (wxMenuBar
* menuBar
, WXWidget parent
, wxMenu
* topMenu
, const wxString
& title
, bool pullDown
)
484 Widget menu
= (Widget
) 0;
485 Widget buttonWidget
= (Widget
) 0;
487 XtSetArg (args
[0], XmNnumColumns
, m_numColumns
);
488 XtSetArg (args
[1], XmNpacking
, (m_numColumns
> 1) ? XmPACK_COLUMN
: XmPACK_TIGHT
);
492 menu
= XmCreatePopupMenu ((Widget
) parent
, "popup", args
, 2);
496 (XtCallbackProc
)wxMenuPopdownCallback
,
502 char mnem
= wxFindMnemonic (title
);
503 menu
= XmCreatePulldownMenu ((Widget
) parent
, "pulldown", args
, 2);
505 wxString
title2(wxStripMenuCodes(title
));
506 wxXmString
label_str(title2
);
507 buttonWidget
= XtVaCreateManagedWidget(title2
,
509 xmCascadeButtonGadgetClass
, (Widget
) parent
,
511 xmCascadeButtonWidgetClass
, (Widget
) parent
,
513 XmNlabelString
, label_str(),
518 XtVaSetValues (buttonWidget
, XmNmnemonic
, mnem
, NULL
);
521 m_menuWidget
= (WXWidget
) menu
;
523 m_topLevelMenu
= topMenu
;
525 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
527 node
= node
->GetNext() )
529 wxMenuItem
*item
= node
->GetData();
531 item
->CreateItem(menu
, menuBar
, topMenu
);
534 SetBackgroundColour(m_backgroundColour
);
535 SetForegroundColour(m_foregroundColour
);
541 // Destroys the Motif implementation of the menu,
542 // but maintains the wxWindows data structures so we can
543 // do a CreateMenu again.
544 void wxMenu::DestroyMenu (bool full
)
546 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
548 node
= node
->GetNext() )
550 wxMenuItem
*item
= node
->GetData();
551 item
->SetMenuBar((wxMenuBar
*) NULL
);
553 item
->DestroyItem(full
);
560 XtVaSetValues((Widget
) m_buttonWidget
, XmNsubMenuId
, NULL
, NULL
);
561 XtDestroyWidget ((Widget
) m_buttonWidget
);
562 m_buttonWidget
= (WXWidget
) 0;
565 if (m_menuWidget
&& full
)
567 XtDestroyWidget((Widget
) m_menuWidget
);
568 m_menuWidget
= (WXWidget
) NULL
;
572 WXWidget
wxMenu::FindMenuItem (int id
, wxMenuItem
** it
) const
577 *it
= (wxMenuItem
*) NULL
;
578 return m_buttonWidget
;
581 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
583 node
= node
->GetNext() )
585 wxMenuItem
*item
= node
->GetData ();
586 if (item
->GetId() == id
)
590 return item
->GetButtonWidget();
593 if (item
->GetSubMenu())
595 WXWidget w
= item
->GetSubMenu()->FindMenuItem (id
, it
);
604 *it
= (wxMenuItem
*) NULL
;
605 return (WXWidget
) NULL
;
608 void wxMenu::SetBackgroundColour(const wxColour
& col
)
610 m_backgroundColour
= col
;
612 wxDoChangeBackgroundColour(m_menuWidget
, (wxColour
&) col
);
614 wxDoChangeBackgroundColour(m_buttonWidget
, (wxColour
&) col
, TRUE
);
616 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
618 node
= node
->GetNext() )
620 wxMenuItem
* item
= node
->GetData();
621 if (item
->GetButtonWidget())
623 // This crashes because it uses gadgets
624 // wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, TRUE);
626 if (item
->GetSubMenu())
627 item
->GetSubMenu()->SetBackgroundColour((wxColour
&) col
);
631 void wxMenu::SetForegroundColour(const wxColour
& col
)
633 m_foregroundColour
= col
;
635 wxDoChangeForegroundColour(m_menuWidget
, (wxColour
&) col
);
637 wxDoChangeForegroundColour(m_buttonWidget
, (wxColour
&) col
);
639 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
641 node
= node
->GetNext() )
643 wxMenuItem
* item
= node
->GetData();
644 if (item
->GetButtonWidget())
646 // This crashes because it uses gadgets
647 // wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
649 if (item
->GetSubMenu())
650 item
->GetSubMenu()->SetForegroundColour((wxColour
&) col
);
654 void wxMenu::ChangeFont(bool keepOriginalSize
)
656 // Lesstif 0.87 hangs here, but 0.93 does not
657 #if !wxCHECK_LESSTIF() || wxCHECK_LESSTIF_VERSION( 0, 93 )
658 if (!m_font
.Ok() || !m_menuWidget
)
661 WXFontType fontType
= m_font
.GetFontType(XtDisplay((Widget
) m_menuWidget
));
663 XtVaSetValues ((Widget
) m_menuWidget
,
664 wxFont::GetFontTag(), fontType
,
668 XtVaSetValues ((Widget
) m_buttonWidget
,
669 wxFont::GetFontTag(), fontType
,
673 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
675 node
= node
->GetNext() )
677 wxMenuItem
* item
= node
->GetData();
678 if (m_menuWidget
&& item
->GetButtonWidget() && m_font
.Ok())
680 XtVaSetValues ((Widget
) item
->GetButtonWidget(),
681 wxFont::GetFontTag(), fontType
,
684 if (item
->GetSubMenu())
685 item
->GetSubMenu()->ChangeFont(keepOriginalSize
);
690 void wxMenu::SetFont(const wxFont
& font
)
696 bool wxMenuBar::SetBackgroundColour(const wxColour
& col
)
698 m_backgroundColour
= col
;
700 wxDoChangeBackgroundColour(m_mainWidget
, (wxColour
&) col
);
702 size_t menuCount
= GetMenuCount();
703 for (size_t i
= 0; i
< menuCount
; i
++)
704 m_menus
.Item(i
)->GetData()->SetBackgroundColour((wxColour
&) col
);
709 bool wxMenuBar::SetForegroundColour(const wxColour
& col
)
711 m_foregroundColour
= col
;
713 wxDoChangeForegroundColour(m_mainWidget
, (wxColour
&) col
);
715 size_t menuCount
= GetMenuCount();
716 for (size_t i
= 0; i
< menuCount
; i
++)
717 m_menus
.Item(i
)->GetData()->SetForegroundColour((wxColour
&) col
);
722 void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize
))
724 // Nothing to do for menubar, fonts are kept in wxMenus
727 bool wxMenuBar::SetFont(const wxFont
& font
)
732 size_t menuCount
= GetMenuCount();
733 for (size_t i
= 0; i
< menuCount
; i
++)
734 m_menus
.Item(i
)->GetData()->SetFont(font
);