Files
wxWidgets/src/motif/menu.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

727 lines
19 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/motif/menu.cpp
// Purpose: wxMenu, wxMenuBar, wxMenuItem
// Author: Julian Smart
// Modified by:
// Created: 17/09/98
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/menu.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/app.h"
#include "wx/utils.h"
#include "wx/frame.h"
#include "wx/settings.h"
#include "wx/menuitem.h"
#endif
#ifdef __VMS__
#pragma message disable nosimpint
#endif
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/CascadeBG.h>
#include <Xm/CascadeB.h>
#include <Xm/SeparatoG.h>
#include <Xm/PushBG.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/RowColumn.h>
#ifdef __VMS__
#pragma message enable nosimpint
#endif
#include "wx/motif/private.h"
// other standard headers
#include <string.h>
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// Menus
// ----------------------------------------------------------------------------
// Construct a menu with optional title (then use append)
void wxMenu::Init()
{
// Motif-specific members
m_numColumns = 1;
m_menuWidget = (WXWidget) NULL;
m_popupShell = (WXWidget) NULL;
m_buttonWidget = (WXWidget) NULL;
m_menuId = 0;
m_topLevelMenu = NULL;
m_ownedByMenuBar = false;
if ( !m_title.empty() )
{
Append(-3, m_title) ;
AppendSeparator() ;
}
}
// The wxWindow destructor will take care of deleting the submenus.
wxMenu::~wxMenu()
{
if (m_menuWidget)
{
if (m_menuParent)
DestroyMenu(true);
else
DestroyMenu(false);
}
// Not sure if this is right
if (m_menuParent && m_menuBar)
{
m_menuParent = NULL;
// m_menuBar = NULL;
}
}
void wxMenu::Break()
{
m_numColumns++;
}
// function appends a new item or submenu to the menu
wxMenuItem* wxMenu::DoAppend(wxMenuItem *pItem)
{
return DoInsert(GetMenuItemCount(), pItem);
}
wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
{
item->DestroyItem(true);
return wxMenuBase::DoRemove(item);
}
wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
{
if (m_menuWidget)
{
// this is a dynamic Append
#ifndef XmNpositionIndex
wxCHECK_MSG( pos == GetMenuItemCount(), -1, wxT("insert not implemented"));
#endif
item->CreateItem(m_menuWidget, GetMenuBar(), m_topLevelMenu, pos);
}
if ( item->IsSubMenu() )
{
item->GetSubMenu()->m_topLevelMenu = m_topLevelMenu;
}
return pos == GetMenuItemCount() ? wxMenuBase::DoAppend(item) :
wxMenuBase::DoInsert(pos, item);
}
void wxMenu::SetTitle(const wxString& label)
{
m_title = label;
wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
if ( !node )
return;
wxMenuItem *item = node->GetData ();
Widget widget = (Widget) item->GetButtonWidget();
if ( !widget )
return;
wxXmString title_str(label);
XtVaSetValues(widget,
XmNlabelString, title_str(),
NULL);
}
bool wxMenu::ProcessCommand(wxCommandEvent & event)
{
// Try the menu's event handler first
wxEvtHandler * const handler = GetEventHandler();
bool processed = handler ? handler->SafelyProcessEvent(event) : false;
// Try the window the menu was popped up from (and up
// through the hierarchy)
if ( !processed && GetInvokingWindow())
processed = GetInvokingWindow()->HandleWindowEvent(event);
return processed;
}
// ----------------------------------------------------------------------------
// Menu Bar
// ----------------------------------------------------------------------------
void wxMenuBar::Init()
{
m_eventHandler = this;
m_menuBarFrame = NULL;
m_mainWidget = (WXWidget) NULL;
}
wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxArrayString& titles, long WXUNUSED(style))
{
wxASSERT( n == titles.GetCount() );
Init();
m_titles = titles;
for ( size_t i = 0; i < n; i++ )
m_menus.Append(menus[i]);
}
wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
{
Init();
for ( size_t i = 0; i < n; i++ )
{
m_menus.Append(menus[i]);
m_titles.Add(titles[i]);
}
}
wxMenuBar::~wxMenuBar()
{
// nothing to do: wxMenuBarBase will delete the menus
}
void wxMenuBar::EnableTop(size_t WXUNUSED(pos), bool WXUNUSED(flag))
{
// wxFAIL_MSG("TODO");
// wxLogWarning("wxMenuBar::EnableTop not yet implemented.");
}
void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
{
wxMenu *menu = GetMenu(pos);
if ( !menu )
return;
Widget w = (Widget)menu->GetButtonWidget();
if (w)
{
wxXmString label_str(label);
XtVaSetValues(w,
XmNlabelString, label_str(),
NULL);
}
m_titles[pos] = label;
}
wxString wxMenuBar::GetMenuLabel(size_t pos) const
{
wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
return m_titles[pos];
}
bool wxMenuBar::Append(wxMenu * menu, const wxString& title)
{
return Insert(GetMenuCount(), menu, title);
}
bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
{
wxCHECK_MSG( pos <= GetMenuCount(), false, wxT("invalid position") );
wxCHECK_MSG( menu, false, wxT("invalid menu") );
wxCHECK_MSG( !menu->GetParent() && !menu->GetButtonWidget(), false,
wxT("menu already appended") );
if ( m_menuBarFrame )
{
WXWidget w = menu->CreateMenu(this, GetMainWidget(), menu,
pos, title, true);
wxCHECK_MSG( w, false, wxT("failed to create menu") );
menu->SetButtonWidget(w);
}
m_titles.Insert(title, pos);
return wxMenuBarBase::Insert(pos, menu, title);
}
wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
{
if ( !wxMenuBarBase::Replace(pos, menu, title) )
return NULL;
wxFAIL_MSG(wxT("TODO"));
return NULL;
}
wxMenu *wxMenuBar::Remove(size_t pos)
{
wxMenu *menu = wxMenuBarBase::Remove(pos);
if ( !menu )
return NULL;
if ( m_menuBarFrame )
menu->DestroyMenu(true);
menu->SetMenuBar(NULL);
m_titles.RemoveAt(pos);
return menu;
}
// Find the menu menuString, item itemString, and return the item id.
// Returns -1 if none found.
int wxMenuBar::FindMenuItem(const wxString& menuString, const wxString& itemString) const
{
const wxString stripped = wxStripMenuCodes(menuString);
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
{
if ( wxStripMenuCodes(m_titles[i]) == stripped )
return m_menus.Item(i)->GetData()->FindItem (itemString);
}
return wxNOT_FOUND;
}
wxMenuItem *wxMenuBar::FindItem(int id, wxMenu ** itemMenu) const
{
if (itemMenu)
*itemMenu = NULL;
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
{
wxMenuItem *item = m_menus.Item(i)->GetData()->FindItem(id, itemMenu);
if (item) return item;
}
return NULL;
}
// Create menubar
bool wxMenuBar::CreateMenuBar(wxFrame* parent)
{
m_parent = parent; // bleach... override it!
PreCreation();
m_parent = NULL;
if (m_mainWidget)
{
XtVaSetValues((Widget) parent->GetMainWidget(), XmNmenuBar, (Widget) m_mainWidget, NULL);
/*
if (!XtIsManaged((Widget) m_mainWidget))
XtManageChild((Widget) m_mainWidget);
*/
XtMapWidget((Widget) m_mainWidget);
return true;
}
Widget menuBarW = XmCreateMenuBar ((Widget) parent->GetMainWidget(),
wxMOTIF_STR("MenuBar"), NULL, 0);
m_mainWidget = (WXWidget) menuBarW;
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
{
wxMenu *menu = GetMenu(i);
wxString title(m_titles[i]);
menu->SetButtonWidget(menu->CreateMenu (this, menuBarW, menu, i, title, true));
if (strcmp (wxStripMenuCodes(title), "Help") == 0)
XtVaSetValues ((Widget) menuBarW, XmNmenuHelpWidget, (Widget) menu->GetButtonWidget(), NULL);
// tear off menu support
#if (XmVersion >= 1002)
if ( menu->IsTearOff() )
{
XtVaSetValues(GetWidget(menu),
XmNtearOffModel, XmTEAR_OFF_ENABLED,
NULL);
Widget tearOff = XmGetTearOffControl(GetWidget(menu));
wxDoChangeForegroundColour((Widget) tearOff, m_foregroundColour);
wxDoChangeBackgroundColour((Widget) tearOff, m_backgroundColour, true);
}
#endif
}
PostCreation();
XtVaSetValues((Widget) parent->GetMainWidget(), XmNmenuBar, (Widget) m_mainWidget, NULL);
XtRealizeWidget ((Widget) menuBarW);
XtManageChild ((Widget) menuBarW);
SetMenuBarFrame(parent);
return true;
}
// Destroy menubar, but keep data structures intact so we can recreate it.
bool wxMenuBar::DestroyMenuBar()
{
if (!m_mainWidget)
{
SetMenuBarFrame(NULL);
return false;
}
XtUnmanageChild ((Widget) m_mainWidget);
XtUnrealizeWidget ((Widget) m_mainWidget);
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
{
wxMenu *menu = GetMenu(i);
menu->DestroyMenu(true);
}
XtDestroyWidget((Widget) m_mainWidget);
m_mainWidget = (WXWidget) 0;
SetMenuBarFrame(NULL);
return true;
}
// Since PopupMenu under Motif stills grab right mouse button events
// after it was closed, we need to delete the associated widgets to
// allow next PopUpMenu to appear...
void wxMenu::DestroyWidgetAndDetach()
{
if (GetMainWidget())
{
wxMenu *menuParent = GetParent();
if ( menuParent )
{
wxMenuItemList::compatibility_iterator node = menuParent->GetMenuItems().GetFirst();
while ( node )
{
if ( node->GetData()->GetSubMenu() == this )
{
delete node->GetData();
menuParent->GetMenuItems().Erase(node);
break;
}
node = node->GetNext();
}
}
DestroyMenu(true);
}
// Mark as no longer popped up
m_menuId = -1;
}
/*
* Create a popup or pulldown menu.
* Submenus of a popup will be pulldown.
*
*/
WXWidget wxMenu::CreateMenu (wxMenuBar * menuBar,
WXWidget parent,
wxMenu * topMenu,
size_t menuIndex,
const wxString& title,
bool pullDown)
{
Widget menu = (Widget) 0;
Widget buttonWidget = (Widget) 0;
Display* dpy = XtDisplay((Widget)parent);
Arg args[5];
XtSetArg (args[0], XmNnumColumns, m_numColumns);
XtSetArg (args[1], XmNpacking, (m_numColumns > 1) ? XmPACK_COLUMN : XmPACK_TIGHT);
if ( !m_font.IsOk() )
{
if ( menuBar )
m_font = menuBar->GetFont();
else if ( GetInvokingWindow() )
m_font = GetInvokingWindow()->GetFont();
}
XtSetArg (args[2], (String)wxFont::GetFontTag(), m_font.GetFontTypeC(dpy) );
if (!pullDown)
{
menu = XmCreatePopupMenu ((Widget) parent, wxMOTIF_STR("popup"), args, 3);
#if 0
XtAddCallback(menu,
XmNunmapCallback,
(XtCallbackProc)wxMenuPopdownCallback,
(XtPointer)this);
#endif
}
else
{
char mnem = wxFindMnemonic (title);
menu = XmCreatePulldownMenu ((Widget) parent, wxMOTIF_STR("pulldown"), args, 3);
wxString title2(wxStripMenuCodes(title));
wxXmString label_str(title2);
buttonWidget = XtVaCreateManagedWidget(title2,
#if wxUSE_GADGETS
xmCascadeButtonGadgetClass, (Widget) parent,
#else
xmCascadeButtonWidgetClass, (Widget) parent,
#endif
XmNlabelString, label_str(),
XmNsubMenuId, menu,
(String)wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
XmNpositionIndex, menuIndex,
NULL);
if (mnem != 0)
XtVaSetValues (buttonWidget, XmNmnemonic, mnem, NULL);
}
m_menuWidget = (WXWidget) menu;
m_topLevelMenu = topMenu;
size_t i = 0;
for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
node;
node = node->GetNext(), ++i )
{
wxMenuItem *item = node->GetData();
item->CreateItem(menu, menuBar, topMenu, i);
}
ChangeFont();
return buttonWidget;
}
// Destroys the Motif implementation of the menu,
// but maintains the wxWidgets data structures so we can
// do a CreateMenu again.
void wxMenu::DestroyMenu (bool full)
{
for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem *item = node->GetData();
item->SetMenuBar(NULL);
item->DestroyItem(full);
}
if (m_buttonWidget)
{
if (full)
{
XtVaSetValues((Widget) m_buttonWidget, XmNsubMenuId, NULL, NULL);
XtDestroyWidget ((Widget) m_buttonWidget);
m_buttonWidget = (WXWidget) 0;
}
}
if (m_menuWidget && full)
{
XtDestroyWidget((Widget) m_menuWidget);
m_menuWidget = (WXWidget) NULL;
}
}
WXWidget wxMenu::FindMenuItem (int id, wxMenuItem ** it) const
{
if (id == m_menuId)
{
if (it)
*it = NULL;
return m_buttonWidget;
}
for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem *item = node->GetData ();
if (item->GetId() == id)
{
if (it)
*it = item;
return item->GetButtonWidget();
}
if (item->GetSubMenu())
{
WXWidget w = item->GetSubMenu()->FindMenuItem (id, it);
if (w)
{
return w;
}
}
}
if (it)
*it = NULL;
return (WXWidget) NULL;
}
void wxMenu::SetBackgroundColour(const wxColour& col)
{
m_backgroundColour = col;
if (!col.IsOk())
return;
if (m_menuWidget)
wxDoChangeBackgroundColour(m_menuWidget, (wxColour&) col);
if (m_buttonWidget)
wxDoChangeBackgroundColour(m_buttonWidget, (wxColour&) col, true);
for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem* item = node->GetData();
if (item->GetButtonWidget())
{
// This crashes because it uses gadgets
// wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, true);
}
if (item->GetSubMenu())
item->GetSubMenu()->SetBackgroundColour((wxColour&) col);
}
}
void wxMenu::SetForegroundColour(const wxColour& col)
{
m_foregroundColour = col;
if (!col.IsOk())
return;
if (m_menuWidget)
wxDoChangeForegroundColour(m_menuWidget, (wxColour&) col);
if (m_buttonWidget)
wxDoChangeForegroundColour(m_buttonWidget, (wxColour&) col);
for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem* item = node->GetData();
if (item->GetButtonWidget())
{
// This crashes because it uses gadgets
// wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
}
if (item->GetSubMenu())
item->GetSubMenu()->SetForegroundColour((wxColour&) col);
}
}
void wxMenu::ChangeFont(bool keepOriginalSize)
{
// Lesstif 0.87 hangs here, but 0.93 does not; MBN: sometimes it does
#if !wxCHECK_LESSTIF() // || wxCHECK_LESSTIF_VERSION( 0, 93 )
if (!m_font.IsOk() || !m_menuWidget)
return;
Display* dpy = XtDisplay((Widget) m_menuWidget);
XtVaSetValues ((Widget) m_menuWidget,
wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
NULL);
if (m_buttonWidget)
{
XtVaSetValues ((Widget) m_buttonWidget,
wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
NULL);
}
for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
node;
node = node->GetNext() )
{
wxMenuItem* item = node->GetData();
if (m_menuWidget && item->GetButtonWidget() && m_font.IsOk())
{
XtVaSetValues ((Widget) item->GetButtonWidget(),
wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
NULL);
}
if (item->GetSubMenu())
item->GetSubMenu()->ChangeFont(keepOriginalSize);
}
#else
wxUnusedVar(keepOriginalSize);
#endif
}
void wxMenu::SetFont(const wxFont& font)
{
m_font = font;
ChangeFont();
}
bool wxMenuBar::SetBackgroundColour(const wxColour& col)
{
if (!wxWindowBase::SetBackgroundColour(col))
return false;
if (!col.IsOk())
return false;
if (m_mainWidget)
wxDoChangeBackgroundColour(m_mainWidget, (wxColour&) col);
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
m_menus.Item(i)->GetData()->SetBackgroundColour((wxColour&) col);
return true;
}
bool wxMenuBar::SetForegroundColour(const wxColour& col)
{
if (!wxWindowBase::SetForegroundColour(col))
return false;
if (!col.IsOk())
return false;
if (m_mainWidget)
wxDoChangeForegroundColour(m_mainWidget, (wxColour&) col);
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
m_menus.Item(i)->GetData()->SetForegroundColour((wxColour&) col);
return true;
}
void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize))
{
// Nothing to do for menubar, fonts are kept in wxMenus
}
bool wxMenuBar::SetFont(const wxFont& font)
{
m_font = font;
ChangeFont();
size_t menuCount = GetMenuCount();
for (size_t i = 0; i < menuCount; i++)
m_menus.Item(i)->GetData()->SetFont(font);
return true;
}