1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
30 #include "wx/settings.h"
33 #include "wx/menuitem.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;
81 if ( !m_title
.empty() )
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
)
119 return DoInsert(GetMenuItemCount(), pItem
);
122 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
124 item
->DestroyItem(true);
126 return wxMenuBase::DoRemove(item
);
129 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
133 // this is a dynamic Append
134 #ifndef XmNpositionIndex
135 wxCHECK_MSG( pos
== GetMenuItemCount(), -1, wxT("insert not implemented"));
137 item
->CreateItem(m_menuWidget
, GetMenuBar(), m_topLevelMenu
, pos
);
140 if ( item
->IsSubMenu() )
142 item
->GetSubMenu()->m_topLevelMenu
= m_topLevelMenu
;
145 return pos
== GetMenuItemCount() ? wxMenuBase::DoAppend(item
) :
146 wxMenuBase::DoInsert(pos
, item
);
149 void wxMenu::SetTitle(const wxString
& label
)
153 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
157 wxMenuItem
*item
= node
->GetData ();
158 Widget widget
= (Widget
) item
->GetButtonWidget();
162 wxXmString
title_str(label
);
163 XtVaSetValues(widget
,
164 XmNlabelString
, title_str(),
168 bool wxMenu::ProcessCommand(wxCommandEvent
& event
)
170 bool processed
= false;
172 // Try the menu's event handler
173 if ( !processed
&& GetEventHandler())
175 processed
= GetEventHandler()->ProcessEvent(event
);
177 // Try the window the menu was popped up from (and up
178 // through the hierarchy)
179 if ( !processed
&& GetInvokingWindow())
180 processed
= GetInvokingWindow()->ProcessEvent(event
);
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 void wxMenuBar::Init()
191 m_eventHandler
= this;
192 m_menuBarFrame
= NULL
;
193 m_mainWidget
= (WXWidget
) NULL
;
194 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENU
);
195 m_foregroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_MENUTEXT
);
196 m_font
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
199 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxArrayString
& titles
, long WXUNUSED(style
))
201 wxASSERT( n
== titles
.GetCount() );
206 for ( size_t i
= 0; i
< n
; i
++ )
207 m_menus
.Append(menus
[i
]);
210 wxMenuBar::wxMenuBar(size_t n
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
214 for ( size_t i
= 0; i
< n
; i
++ )
216 m_menus
.Append(menus
[i
]);
217 m_titles
.Add(titles
[i
]);
221 wxMenuBar::~wxMenuBar()
223 // nothing to do: wxMenuBarBase will delete the menus
226 void wxMenuBar::EnableTop(size_t WXUNUSED(pos
), bool WXUNUSED(flag
))
228 // wxFAIL_MSG("TODO");
229 // wxLogWarning("wxMenuBar::EnableTop not yet implemented.");
232 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
234 wxMenu
*menu
= GetMenu(pos
);
238 Widget w
= (Widget
)menu
->GetButtonWidget();
241 wxXmString
label_str(label
);
244 XmNlabelString
, label_str(),
249 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
251 wxMenu
*menu
= GetMenu(pos
);
254 Widget w
= (Widget
)menu
->GetButtonWidget();
259 XmNlabelString
, &text
,
262 return wxXmStringToString( text
);
266 return wxEmptyString
;
269 bool wxMenuBar::Append(wxMenu
* menu
, const wxString
& title
)
271 return Insert(GetMenuCount(), menu
, title
);
274 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
276 wxCHECK_MSG( pos
<= GetMenuCount(), false, wxT("invalid position") );
277 wxCHECK_MSG( menu
, false, wxT("invalid menu") );
278 wxCHECK_MSG( !menu
->GetParent() && !menu
->GetButtonWidget(), false,
279 wxT("menu already appended") );
281 if ( m_menuBarFrame
)
283 WXWidget w
= menu
->CreateMenu(this, GetMainWidget(), menu
,
285 wxCHECK_MSG( w
, false, wxT("failed to create menu") );
286 menu
->SetButtonWidget(w
);
289 m_titles
.Insert(title
, pos
);
291 return wxMenuBarBase::Insert(pos
, menu
, title
);
294 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
296 if ( !wxMenuBarBase::Replace(pos
, menu
, title
) )
299 wxFAIL_MSG(wxT("TODO"));
304 wxMenu
*wxMenuBar::Remove(size_t pos
)
306 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
310 if ( m_menuBarFrame
)
311 menu
->DestroyMenu(true);
313 menu
->SetMenuBar(NULL
);
315 m_titles
.RemoveAt(pos
);
320 // Find the menu menuString, item itemString, and return the item id.
321 // Returns -1 if none found.
322 int wxMenuBar::FindMenuItem (const wxString
& menuString
, const wxString
& itemString
) const
326 wxStripMenuCodes (wxConstCast(menuString
.c_str(), char), buf1
);
328 size_t menuCount
= GetMenuCount();
329 for (size_t i
= 0; i
< menuCount
; i
++)
331 wxStripMenuCodes (wxConstCast(m_titles
[i
].c_str(), char), buf2
);
332 if (strcmp (buf1
, buf2
) == 0)
333 return m_menus
.Item(i
)->GetData()->FindItem (itemString
);
338 wxMenuItem
*wxMenuBar::FindItem(int id
, wxMenu
** itemMenu
) const
343 size_t menuCount
= GetMenuCount();
344 for (size_t i
= 0; i
< menuCount
; i
++)
346 wxMenuItem
*item
= m_menus
.Item(i
)->GetData()->FindItem(id
, itemMenu
);
347 if (item
) return item
;
354 bool wxMenuBar::CreateMenuBar(wxFrame
* parent
)
358 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
360 if (!XtIsManaged((Widget) m_mainWidget))
361 XtManageChild((Widget) m_mainWidget);
363 XtMapWidget((Widget
) m_mainWidget
);
367 Widget menuBarW
= XmCreateMenuBar ((Widget
) parent
->GetMainWidget(),
368 wxMOTIF_STR("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
, i
, 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
,
388 Widget tearOff
= XmGetTearOffControl(GetWidget(menu
));
389 wxDoChangeForegroundColour((Widget
) tearOff
, m_foregroundColour
);
390 wxDoChangeBackgroundColour((Widget
) tearOff
, m_backgroundColour
, true);
395 SetBackgroundColour(m_backgroundColour
);
396 SetForegroundColour(m_foregroundColour
);
399 XtVaSetValues((Widget
) parent
->GetMainWidget(), XmNmenuBar
, (Widget
) m_mainWidget
, NULL
);
400 XtRealizeWidget ((Widget
) menuBarW
);
401 XtManageChild ((Widget
) menuBarW
);
402 SetMenuBarFrame(parent
);
407 // Destroy menubar, but keep data structures intact so we can recreate it.
408 bool wxMenuBar::DestroyMenuBar()
412 SetMenuBarFrame((wxFrame
*) NULL
);
416 XtUnmanageChild ((Widget
) m_mainWidget
);
417 XtUnrealizeWidget ((Widget
) m_mainWidget
);
419 size_t menuCount
= GetMenuCount();
420 for (size_t i
= 0; i
< menuCount
; i
++)
422 wxMenu
*menu
= GetMenu(i
);
423 menu
->DestroyMenu(true);
426 XtDestroyWidget((Widget
) m_mainWidget
);
427 m_mainWidget
= (WXWidget
) 0;
429 SetMenuBarFrame((wxFrame
*) NULL
);
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...
437 void wxMenu::DestroyWidgetAndDetach()
441 wxMenu
*menuParent
= GetParent();
444 wxMenuItemList::compatibility_iterator node
= menuParent
->GetMenuItems().GetFirst();
447 if ( node
->GetData()->GetSubMenu() == this )
449 delete node
->GetData();
450 menuParent
->GetMenuItems().Erase(node
);
455 node
= node
->GetNext();
462 // Mark as no longer popped up
467 * Create a popup or pulldown menu.
468 * Submenus of a popup will be pulldown.
472 WXWidget
wxMenu::CreateMenu (wxMenuBar
* menuBar
,
475 size_t WXUNUSED(index
),
476 const wxString
& title
,
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
;
521 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
523 node
= node
->GetNext(), ++i
)
525 wxMenuItem
*item
= node
->GetData();
527 item
->CreateItem(menu
, menuBar
, topMenu
, i
);
530 SetBackgroundColour(m_backgroundColour
);
531 SetForegroundColour(m_foregroundColour
);
537 // Destroys the Motif implementation of the menu,
538 // but maintains the wxWidgets data structures so we can
539 // do a CreateMenu again.
540 void wxMenu::DestroyMenu (bool full
)
542 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
544 node
= node
->GetNext() )
546 wxMenuItem
*item
= node
->GetData();
547 item
->SetMenuBar((wxMenuBar
*) NULL
);
549 item
->DestroyItem(full
);
556 XtVaSetValues((Widget
) m_buttonWidget
, XmNsubMenuId
, NULL
, NULL
);
557 XtDestroyWidget ((Widget
) m_buttonWidget
);
558 m_buttonWidget
= (WXWidget
) 0;
561 if (m_menuWidget
&& full
)
563 XtDestroyWidget((Widget
) m_menuWidget
);
564 m_menuWidget
= (WXWidget
) NULL
;
568 WXWidget
wxMenu::FindMenuItem (int id
, wxMenuItem
** it
) const
573 *it
= (wxMenuItem
*) NULL
;
574 return m_buttonWidget
;
577 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
579 node
= node
->GetNext() )
581 wxMenuItem
*item
= node
->GetData ();
582 if (item
->GetId() == id
)
586 return item
->GetButtonWidget();
589 if (item
->GetSubMenu())
591 WXWidget w
= item
->GetSubMenu()->FindMenuItem (id
, it
);
600 *it
= (wxMenuItem
*) NULL
;
601 return (WXWidget
) NULL
;
604 void wxMenu::SetBackgroundColour(const wxColour
& col
)
606 m_backgroundColour
= col
;
608 wxDoChangeBackgroundColour(m_menuWidget
, (wxColour
&) col
);
610 wxDoChangeBackgroundColour(m_buttonWidget
, (wxColour
&) col
, true);
612 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
614 node
= node
->GetNext() )
616 wxMenuItem
* item
= node
->GetData();
617 if (item
->GetButtonWidget())
619 // This crashes because it uses gadgets
620 // wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, true);
622 if (item
->GetSubMenu())
623 item
->GetSubMenu()->SetBackgroundColour((wxColour
&) col
);
627 void wxMenu::SetForegroundColour(const wxColour
& col
)
629 m_foregroundColour
= col
;
631 wxDoChangeForegroundColour(m_menuWidget
, (wxColour
&) col
);
633 wxDoChangeForegroundColour(m_buttonWidget
, (wxColour
&) col
);
635 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
637 node
= node
->GetNext() )
639 wxMenuItem
* item
= node
->GetData();
640 if (item
->GetButtonWidget())
642 // This crashes because it uses gadgets
643 // wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
645 if (item
->GetSubMenu())
646 item
->GetSubMenu()->SetForegroundColour((wxColour
&) col
);
650 void wxMenu::ChangeFont(bool keepOriginalSize
)
652 // Lesstif 0.87 hangs here, but 0.93 does not; MBN: sometimes it does
653 #if !wxCHECK_LESSTIF() // || wxCHECK_LESSTIF_VERSION( 0, 93 )
654 if (!m_font
.Ok() || !m_menuWidget
)
657 Display
* dpy
= XtDisplay((Widget
) m_menuWidget
);
659 XtVaSetValues ((Widget
) m_menuWidget
,
660 wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
),
664 XtVaSetValues ((Widget
) m_buttonWidget
,
665 wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
),
669 for ( wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
671 node
= node
->GetNext() )
673 wxMenuItem
* item
= node
->GetData();
674 if (m_menuWidget
&& item
->GetButtonWidget() && m_font
.Ok())
676 XtVaSetValues ((Widget
) item
->GetButtonWidget(),
677 wxFont::GetFontTag(), m_font
.GetFontTypeC(dpy
),
680 if (item
->GetSubMenu())
681 item
->GetSubMenu()->ChangeFont(keepOriginalSize
);
684 wxUnusedVar(keepOriginalSize
);
688 void wxMenu::SetFont(const wxFont
& font
)
694 bool wxMenuBar::SetBackgroundColour(const wxColour
& col
)
696 m_backgroundColour
= col
;
698 wxDoChangeBackgroundColour(m_mainWidget
, (wxColour
&) col
);
700 size_t menuCount
= GetMenuCount();
701 for (size_t i
= 0; i
< menuCount
; i
++)
702 m_menus
.Item(i
)->GetData()->SetBackgroundColour((wxColour
&) col
);
707 bool wxMenuBar::SetForegroundColour(const wxColour
& col
)
709 m_foregroundColour
= col
;
711 wxDoChangeForegroundColour(m_mainWidget
, (wxColour
&) col
);
713 size_t menuCount
= GetMenuCount();
714 for (size_t i
= 0; i
< menuCount
; i
++)
715 m_menus
.Item(i
)->GetData()->SetForegroundColour((wxColour
&) col
);
720 void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize
))
722 // Nothing to do for menubar, fonts are kept in wxMenus
725 bool wxMenuBar::SetFont(const wxFont
& font
)
730 size_t menuCount
= GetMenuCount();
731 for (size_t i
= 0; i
< menuCount
; i
++)
732 m_menus
.Item(i
)->GetData()->SetFont(font
);