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 #pragma message disable nosimpint
35 #define XtDisplay XTDISPLAY
36 #define XtWindow XTWINDOW
39 #include <Xm/LabelG.h>
40 #include <Xm/CascadeBG.h>
41 #include <Xm/CascadeB.h>
42 #include <Xm/SeparatoG.h>
43 #include <Xm/PushBG.h>
44 #include <Xm/ToggleB.h>
45 #include <Xm/ToggleBG.h>
46 #include <Xm/RowColumn.h>
48 #pragma message enable nosimpint
51 #include "wx/motif/private.h"
53 // other standard headers
56 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
57 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxEvtHandler
)
59 // ============================================================================
61 // ============================================================================
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 // Construct a menu with optional title (then use append)
70 // Motif-specific members
72 m_menuWidget
= (WXWidget
) NULL
;
73 m_popupShell
= (WXWidget
) NULL
;
74 m_buttonWidget
= (WXWidget
) NULL
;
76 m_topLevelMenu
= (wxMenu
*) NULL
;
77 m_ownedByMenuBar
= FALSE
;
81 Append(wxID_SEPARATOR
, m_title
) ;
85 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENU
);
86 m_foregroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENUTEXT
);
87 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
90 // The wxWindow destructor will take care of deleting the submenus.
101 // Not sure if this is right
102 if (m_menuParent
&& m_menuBar
)
114 // function appends a new item or submenu to the menu
115 bool wxMenu::DoAppend(wxMenuItem
*pItem
)
119 // this is a dynamic Append
120 pItem
->CreateItem(m_menuWidget
, m_menuBar
, m_topLevelMenu
);
123 if ( pItem
->IsSubMenu() )
125 pItem
->GetSubMenu()->m_topLevelMenu
= m_topLevelMenu
;
128 return wxMenuBase::DoAppend(pItem
);
131 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
133 item
->DestroyItem(TRUE
);
135 return wxMenuBase::DoRemove(item
);
138 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
140 if ( !wxMenuBase::DoInsert(pos
, item
) )
143 wxFAIL_MSG(wxT("not implemented"));
148 void wxMenu::SetTitle(const wxString
& label
)
152 wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
156 wxMenuItem
*item
= node
->GetData ();
157 Widget widget
= (Widget
) item
->GetButtonWidget();
161 wxXmString
title_str(label
);
162 XtVaSetValues(widget
,
163 XmNlabelString
, title_str(),
167 bool wxMenu::ProcessCommand(wxCommandEvent
& event
)
169 bool processed
= FALSE
;
171 #if wxUSE_MENU_CALLBACK
175 (void) (*(m_callback
)) (*this, event
);
178 #endif // wxUSE_MENU_CALLBACK
180 // Try the menu's event handler
181 if ( !processed
&& GetEventHandler())
183 processed
= GetEventHandler()->ProcessEvent(event
);
185 // Try the window the menu was popped up from (and up
186 // through the hierarchy)
187 if ( !processed
&& GetInvokingWindow())
188 processed
= GetInvokingWindow()->ProcessEvent(event
);
193 // ----------------------------------------------------------------------------
195 // ----------------------------------------------------------------------------
197 void wxMenuBar::Init()
199 m_eventHandler
= this;
200 m_menuBarFrame
= NULL
;
201 m_mainWidget
= (WXWidget
) NULL
;
202 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENU
);
203 m_foregroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_MENUTEXT
);
204 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
207 wxMenuBar::wxMenuBar(int n
, wxMenu
*menus
[], const wxString titles
[])
211 for ( int i
= 0; i
< n
; i
++ )
213 m_menus
.Append(menus
[i
]);
214 m_titles
.Add(titles
[i
]);
218 wxMenuBar::~wxMenuBar()
220 // nothing to do: wxMenuBarBase will delete the menus
223 void wxMenuBar::EnableTop(size_t WXUNUSED(pos
), bool WXUNUSED(flag
))
225 // wxFAIL_MSG("TODO");
226 // wxLogWarning("wxMenuBar::EnableTop not yet implemented.");
229 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
231 wxMenu
*menu
= GetMenu(pos
);
235 Widget w
= (Widget
)menu
->GetButtonWidget();
238 wxXmString
label_str(label
);
241 XmNlabelString
, label_str(),
246 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
250 wxMenu
*menu
= GetMenu(pos
);
253 Widget w
= (Widget
)menu
->GetButtonWidget();
258 XmNlabelString
, &text
,
262 if ( XmStringGetLtoR(text
, XmSTRING_DEFAULT_CHARSET
, &s
) )
274 bool wxMenuBar::Append(wxMenu
* menu
, const wxString
& title
)
276 wxCHECK_MSG( menu
, FALSE
, wxT("invalid menu") );
277 wxCHECK_MSG( !menu
->GetParent() && !menu
->GetButtonWidget(), FALSE
,
278 wxT("menu already appended") );
280 if ( m_menuBarFrame
)
282 WXWidget w
= menu
->CreateMenu(this, GetMainWidget(), menu
, title
, TRUE
);
283 wxCHECK_MSG( w
, FALSE
, wxT("failed to create menu") );
284 menu
->SetButtonWidget(w
);
287 menu
->SetMenuBar(this);
291 return wxMenuBarBase::Append(menu
, title
);
294 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
296 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
299 wxFAIL_MSG(wxT("TODO"));
304 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
306 if ( !wxMenuBarBase::Replace(pos
, menu
, title
) )
309 wxFAIL_MSG(wxT("TODO"));
314 wxMenu
*wxMenuBar::Remove(size_t pos
)
316 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
320 if ( m_menuBarFrame
)
321 menu
->DestroyMenu(TRUE
);
323 menu
->SetMenuBar(NULL
);
325 m_titles
.Remove(pos
);
330 // Find the menu menuString, item itemString, and return the item id.
331 // Returns -1 if none found.
332 int wxMenuBar::FindMenuItem (const wxString
& menuString
, const wxString
& itemString
) const
336 wxStripMenuCodes ((char *)(const char *)menuString
, buf1
);
338 size_t menuCount
= GetMenuCount();
339 for (size_t i
= 0; i
< menuCount
; i
++)
341 wxStripMenuCodes ((char *)(const char *)m_titles
[i
], buf2
);
342 if (strcmp (buf1
, buf2
) == 0)
343 return m_menus
[i
]->FindItem (itemString
);
348 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
** itemMenu
) const
353 wxMenuItem
*item
= NULL
;
354 size_t menuCount
= GetMenuCount();
355 for (size_t i
= 0; i
< menuCount
; i
++)
356 if ((item
= m_menus
[i
]->FindItem(id
, itemMenu
)))
362 bool wxMenuBar::CreateMenuBar(wxFrame
* parent
)
366 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
368 if (!XtIsManaged((Widget) m_mainWidget))
369 XtManageChild((Widget) m_mainWidget);
371 XtMapWidget((Widget
) m_mainWidget
);
375 Widget menuBarW
= XmCreateMenuBar ((Widget
) parent
->GetMainWidget(), "MenuBar", NULL
, 0);
376 m_mainWidget
= (WXWidget
) menuBarW
;
378 size_t menuCount
= GetMenuCount();
379 for (size_t i
= 0; i
< menuCount
; i
++)
381 wxMenu
*menu
= GetMenu(i
);
382 wxString
title(m_titles
[i
]);
383 menu
->SetButtonWidget(menu
->CreateMenu (this, menuBarW
, menu
, title
, TRUE
));
385 if (strcmp (wxStripMenuCodes(title
), "Help") == 0)
386 XtVaSetValues ((Widget
) menuBarW
, XmNmenuHelpWidget
, (Widget
) menu
->GetButtonWidget(), NULL
);
388 // tear off menu support
389 #if (XmVersion >= 1002)
390 if ( menu
->IsTearOff() )
392 XtVaSetValues(GetWidget(menu
),
393 XmNtearOffModel
, XmTEAR_OFF_ENABLED
,
395 Widget tearOff
= XmGetTearOffControl(GetWidget(menu
));
396 wxDoChangeForegroundColour((Widget
) tearOff
, m_foregroundColour
);
397 wxDoChangeBackgroundColour((Widget
) tearOff
, m_backgroundColour
, TRUE
);
402 SetBackgroundColour(m_backgroundColour
);
403 SetForegroundColour(m_foregroundColour
);
406 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
407 XtRealizeWidget ((Widget
) menuBarW
);
408 XtManageChild ((Widget
) menuBarW
);
409 SetMenuBarFrame(parent
);
414 // Destroy menubar, but keep data structures intact so we can recreate it.
415 bool wxMenuBar::DestroyMenuBar()
419 SetMenuBarFrame((wxFrame
*) NULL
);
423 XtUnmanageChild ((Widget
) m_mainWidget
);
424 XtUnrealizeWidget ((Widget
) m_mainWidget
);
426 size_t menuCount
= GetMenuCount();
427 for (size_t i
= 0; i
< menuCount
; i
++)
429 wxMenu
*menu
= GetMenu(i
);
430 menu
->DestroyMenu(TRUE
);
433 XtDestroyWidget((Widget
) m_mainWidget
);
434 m_mainWidget
= (WXWidget
) 0;
436 SetMenuBarFrame((wxFrame
*) NULL
);
442 static XtWorkProcId WorkProcMenuId
;
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...
449 int PostDeletionOfMenu( XtPointer
* clientData
)
451 XtRemoveWorkProc(WorkProcMenuId
);
452 wxMenu
*menu
= (wxMenu
*)clientData
;
454 if (menu
->GetMainWidget())
456 wxMenu
*menuParent
= menu
->GetParent();
459 wxMenuItemList::Node
*node
= menuParent
->GetMenuItems().GetFirst();
462 if ( node
->GetData()->GetSubMenu() == menu
)
464 menuParent
->GetMenuItems().DeleteNode(node
);
469 node
= node
->GetNext();
473 menu
->DestroyMenu(TRUE
);
476 // Mark as no longer popped up
483 wxMenuPopdownCallback(Widget
WXUNUSED(w
), XtPointer clientData
,
484 XtPointer
WXUNUSED(ptr
))
486 wxMenu
*menu
= (wxMenu
*)clientData
;
488 // Added by JOREL Jean-Charles <jjorel@silr.ireste.fr>
489 /* Since Callbacks of MenuItems are not yet processed, we put a
490 * background job which will be done when system will be idle.
491 * What awful hack!! :(
494 WorkProcMenuId
= XtAppAddWorkProc(
495 (XtAppContext
) wxTheApp
->GetAppContext(),
496 (XtWorkProc
) PostDeletionOfMenu
,
498 // Apparently not found in Motif headers
499 // XtVaSetValues( w, XmNpopupEnabled, XmPOPUP_DISABLED, NULL );
503 * Create a popup or pulldown menu.
504 * Submenus of a popup will be pulldown.
508 WXWidget
wxMenu::CreateMenu (wxMenuBar
* menuBar
, WXWidget parent
, wxMenu
* topMenu
, const wxString
& title
, bool pullDown
)
510 Widget menu
= (Widget
) 0;
511 Widget buttonWidget
= (Widget
) 0;
513 XtSetArg (args
[0], XmNnumColumns
, m_numColumns
);
514 XtSetArg (args
[1], XmNpacking
, XmPACK_COLUMN
);
518 menu
= XmCreatePopupMenu ((Widget
) parent
, "popup", args
, 2);
521 (XtCallbackProc
)wxMenuPopdownCallback
,
526 char mnem
= wxFindMnemonic (title
);
527 wxStripMenuCodes ((char*) (const char*) title
, wxBuffer
);
529 menu
= XmCreatePulldownMenu ((Widget
) parent
, "pulldown", args
, 2);
531 wxString
title2(wxStripMenuCodes(title
));
532 wxXmString
label_str(title2
);
533 buttonWidget
= XtVaCreateManagedWidget(title2
,
535 xmCascadeButtonGadgetClass
, (Widget
) parent
,
537 xmCascadeButtonWidgetClass
, (Widget
) parent
,
539 XmNlabelString
, label_str(),
544 XtVaSetValues (buttonWidget
, XmNmnemonic
, mnem
, NULL
);
547 m_menuWidget
= (WXWidget
) menu
;
550 m_topLevelMenu
= topMenu
;
552 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
554 node
= node
->GetNext() )
556 wxMenuItem
*item
= node
->GetData();
558 item
->CreateItem(menu
, menuBar
, topMenu
);
561 SetBackgroundColour(m_backgroundColour
);
562 SetForegroundColour(m_foregroundColour
);
568 // Destroys the Motif implementation of the menu,
569 // but maintains the wxWindows data structures so we can
570 // do a CreateMenu again.
571 void wxMenu::DestroyMenu (bool full
)
573 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
575 node
= node
->GetNext() )
577 wxMenuItem
*item
= node
->GetData();
578 item
->SetMenuBar((wxMenuBar
*) NULL
);
580 item
->DestroyItem(full
);
587 XtVaSetValues((Widget
) m_buttonWidget
, XmNsubMenuId
, NULL
, NULL
);
588 XtDestroyWidget ((Widget
) m_buttonWidget
);
589 m_buttonWidget
= (WXWidget
) 0;
592 if (m_menuWidget
&& full
)
594 XtDestroyWidget((Widget
) m_menuWidget
);
595 m_menuWidget
= (WXWidget
) NULL
;
599 WXWidget
wxMenu::FindMenuItem (int id
, wxMenuItem
** it
) const
604 *it
= (wxMenuItem
*) NULL
;
605 return m_buttonWidget
;
608 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
610 node
= node
->GetNext() )
612 wxMenuItem
*item
= node
->GetData ();
613 if (item
->GetId() == id
)
617 return item
->GetButtonWidget();
620 if (item
->GetSubMenu())
622 WXWidget w
= item
->GetSubMenu()->FindMenuItem (id
, it
);
631 *it
= (wxMenuItem
*) NULL
;
632 return (WXWidget
) NULL
;
635 void wxMenu::SetBackgroundColour(const wxColour
& col
)
637 m_backgroundColour
= col
;
639 wxDoChangeBackgroundColour(m_menuWidget
, (wxColour
&) col
);
641 wxDoChangeBackgroundColour(m_buttonWidget
, (wxColour
&) col
, TRUE
);
643 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
645 node
= node
->GetNext() )
647 wxMenuItem
* item
= node
->GetData();
648 if (item
->GetButtonWidget())
650 // This crashes because it uses gadgets
651 // wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, TRUE);
653 if (item
->GetSubMenu())
654 item
->GetSubMenu()->SetBackgroundColour((wxColour
&) col
);
658 void wxMenu::SetForegroundColour(const wxColour
& col
)
660 m_foregroundColour
= col
;
662 wxDoChangeForegroundColour(m_menuWidget
, (wxColour
&) col
);
664 wxDoChangeForegroundColour(m_buttonWidget
, (wxColour
&) col
);
666 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
668 node
= node
->GetNext() )
670 wxMenuItem
* item
= node
->GetData();
671 if (item
->GetButtonWidget())
673 // This crashes because it uses gadgets
674 // wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
676 if (item
->GetSubMenu())
677 item
->GetSubMenu()->SetForegroundColour((wxColour
&) col
);
681 void wxMenu::ChangeFont(bool keepOriginalSize
)
683 // lesstif 0.87 hangs when setting XmNfontList
684 #ifndef LESSTIF_VERSION
685 if (!m_font
.Ok() || !m_menuWidget
)
688 XmFontList fontList
= (XmFontList
) m_font
.GetFontList(1.0, XtDisplay((Widget
) m_menuWidget
));
690 XtVaSetValues ((Widget
) m_menuWidget
,
691 XmNfontList
, fontList
,
695 XtVaSetValues ((Widget
) m_buttonWidget
,
696 XmNfontList
, fontList
,
700 for ( wxMenuItemList::Node
*node
= GetMenuItems().GetFirst();
702 node
= node
->GetNext() )
704 wxMenuItem
* item
= node
->GetData();
705 if (m_menuWidget
&& item
->GetButtonWidget() && m_font
.Ok())
707 XtVaSetValues ((Widget
) item
->GetButtonWidget(),
708 XmNfontList
, fontList
,
711 if (item
->GetSubMenu())
712 item
->GetSubMenu()->ChangeFont(keepOriginalSize
);
717 void wxMenu::SetFont(const wxFont
& font
)
723 bool wxMenuBar::SetBackgroundColour(const wxColour
& col
)
725 m_backgroundColour
= col
;
727 wxDoChangeBackgroundColour(m_mainWidget
, (wxColour
&) col
);
729 size_t menuCount
= GetMenuCount();
730 for (size_t i
= 0; i
< menuCount
; i
++)
731 m_menus
[i
]->SetBackgroundColour((wxColour
&) col
);
736 bool wxMenuBar::SetForegroundColour(const wxColour
& col
)
738 m_foregroundColour
= col
;
740 wxDoChangeForegroundColour(m_mainWidget
, (wxColour
&) col
);
742 size_t menuCount
= GetMenuCount();
743 for (size_t i
= 0; i
< menuCount
; i
++)
744 m_menus
[i
]->SetForegroundColour((wxColour
&) col
);
749 void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize
))
751 // Nothing to do for menubar, fonts are kept in wxMenus
754 bool wxMenuBar::SetFont(const wxFont
& font
)
759 size_t menuCount
= GetMenuCount();
760 for (size_t i
= 0; i
< menuCount
; i
++)
761 m_menus
[i
]->SetFont(font
);