/////////////////////////////////////////////////////////////////////////////
// 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/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))
-//#define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g))
+#define gtk_accel_group_detach(g, o) gtk_window_remove_accel_group((o), (g))
//#define gtk_menu_ensure_uline_accel_group(m) gtk_menu_get_accel_group(m)
#define ACCEL_OBJECT GtkWindow
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
//-----------------------------------------------------------------------------
extern "C" {
-static void gtk_menu_open_callback( GtkWidget *widget, wxMenu *menu )
+static void
+gtk_menu_open_callback(GtkWidget * WXUNUSED(widget), wxMenu *menu)
{
wxMenuEvent event(wxEVT_MENU_OPEN, -1, menu);
DoCommonMenuCallbackCode(menu, event);
}
-static void gtk_menu_close_callback( GtkWidget *widget, wxMenuBar *menubar )
+static void
+gtk_menu_close_callback(GtkWidget * WXUNUSED(widget), wxMenuBar *menubar)
{
if ( !menubar->GetMenuCount() )
{
while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
top_frame = top_frame->GetParent();
+ // support for native hot keys
+ ACCEL_OBJECT *obj = ACCEL_OBJ_CAST(top_frame->m_widget);
+ if ( menu->m_accel && g_slist_find( ACCEL_OBJECTS(menu->m_accel), obj ) )
+ gtk_accel_group_detach( menu->m_accel, obj );
+
wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
while (node)
{
// m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables
// addings menu later on.
if (m_invokingWindow)
- {
wxMenubarSetInvokingWindow( menu, m_invokingWindow );
- // OPTIMISE ME: we should probably cache this, or pass it
- // directly, but for now this is a minimal
- // change to validate the new dynamic sizing.
- // see (and refactor :) similar code in Remove
- // below.
-
- wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame );
-
- if( frame )
- frame->UpdateMenuBarSize();
- }
-
return true;
}
menu->m_owner = NULL;
if (m_invokingWindow)
- {
- // OPTIMISE ME: see comment in GtkAppend
- wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame );
-
- if( frame )
- frame->UpdateMenuBarSize();
- }
+ wxMenubarUnsetInvokingWindow( menu, m_invokingWindow );
return menu;
}
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 );
commandEvent.SetEventObject(frame);
if (item->IsCheckable())
commandEvent.SetInt(item->IsChecked());
- commandEvent.SetEventObject(menu);
frame->GetEventHandler()->ProcessEvent(commandEvent);
}
// 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());
}
// 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)
{
wxMenu::~wxMenu()
{
- WX_CLEAR_LIST(wxMenuItemList, m_items);
-
if ( GTK_IS_WIDGET( m_menu ))
{
// 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 )
gtk_widget_destroy( m_menu );
}
+
+ // This must come after we release GTK resources above. Otherwise, GTK will
+ // give warnings/errors when attempting to free accelerator resources from
+ // child items that just were destroyed (the m_menu widget can contain
+ // references to accelerators in child items. Problem detected when removing
+ // a menu from a wxMenuBar, and the removed menu had submenus with accelerators.)
+ WX_CLEAR_LIST(wxMenuItemList, m_items);
}
void wxMenu::SetLayoutDirection(const wxLayoutDirection dir)
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);
}
#endif // __WXGTK20__
+
+#endif // wxUSE_MENUS