/////////////////////////////////////////////////////////////////////////////
// Name: src/gtk/menu.cpp
-// Purpose:
+// Purpose: implementation of wxMenuBar and wxMenu classes for wxGTK
// Author: Robert Roebling
// Id: $Id$
// Copyright: (c) 1998 Robert Roebling
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
+#if wxUSE_MENUS
+
#include "wx/menu.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/frame.h"
#include "wx/bitmap.h"
+ #include "wx/app.h"
#endif
#include "wx/accel.h"
#include "wx/stockitem.h"
#include "wx/gtk/private.h"
+#ifdef __WXGTK20__
+#include <gdk/gdktypes.h>
+#endif
+
// FIXME: is this right? somehow I don't think so (VZ)
#define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g))
static wxString wxReplaceUnderscore( const wxString& title )
{
- const wxChar *pc;
-
// GTK 1.2 wants to have "_" instead of "&" for accelerators
wxString str;
- pc = title;
- while (*pc != wxT('\0'))
+
+ for ( wxString::const_iterator pc = title.begin(); pc != title.end(); ++pc )
{
- if ((*pc == wxT('&')) && (*(pc+1) == wxT('&')))
+ if ((*pc == wxT('&')) && (pc+1 != title.end()) && (*(pc+1) == wxT('&')))
{
// "&" is doubled to indicate "&" instead of accelerator
++pc;
str << *pc;
}
- ++pc;
}
// wxPrintf( wxT("before %s after %s\n"), title.c_str(), str.c_str() );
return str;
}
+static wxString wxConvertFromGTKToWXLabel(const wxString& gtkLabel)
+{
+ wxString label;
+ for ( const wxChar *pc = gtkLabel.c_str(); *pc; pc++ )
+ {
+ // '_' is the escape character for GTK+.
+
+ if ( *pc == wxT('_') && *(pc+1) == wxT('_'))
+ {
+ // An underscore was escaped.
+ label += wxT('_');
+ pc++;
+ }
+ else if ( *pc == wxT('_') )
+ {
+ // Convert GTK+ hotkey symbol to wxWidgets/Windows standard
+ label += wxT('&');
+ }
+ else if ( *pc == wxT('&') )
+ {
+ // Double the ampersand to escape it as far as wxWidgets is concerned
+ label += wxT("&&");
+ }
+ else
+ {
+ // don't remove ampersands '&' since if we have them in the menu title
+ // it means that they were doubled to indicate "&" instead of accelerator
+ label += *pc;
+ }
+ }
+
+ return label;
+}
+
//-----------------------------------------------------------------------------
// activate message from GTK
//-----------------------------------------------------------------------------
static void DoCommonMenuCallbackCode(wxMenu *menu, wxMenuEvent& event)
{
- if (g_isIdle)
- wxapp_install_idle_handler();
-
event.SetEventObject( menu );
wxEvtHandler* handler = menu->GetEventHandler();
void wxMenuBar::Init(size_t n, wxMenu *menus[], const wxString titles[], long style)
{
- // the parent window is known after wxFrame::SetMenu()
- m_needParent = false;
m_style = style;
- m_invokingWindow = (wxWindow*) NULL;
+ m_invokingWindow = NULL;
- if (!PreCreation( (wxWindow*) NULL, wxDefaultPosition, wxDefaultSize ) ||
- !CreateBase( (wxWindow*) NULL, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("menubar") ))
+ if (!PreCreation( NULL, wxDefaultPosition, wxDefaultSize ) ||
+ !CreateBase( NULL, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("menubar") ))
{
wxFAIL_MSG( wxT("wxMenuBar creation failed") );
return;
if (style & wxMB_DOCKABLE)
{
m_widget = gtk_handle_box_new();
- gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_menubar) );
- gtk_widget_show( GTK_WIDGET(m_menubar) );
+ gtk_container_add(GTK_CONTAINER(m_widget), m_menubar);
+ gtk_widget_show(m_menubar);
}
else
{
- m_widget = GTK_WIDGET(m_menubar);
+ m_widget = m_menubar;
}
PostCreation();
static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString, const wxString &itemString )
{
- if (wxMenuItem::GetLabelFromText(menu->GetTitle()) == wxMenuItem::GetLabelFromText(menuString))
+ if (wxMenuItem::GetLabelText(wxConvertFromGTKToWXLabel(menu->GetTitle())) == wxMenuItem::GetLabelText(menuString))
{
int res = menu->FindItem( itemString );
if (res != wxNOT_FOUND)
gtk_widget_set_sensitive( menu->m_owner, flag );
}
-wxString wxMenuBar::GetLabelTop( size_t pos ) const
+wxString wxMenuBar::GetMenuLabel( size_t pos ) const
{
wxMenuList::compatibility_iterator node = m_menus.Item( pos );
wxMenu* menu = node->GetData();
- wxString label;
- wxString text( menu->GetTitle() );
- for ( const wxChar *pc = text.c_str(); *pc; pc++ )
- {
- if ( *pc == wxT('_') )
- {
- // '_' is the escape character for GTK+
- continue;
- }
-
- // don't remove ampersands '&' since if we have them in the menu title
- // it means that they were doubled to indicate "&" instead of accelerator
-
- label += *pc;
- }
-
- return label;
+ return wxConvertFromGTKToWXLabel(menu->GetTitle());
}
-void wxMenuBar::SetLabelTop( size_t pos, const wxString& label )
+void wxMenuBar::SetMenuLabel( size_t pos, const wxString& label )
{
wxMenuList::compatibility_iterator node = m_menus.Item( pos );
extern "C" {
static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu )
{
- if (g_isIdle)
- wxapp_install_idle_handler();
-
int id = menu->FindMenuIdByMenuItem(widget);
/* should find it for normal (not popup) menu */
extern "C" {
static void gtk_menu_hilight_callback( GtkWidget *widget, wxMenu *menu )
{
- if (g_isIdle) wxapp_install_idle_handler();
-
int id = menu->FindMenuIdByMenuItem(widget);
wxASSERT( id != -1 ); // should find it!
extern "C" {
static void gtk_menu_nolight_callback( GtkWidget *widget, wxMenu *menu )
{
- if (g_isIdle) wxapp_install_idle_handler();
-
int id = menu->FindMenuIdByMenuItem(widget);
wxASSERT( id != -1 ); // should find it!
// return the menu item text without any menu accels
/* static */
-wxString wxMenuItemBase::GetLabelFromText(const wxString& text)
+
+wxString wxMenuItemBase::GetLabelText(const wxString& text)
{
+ // The argument to this function will now always be in wxWidgets standard label
+ // format, not GTK+ format, so we do what the other ports do.
+
+ return wxStripMenuCodes(text);
+
+#if 0
wxString label;
for ( const wxChar *pc = text.c_str(); *pc; pc++ )
label += *pc;
}
- // wxPrintf( wxT("GetLabelFromText(): text %s label %s\n"), text.c_str(), label.c_str() );
+ // wxPrintf( wxT("GetLabelText(): text %s label %s\n"), text.c_str(), label.c_str() );
return label;
+#endif
}
-void wxMenuItem::SetText( const wxString& str )
+wxString wxMenuItem::GetItemLabel() const
+{
+ wxString label = wxConvertFromGTKToWXLabel(m_text);
+ if (!m_hotKey.IsEmpty())
+ label = label + wxT("\t") + m_hotKey;
+ return label;
+}
+
+void wxMenuItem::SetItemLabel( const wxString& str )
{
// cache some data which must be used later
bool isstock = wxIsStockID(GetId());
gtk_accelerator_parse( (const char*) oldbuf, &accel_key, &accel_mods);
if (accel_key != 0)
{
- gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem),
+ gtk_widget_remove_accelerator(m_menuItem,
m_parentMenu->m_accel,
accel_key,
accel_mods );
{
// if the accelerator was taken from a stock ID, just get it back from GTK+ stock
if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key))
- gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem),
+ gtk_widget_remove_accelerator( m_menuItem,
m_parentMenu->m_accel,
accel_key,
accel_mods );
gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods);
if (accel_key != 0)
{
- gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem),
+ gtk_widget_add_accelerator( m_menuItem,
"activate",
m_parentMenu->m_accel,
accel_key,
{
// if the accelerator was taken from a stock ID, just get it back from GTK+ stock
if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key))
- gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem),
+ gtk_widget_remove_accelerator( m_menuItem,
m_parentMenu->m_accel,
accel_key,
accel_mods );
}
// NOTE: this function is different from the similar functions GTKProcessMnemonics()
-// implemented in control.cpp and from wxMenuItemBase::GetLabelFromText...
+// implemented in control.cpp and from wxMenuItemBase::GetLabelText...
// so there's no real code duplication
wxString wxMenuItem::GTKProcessMenuItemLabel(const wxString& str, wxString *hotKey)
{
wxString text;
// '\t' is the deliminator indicating a hot key
- const wxChar *pc = str;
- while ( (*pc != wxT('\0')) && (*pc != wxT('\t')) )
+ wxString::const_iterator pc = str.begin();
+ while ( pc != str.end() && *pc != wxT('\t') )
{
- if ((*pc == wxT('&')) && (*(pc+1) == wxT('&')))
+ if (*pc == wxT('&'))
{
- // "&" is doubled to indicate "&" instead of accelerator
- ++pc;
- text << wxT('&');
- }
- else if (*pc == wxT('&'))
- {
- text << wxT('_');
+ wxString::const_iterator next = pc + 1;
+ if (next != str.end() && *next == wxT('&'))
+ {
+ // "&" is doubled to indicate "&" instead of accelerator
+ ++pc;
+ text << wxT('&');
+ }
+ else
+ {
+ text << wxT('_');
+ }
}
else if ( *pc == wxT('_') ) // escape underscores
{
if(*pc == wxT('\t'))
{
pc++;
- *hotKey = pc;
+ hotKey->assign(pc, str.end());
}
}
{
// see wxMenu::Init
gtk_widget_unref( m_menu );
+ g_object_unref( m_accel );
+
// if the menu is inserted in another menu at this time, there was
// one more reference to it:
if ( m_owner )
GtkWidget *menuItem;
// cache some data used later
- wxString text = mitem->GetText();
+ wxString text = mitem->wxMenuItemBase::GetItemLabel();
int id = mitem->GetId();
bool isstock = wxIsStockID(id);
const char *stockid = NULL;
}
else // a normal item
{
- // NB: 'text' variable has "_" instead of "&" after mitem->SetText()
+ // NB: 'text' variable has "_" instead of "&" after mitem->SetItemLabel()
// so don't use it
switch ( mitem->GetKind() )
GdkModifierType accel_mods;
wxCharBuffer buf = wxGTK_CONV_SYS( GetGtkHotKey(*mitem) );
- // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetGtkHotKey(*mitem).c_str() );
+ // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetItemLabel().c_str(), GetGtkHotKey(*mitem).c_str() );
if (buf[(size_t)0] != '\0')
{
gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods);
if (accel_key != 0)
{
- gtk_widget_add_accelerator (GTK_WIDGET(menuItem),
+ gtk_widget_add_accelerator (menuItem,
"activate",
m_accel,
accel_key,
{
// if the accelerator was taken from a stock ID, just get it back from GTK+ stock
if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key))
- gtk_widget_add_accelerator( GTK_WIDGET(menuItem),
+ gtk_widget_add_accelerator( menuItem,
"activate",
m_accel,
accel_key,
hotkey << wxT("Down" );
break;
case WXK_PAGEUP:
- hotkey << wxT("PgUp" );
+ hotkey << wxT("Page_Up" );
break;
case WXK_PAGEDOWN:
- hotkey << wxT("PgDn" );
+ hotkey << wxT("Page_Down" );
break;
case WXK_LEFT:
hotkey << wxT("Left" );
hotkey << wxT("KP_Down" );
break;
case WXK_NUMPAD_PAGEUP:
- hotkey << wxT("KP_PgUp" );
+ hotkey << wxT("KP_Page_Up" );
break;
case WXK_NUMPAD_PAGEDOWN:
- hotkey << wxT("KP_PgDn" );
+ hotkey << wxT("KP_Page_Down" );
break;
case WXK_NUMPAD_END:
hotkey << wxT("KP_End" );
default:
if ( code < 127 )
{
- wxString name = wxGTK_CONV_BACK( gdk_keyval_name((guint)code) );
- if ( name )
+ const wxString
+ name = wxGTK_CONV_BACK_SYS(gdk_keyval_name((guint)code));
+ if ( !name.empty() )
{
hotkey << name;
break;
}
#endif // wxUSE_MENUS_NATIVE
+
+#ifdef __WXGTK20__
+
+#include <gtk/gtk.h>
+
+const char *wxGetStockGtkID(wxWindowID id)
+{
+ #define STOCKITEM(wx,gtk) \
+ case wx: \
+ return gtk;
+
+ #define STOCKITEM_MISSING(wx) \
+ case wx: \
+ return NULL;
+
+ #if GTK_CHECK_VERSION(2,4,0)
+ #define STOCKITEM_24(wx,gtk) STOCKITEM(wx,gtk)
+ #else
+ #define STOCKITEM_24(wx,gtk) STOCKITEM_MISSING(wx)
+ #endif
+
+ #if GTK_CHECK_VERSION(2,6,0)
+ #define STOCKITEM_26(wx,gtk) STOCKITEM(wx,gtk)
+ #else
+ #define STOCKITEM_26(wx,gtk) STOCKITEM_MISSING(wx)
+ #endif
+
+ #if GTK_CHECK_VERSION(2,10,0)
+ #define STOCKITEM_210(wx,gtk) STOCKITEM(wx,gtk)
+ #else
+ #define STOCKITEM_210(wx,gtk) STOCKITEM_MISSING(wx)
+ #endif
+
+
+ switch (id)
+ {
+ STOCKITEM_26(wxID_ABOUT, GTK_STOCK_ABOUT)
+ STOCKITEM(wxID_ADD, GTK_STOCK_ADD)
+ STOCKITEM(wxID_APPLY, GTK_STOCK_APPLY)
+ STOCKITEM(wxID_BOLD, GTK_STOCK_BOLD)
+ STOCKITEM(wxID_CANCEL, GTK_STOCK_CANCEL)
+ STOCKITEM(wxID_CLEAR, GTK_STOCK_CLEAR)
+ STOCKITEM(wxID_CLOSE, GTK_STOCK_CLOSE)
+ STOCKITEM(wxID_COPY, GTK_STOCK_COPY)
+ STOCKITEM(wxID_CUT, GTK_STOCK_CUT)
+ STOCKITEM(wxID_DELETE, GTK_STOCK_DELETE)
+ STOCKITEM_26(wxID_EDIT, GTK_STOCK_EDIT)
+ STOCKITEM(wxID_FIND, GTK_STOCK_FIND)
+ STOCKITEM_26(wxID_FILE, GTK_STOCK_FILE)
+ STOCKITEM(wxID_REPLACE, GTK_STOCK_FIND_AND_REPLACE)
+ STOCKITEM(wxID_BACKWARD, GTK_STOCK_GO_BACK)
+ STOCKITEM(wxID_DOWN, GTK_STOCK_GO_DOWN)
+ STOCKITEM(wxID_FORWARD, GTK_STOCK_GO_FORWARD)
+ STOCKITEM(wxID_UP, GTK_STOCK_GO_UP)
+ STOCKITEM(wxID_HELP, GTK_STOCK_HELP)
+ STOCKITEM(wxID_HOME, GTK_STOCK_HOME)
+ STOCKITEM_24(wxID_INDENT, GTK_STOCK_INDENT)
+ STOCKITEM(wxID_INDEX, GTK_STOCK_INDEX)
+ STOCKITEM(wxID_ITALIC, GTK_STOCK_ITALIC)
+ STOCKITEM(wxID_JUSTIFY_CENTER, GTK_STOCK_JUSTIFY_CENTER)
+ STOCKITEM(wxID_JUSTIFY_FILL, GTK_STOCK_JUSTIFY_FILL)
+ STOCKITEM(wxID_JUSTIFY_LEFT, GTK_STOCK_JUSTIFY_LEFT)
+ STOCKITEM(wxID_JUSTIFY_RIGHT, GTK_STOCK_JUSTIFY_RIGHT)
+ STOCKITEM(wxID_NEW, GTK_STOCK_NEW)
+ STOCKITEM(wxID_NO, GTK_STOCK_NO)
+ STOCKITEM(wxID_OK, GTK_STOCK_OK)
+ STOCKITEM(wxID_OPEN, GTK_STOCK_OPEN)
+ STOCKITEM(wxID_PASTE, GTK_STOCK_PASTE)
+ STOCKITEM(wxID_PREFERENCES, GTK_STOCK_PREFERENCES)
+ STOCKITEM(wxID_PRINT, GTK_STOCK_PRINT)
+ STOCKITEM(wxID_PREVIEW, GTK_STOCK_PRINT_PREVIEW)
+ STOCKITEM(wxID_PROPERTIES, GTK_STOCK_PROPERTIES)
+ STOCKITEM(wxID_EXIT, GTK_STOCK_QUIT)
+ STOCKITEM(wxID_REDO, GTK_STOCK_REDO)
+ STOCKITEM(wxID_REFRESH, GTK_STOCK_REFRESH)
+ STOCKITEM(wxID_REMOVE, GTK_STOCK_REMOVE)
+ STOCKITEM(wxID_REVERT_TO_SAVED, GTK_STOCK_REVERT_TO_SAVED)
+ STOCKITEM(wxID_SAVE, GTK_STOCK_SAVE)
+ STOCKITEM(wxID_SAVEAS, GTK_STOCK_SAVE_AS)
+ STOCKITEM_210(wxID_SELECTALL, GTK_STOCK_SELECT_ALL)
+ STOCKITEM(wxID_STOP, GTK_STOCK_STOP)
+ STOCKITEM(wxID_UNDELETE, GTK_STOCK_UNDELETE)
+ STOCKITEM(wxID_UNDERLINE, GTK_STOCK_UNDERLINE)
+ STOCKITEM(wxID_UNDO, GTK_STOCK_UNDO)
+ STOCKITEM_24(wxID_UNINDENT, GTK_STOCK_UNINDENT)
+ STOCKITEM(wxID_YES, GTK_STOCK_YES)
+ STOCKITEM(wxID_ZOOM_100, GTK_STOCK_ZOOM_100)
+ STOCKITEM(wxID_ZOOM_FIT, GTK_STOCK_ZOOM_FIT)
+ STOCKITEM(wxID_ZOOM_IN, GTK_STOCK_ZOOM_IN)
+ STOCKITEM(wxID_ZOOM_OUT, GTK_STOCK_ZOOM_OUT)
+
+ default:
+ wxFAIL_MSG( _T("invalid stock item ID") );
+ break;
+ };
+
+ #undef STOCKITEM
+
+ return NULL;
+}
+
+bool wxGetStockGtkAccelerator(const char *id, GdkModifierType *mod, guint *key)
+{
+ if (!id)
+ return false;
+
+ GtkStockItem stock_item;
+ if (gtk_stock_lookup (id, &stock_item))
+ {
+ if (key) *key = stock_item.keyval;
+ if (mod) *mod = stock_item.modifier;
+
+ // some GTK stock items have zero values for the keyval;
+ // it means that they do not have an accelerator...
+ if (stock_item.keyval)
+ return true;
+ }
+
+ return false;
+}
+
+#endif // __WXGTK20__
+
+#endif // wxUSE_MENUS