1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
18 #pragma implementation "menu.h"
21 // ----------------------------------------------------------------------------
23 // ----------------------------------------------------------------------------
26 #include "wx/menuitem.h"
31 #include "wx/settings.h"
34 #include <Xm/LabelG.h>
35 #include <Xm/CascadeBG.h>
36 #include <Xm/CascadeB.h>
37 #include <Xm/SeparatoG.h>
38 #include <Xm/PushBG.h>
39 #include <Xm/ToggleB.h>
40 #include <Xm/ToggleBG.h>
41 #include <Xm/RowColumn.h>
43 #include "wx/motif/private.h"
45 // other standard headers
48 #if !USE_SHARED_LIBRARY
49 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
50 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxEvtHandler
)
53 // ============================================================================
55 // ============================================================================
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 // Construct a menu with optional title (then use append)
64 // Motif-specific members
66 m_menuWidget
= (WXWidget
) NULL
;
67 m_popupShell
= (WXWidget
) NULL
;
68 m_buttonWidget
= (WXWidget
) NULL
;
70 m_topLevelMenu
= (wxMenu
*) NULL
;
71 m_ownedByMenuBar
= FALSE
;
75 Append(wxID_SEPARATOR
, m_title
) ;
79 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENU
);
80 m_foregroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENUTEXT
);
81 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
84 // The wxWindow destructor will take care of deleting the submenus.
95 // Not sure if this is right
96 if (m_menuParent
&& m_menuBar
)
108 // function appends a new item or submenu to the menu
109 bool wxMenu::DoAppend(wxMenuItem
*pItem
)
113 // this is a dynamic Append
114 pItem
->CreateItem(m_menuWidget
, m_menuBar
, m_topLevelMenu
);
117 if ( pItem
->IsSubMenu() )
119 pItem
->GetSubMenu()->m_topLevelMenu
= m_topLevelMenu
;
122 return wxMenuBase::DoAppend(pItem
);
125 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
127 item
->DestroyItem(TRUE
);
129 return wxMenuBase::DoRemove(item
);
132 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
134 if ( !wxMenuBase::DoInsert(pos
, item
) )
137 wxFAIL_MSG(wxT("not implemented"));
142 void wxMenu::SetTitle(const wxString
& label
)
146 wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
150 wxMenuItem
*item
= node
->GetData ();
151 Widget widget
= (Widget
) item
->GetButtonWidget();
155 wxXmString
title_str(label
);
156 XtVaSetValues(widget
,
157 XmNlabelString
, title_str(),
161 bool wxMenu::ProcessCommand(wxCommandEvent
& event
)
163 bool processed
= FALSE
;
165 #if WXWIN_COMPATIBILITY
169 (void) (*(m_callback
)) (*this, event
);
172 #endif // WXWIN_COMPATIBILITY
174 // Try the menu's event handler
175 if ( !processed
&& GetEventHandler())
177 processed
= GetEventHandler()->ProcessEvent(event
);
179 // Try the window the menu was popped up from (and up
180 // through the hierarchy)
181 if ( !processed
&& GetInvokingWindow())
182 processed
= GetInvokingWindow()->ProcessEvent(event
);
187 // ----------------------------------------------------------------------------
189 // ----------------------------------------------------------------------------
191 void wxMenuBar::Init()
193 m_eventHandler
= this;
194 m_menuBarFrame
= NULL
;
195 m_mainWidget
= (WXWidget
) NULL
;
196 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENU
);
197 m_foregroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENUTEXT
);
198 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
201 wxMenuBar::wxMenuBar(int n
, wxMenu
*menus
[], const wxString titles
[])
205 for ( int i
= 0; i
< n
; i
++ )
207 m_menus
.Append(menus
[i
]);
208 m_titles
.Add(titles
[i
]);
212 wxMenuBar::~wxMenuBar()
214 // nothing to do: wxMenuBarBase will delete the menus
217 void wxMenuBar::EnableTop(size_t WXUNUSED(pos
), bool WXUNUSED(flag
))
222 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
224 wxMenu
*menu
= GetMenu(pos
);
228 Widget w
= (Widget
)menu
->GetButtonWidget();
231 wxXmString
label_str(label
);
234 XmNlabelString
, label_str(),
239 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
243 wxMenu
*menu
= GetMenu(pos
);
246 Widget w
= (Widget
)menu
->GetButtonWidget();
251 XmNlabelString
, &text
,
255 if ( XmStringGetLtoR(text
, XmSTRING_DEFAULT_CHARSET
, &s
) )
267 bool wxMenuBar::Append(wxMenu
* menu
, const wxString
& title
)
269 wxCHECK_MSG( menu
, FALSE
, wxT("invalid menu") );
270 wxCHECK_MSG( !menu
->GetParent() && !menu
->GetButtonWidget(), FALSE
,
271 wxT("menu already appended") );
273 if ( m_menuBarFrame
)
275 WXWidget w
= menu
->CreateMenu(this, GetMainWidget(), menu
, title
, TRUE
);
276 wxCHECK_MSG( w
, FALSE
, wxT("failed to create menu") );
277 menu
->SetButtonWidget(w
);
280 menu
->SetMenuBar(this);
284 return wxMenuBarBase::Append(menu
, title
);
287 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
289 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
292 wxFAIL_MSG(wxT("TODO"));
297 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
299 if ( !wxMenuBarBase::Replace(pos
, menu
, title
) )
302 wxFAIL_MSG(wxT("TODO"));
307 wxMenu
*wxMenuBar::Remove(size_t pos
)
309 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
313 if ( m_menuBarFrame
)
314 menu
->DestroyMenu(TRUE
);
316 menu
->SetMenuBar(NULL
);
318 m_titles
.Remove(pos
);
323 // Find the menu menuString, item itemString, and return the item id.
324 // Returns -1 if none found.
325 int wxMenuBar::FindMenuItem (const wxString
& menuString
, const wxString
& itemString
) const
329 wxStripMenuCodes ((char *)(const char *)menuString
, buf1
);
331 size_t menuCount
= GetMenuCount();
332 for (size_t i
= 0; i
< menuCount
; i
++)
334 wxStripMenuCodes ((char *)(const char *)m_titles
[i
], buf2
);
335 if (strcmp (buf1
, buf2
) == 0)
336 return m_menus
[i
]->FindItem (itemString
);
341 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
** itemMenu
) const
346 wxMenuItem
*item
= NULL
;
347 size_t menuCount
= GetMenuCount();
348 for (size_t i
= 0; i
< menuCount
; i
++)
349 if ((item
= m_menus
[i
]->FindItem(id
, itemMenu
)))
355 bool wxMenuBar::CreateMenuBar(wxFrame
* parent
)
359 XtVaSetValues((Widget
) parent
->GetMainWindowWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
361 if (!XtIsManaged((Widget) m_mainWidget))
362 XtManageChild((Widget) m_mainWidget);
364 XtMapWidget((Widget
) m_mainWidget
);
368 Widget menuBarW
= XmCreateMenuBar ((Widget
) parent
->GetMainWindowWidget(), "MenuBar", NULL
, 0);
369 m_mainWidget
= (WXWidget
) menuBarW
;
371 size_t menuCount
= GetMenuCount();
372 for (size_t i
= 0; i
< menuCount
; i
++)
374 wxMenu
*menu
= GetMenu(i
);
375 wxString
title(m_titles
[i
]);
376 menu
->SetButtonWidget(menu
->CreateMenu (this, menuBarW
, menu
, title
, TRUE
));
378 if (strcmp (wxStripMenuCodes(title
), "Help") == 0)
379 XtVaSetValues ((Widget
) menuBarW
, XmNmenuHelpWidget
, (Widget
) menu
->GetButtonWidget(), NULL
);
381 // tear off menu support
382 #if (XmVersion >= 1002)
383 if ( menu
->IsTearOff() )
385 XtVaSetValues(GetWidget(menu
),
386 XmNtearOffModel
, XmTEAR_OFF_ENABLED
,
392 SetBackgroundColour(m_backgroundColour
);
393 SetForegroundColour(m_foregroundColour
);
396 XtVaSetValues((Widget
) parent
->GetMainWindowWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
397 XtRealizeWidget ((Widget
) menuBarW
);
398 XtManageChild ((Widget
) menuBarW
);
399 SetMenuBarFrame(parent
);
404 // Destroy menubar, but keep data structures intact so we can recreate it.
405 bool wxMenuBar::DestroyMenuBar()
409 SetMenuBarFrame((wxFrame
*) NULL
);
413 XtUnmanageChild ((Widget
) m_mainWidget
);
414 XtUnrealizeWidget ((Widget
) m_mainWidget
);
416 size_t menuCount
= GetMenuCount();
417 for (size_t i
= 0; i
< menuCount
; i
++)
419 wxMenu
*menu
= GetMenu(i
);
420 menu
->DestroyMenu(TRUE
);
423 XtDestroyWidget((Widget
) m_mainWidget
);
424 m_mainWidget
= (WXWidget
) 0;
426 SetMenuBarFrame((wxFrame
*) NULL
);
432 static XtWorkProcId WorkProcMenuId
;
434 /* Since PopupMenu under Motif stills grab right mouse button events
435 * after it was closed, we need to delete the associated widgets to
436 * allow next PopUpMenu to appear...
439 int PostDeletionOfMenu( XtPointer
* clientData
)
441 XtRemoveWorkProc(WorkProcMenuId
);
442 wxMenu
*menu
= (wxMenu
*)clientData
;
444 if (menu
->GetMainWidget())
446 wxMenu
*menuParent
= menu
->GetParent();
449 wxMenuItemList::Node
*node
= menuParent
->GetMenuItems().GetFirst();
452 if ( node
->GetData()->GetSubMenu() == menu
)
454 menuParent
->GetMenuItems().DeleteNode(node
);
459 node
= node
->GetNext();
463 menu
->DestroyMenu(TRUE
);
466 // Mark as no longer popped up
473 wxMenuPopdownCallback(Widget
WXUNUSED(w
), XtPointer clientData
,
474 XtPointer
WXUNUSED(ptr
))
476 wxMenu
*menu
= (wxMenu
*)clientData
;
478 // Added by JOREL Jean-Charles <jjorel@silr.ireste.fr>
479 /* Since Callbacks of MenuItems are not yet processed, we put a
480 * background job which will be done when system will be idle.
481 * What awful hack!! :(
484 WorkProcMenuId
= XtAppAddWorkProc(
485 (XtAppContext
) wxTheApp
->GetAppContext(),
486 (XtWorkProc
) PostDeletionOfMenu
,
488 // Apparently not found in Motif headers
489 // XtVaSetValues( w, XmNpopupEnabled, XmPOPUP_DISABLED, NULL );
493 * Create a popup or pulldown menu.
494 * Submenus of a popup will be pulldown.
498 WXWidget
wxMenu::CreateMenu (wxMenuBar
* menuBar
, WXWidget parent
, wxMenu
* topMenu
, const wxString
& title
, bool pullDown
)
500 Widget menu
= (Widget
) 0;
501 Widget buttonWidget
= (Widget
) 0;
503 XtSetArg (args
[0], XmNnumColumns
, m_numColumns
);
504 XtSetArg (args
[1], XmNpacking
, XmPACK_COLUMN
);
508 menu
= XmCreatePopupMenu ((Widget
) parent
, "popup", args
, 2);
511 (XtCallbackProc
)wxMenuPopdownCallback
,
516 char mnem
= wxFindMnemonic (title
);
517 wxStripMenuCodes ((char*) (const char*) title
, wxBuffer
);
519 menu
= XmCreatePulldownMenu ((Widget
) parent
, "pulldown", args
, 2);
521 wxString
title2(wxStripMenuCodes(title
));
522 wxXmString
label_str(title2
);
523 buttonWidget
= XtVaCreateManagedWidget(title2
,
525 xmCascadeButtonGadgetClass
, (Widget
) parent
,
527 xmCascadeButtonWidgetClass
, (Widget
) parent
,
529 XmNlabelString
, label_str(),
534 XtVaSetValues (buttonWidget
, XmNmnemonic
, mnem
, NULL
);
537 m_menuWidget
= (WXWidget
) menu
;
540 m_topLevelMenu
= topMenu
;
542 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
544 node
= node
->GetNext() )
546 wxMenuItem
*item
= node
->GetData();
548 item
->CreateItem(menu
, menuBar
, topMenu
);
551 SetBackgroundColour(m_backgroundColour
);
552 SetForegroundColour(m_foregroundColour
);
558 // Destroys the Motif implementation of the menu,
559 // but maintains the wxWindows data structures so we can
560 // do a CreateMenu again.
561 void wxMenu::DestroyMenu (bool full
)
563 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
565 node
= node
->GetNext() )
567 wxMenuItem
*item
= node
->GetData();
568 item
->SetMenuBar((wxMenuBar
*) NULL
);
570 item
->DestroyItem(full
);
577 XtVaSetValues((Widget
) m_buttonWidget
, XmNsubMenuId
, NULL
, NULL
);
578 XtDestroyWidget ((Widget
) m_buttonWidget
);
579 m_buttonWidget
= (WXWidget
) 0;
582 if (m_menuWidget
&& full
)
584 XtDestroyWidget((Widget
) m_menuWidget
);
585 m_menuWidget
= (WXWidget
) NULL
;
589 WXWidget
wxMenu::FindMenuItem (int id
, wxMenuItem
** it
) const
594 *it
= (wxMenuItem
*) NULL
;
595 return m_buttonWidget
;
598 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
600 node
= node
->GetNext() )
602 wxMenuItem
*item
= node
->GetData ();
603 if (item
->GetId() == id
)
607 return item
->GetButtonWidget();
610 if (item
->GetSubMenu())
612 WXWidget w
= item
->GetSubMenu()->FindMenuItem (id
, it
);
621 *it
= (wxMenuItem
*) NULL
;
622 return (WXWidget
) NULL
;
625 void wxMenu::SetBackgroundColour(const wxColour
& col
)
627 m_backgroundColour
= col
;
629 wxDoChangeBackgroundColour(m_menuWidget
, (wxColour
&) col
);
631 wxDoChangeBackgroundColour(m_buttonWidget
, (wxColour
&) col
, TRUE
);
633 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
635 node
= node
->GetNext() )
637 wxMenuItem
* item
= node
->GetData();
638 if (item
->GetButtonWidget())
640 // This crashes because it uses gadgets
641 // wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, TRUE);
643 if (item
->GetSubMenu())
644 item
->GetSubMenu()->SetBackgroundColour((wxColour
&) col
);
648 void wxMenu::SetForegroundColour(const wxColour
& col
)
650 m_foregroundColour
= col
;
652 wxDoChangeForegroundColour(m_menuWidget
, (wxColour
&) col
);
654 wxDoChangeForegroundColour(m_buttonWidget
, (wxColour
&) col
);
656 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
658 node
= node
->GetNext() )
660 wxMenuItem
* item
= node
->GetData();
661 if (item
->GetButtonWidget())
663 // This crashes because it uses gadgets
664 // wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
666 if (item
->GetSubMenu())
667 item
->GetSubMenu()->SetForegroundColour((wxColour
&) col
);
671 void wxMenu::ChangeFont(bool keepOriginalSize
)
673 // lesstif 0.87 hangs when setting XmNfontList
674 #ifndef LESSTIF_VERSION
675 if (!m_font
.Ok() || !m_menuWidget
)
678 XmFontList fontList
= (XmFontList
) m_font
.GetFontList(1.0, XtDisplay((Widget
) m_menuWidget
));
680 XtVaSetValues ((Widget
) m_menuWidget
,
681 XmNfontList
, fontList
,
685 XtVaSetValues ((Widget
) m_buttonWidget
,
686 XmNfontList
, fontList
,
690 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
692 node
= node
->GetNext() )
694 wxMenuItem
* item
= node
->GetData();
695 if (m_menuWidget
&& item
->GetButtonWidget() && m_font
.Ok())
697 XtVaSetValues ((Widget
) item
->GetButtonWidget(),
698 XmNfontList
, fontList
,
701 if (item
->GetSubMenu())
702 item
->GetSubMenu()->ChangeFont(keepOriginalSize
);
707 void wxMenu::SetFont(const wxFont
& font
)
713 bool wxMenuBar::SetBackgroundColour(const wxColour
& col
)
715 m_backgroundColour
= col
;
717 wxDoChangeBackgroundColour(m_mainWidget
, (wxColour
&) col
);
719 size_t menuCount
= GetMenuCount();
720 for (size_t i
= 0; i
< menuCount
; i
++)
721 m_menus
[i
]->SetBackgroundColour((wxColour
&) col
);
726 bool wxMenuBar::SetForegroundColour(const wxColour
& col
)
728 m_foregroundColour
= col
;
730 wxDoChangeForegroundColour(m_mainWidget
, (wxColour
&) col
);
732 size_t menuCount
= GetMenuCount();
733 for (size_t i
= 0; i
< menuCount
; i
++)
734 m_menus
[i
]->SetForegroundColour((wxColour
&) col
);
739 void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize
))
741 // Nothing to do for menubar, fonts are kept in wxMenus
744 bool wxMenuBar::SetFont(const wxFont
& font
)
749 size_t menuCount
= GetMenuCount();
750 for (size_t i
= 0; i
< menuCount
; i
++)
751 m_menus
[i
]->SetFont(font
);