diff --git a/Makefile.in b/Makefile.in index d025e6cd4f..d260788331 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4524,6 +4524,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS = \ monodll_listbox.o \ monodll_mdi.o \ monodll_menu.o \ + monodll_mnemonics.o \ monodll_msgdlg.o \ monodll_notebook.o \ monodll_radiobox.o \ @@ -6403,6 +6404,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS_1 = \ monolib_listbox.o \ monolib_mdi.o \ monolib_menu.o \ + monolib_mnemonics.o \ monolib_msgdlg.o \ monolib_notebook.o \ monolib_radiobox.o \ @@ -8559,6 +8561,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS_2 = \ coredll_listbox.o \ coredll_mdi.o \ coredll_menu.o \ + coredll_mnemonics.o \ coredll_msgdlg.o \ coredll_notebook.o \ coredll_radiobox.o \ @@ -10053,6 +10056,7 @@ COND_TOOLKIT_GTK_TOOLKIT_VERSION_2___GUI_SRC_OBJECTS_3 = \ corelib_listbox.o \ corelib_mdi.o \ corelib_menu.o \ + corelib_mnemonics.o \ corelib_msgdlg.o \ corelib_notebook.o \ corelib_radiobox.o \ @@ -13735,6 +13739,9 @@ monodll_gprint.o: $(srcdir)/src/gtk/gnome/gprint.cpp $(MONODLL_ODEP) monodll_gvfs.o: $(srcdir)/src/gtk/gnome/gvfs.cpp $(MONODLL_ODEP) $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/gtk/gnome/gvfs.cpp +monodll_mnemonics.o: $(srcdir)/src/gtk/mnemonics.cpp $(MONODLL_ODEP) + $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/gtk/mnemonics.cpp + monodll_treeentry_gtk.o: $(srcdir)/src/gtk/treeentry_gtk.c $(MONODLL_ODEP) $(CCC) -c -o $@ $(MONODLL_CFLAGS) $(srcdir)/src/gtk/treeentry_gtk.c @@ -18187,6 +18194,9 @@ monolib_gprint.o: $(srcdir)/src/gtk/gnome/gprint.cpp $(MONOLIB_ODEP) monolib_gvfs.o: $(srcdir)/src/gtk/gnome/gvfs.cpp $(MONOLIB_ODEP) $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/gtk/gnome/gvfs.cpp +monolib_mnemonics.o: $(srcdir)/src/gtk/mnemonics.cpp $(MONOLIB_ODEP) + $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/gtk/mnemonics.cpp + monolib_treeentry_gtk.o: $(srcdir)/src/gtk/treeentry_gtk.c $(MONOLIB_ODEP) $(CCC) -c -o $@ $(MONOLIB_CFLAGS) $(srcdir)/src/gtk/treeentry_gtk.c @@ -23965,6 +23975,9 @@ coredll_gprint.o: $(srcdir)/src/gtk/gnome/gprint.cpp $(COREDLL_ODEP) coredll_gvfs.o: $(srcdir)/src/gtk/gnome/gvfs.cpp $(COREDLL_ODEP) $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/gtk/gnome/gvfs.cpp +coredll_mnemonics.o: $(srcdir)/src/gtk/mnemonics.cpp $(COREDLL_ODEP) + $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/gtk/mnemonics.cpp + coredll_treeentry_gtk.o: $(srcdir)/src/gtk/treeentry_gtk.c $(COREDLL_ODEP) $(CCC) -c -o $@ $(COREDLL_CFLAGS) $(srcdir)/src/gtk/treeentry_gtk.c @@ -27034,6 +27047,9 @@ corelib_gprint.o: $(srcdir)/src/gtk/gnome/gprint.cpp $(CORELIB_ODEP) corelib_gvfs.o: $(srcdir)/src/gtk/gnome/gvfs.cpp $(CORELIB_ODEP) $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/gtk/gnome/gvfs.cpp +corelib_mnemonics.o: $(srcdir)/src/gtk/mnemonics.cpp $(CORELIB_ODEP) + $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/gtk/mnemonics.cpp + corelib_treeentry_gtk.o: $(srcdir)/src/gtk/treeentry_gtk.c $(CORELIB_ODEP) $(CCC) -c -o $@ $(CORELIB_CFLAGS) $(srcdir)/src/gtk/treeentry_gtk.c diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index cde7bbdadc..db58e7dcf8 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -1056,6 +1056,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/gtk/listbox.cpp src/gtk/mdi.cpp src/gtk/menu.cpp + src/gtk/mnemonics.cpp src/gtk/msgdlg.cpp src/gtk/notebook.cpp src/gtk/radiobox.cpp diff --git a/include/wx/gtk/private/mnemonics.h b/include/wx/gtk/private/mnemonics.h new file mode 100644 index 0000000000..651a58e343 --- /dev/null +++ b/include/wx/gtk/private/mnemonics.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: gtk/private/mnemonics.h +// Purpose: helper functions for dealing with GTK+ mnemonics +// Author: Vadim Zeitlin +// Created: 2007-11-12 +// RCS-ID: $Id$ +// Copyright: (c) 2007 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _GTK_PRIVATE_MNEMONICS_H_ +#define _GTK_PRIVATE_MNEMONICS_H_ + +#if wxUSE_CONTROLS || wxUSE_MENUS + +#include "wx/string.h" + +// ---------------------------------------------------------------------------- +// functions to convert between wxWidgets and GTK+ string containing mnemonics +// ---------------------------------------------------------------------------- + +// remove all mnemonics from a string +wxString wxGTKRemoveMnemonics(const wxString& label); + +// convert a wx string with '&' to GTK+ string with '_'s +wxString wxConvertMnemonicsToGTK(const wxString& label); + +// convert a wx string with '&' to indicate mnemonics as well as HTML entities +// to a GTK+ string with "&" used instead of '&', i.e. suitable for use +// with GTK+ functions using markup strings +wxString wxConvertMnemonicsToGTKMarkup(const wxString& label); + +// convert GTK+ string with '_'s to wx string with '&'s +wxString wxConvertMnemonicsFromGTK(const wxString& label); + +#endif // wxUSE_CONTROLS || wxUSE_MENUS + +#endif // _GTK_PRIVATE_MNEMONICS_H_ + diff --git a/include/wx/private/stattext.h b/include/wx/private/stattext.h index be8f89c092..1618315881 100644 --- a/include/wx/private/stattext.h +++ b/include/wx/private/stattext.h @@ -67,6 +67,8 @@ private: bool m_eol; }; +#endif // wxUSE_STATTEXT + enum { wxMARKUP_ENTITY_AMP, @@ -92,6 +94,4 @@ enum // extern const wxChar *wxMarkupEntities[wxMARKUP_ELEMENT_MAX][wxMARKUP_ENTITY_MAX]; -#endif // wxUSE_STATTEXT - #endif // _WX_PRIVATE_STATTEXT_H_ diff --git a/src/common/stattextcmn.cpp b/src/common/stattextcmn.cpp index b4b6acee00..f7b6a787dd 100644 --- a/src/common/stattextcmn.cpp +++ b/src/common/stattextcmn.cpp @@ -37,8 +37,6 @@ #include "wx/containr.h" #endif -#if wxUSE_STATTEXT - const wxChar *wxMarkupEntities[][wxMARKUP_ENTITY_MAX] = { // the entities handled by SetLabel() when wxST_MARKUP is used and their referenced string @@ -47,6 +45,7 @@ const wxChar *wxMarkupEntities[][wxMARKUP_ENTITY_MAX] = { wxT("&"), wxT("<"), wxT(">"), wxT("'"), wxT("\"") } }; +#if wxUSE_STATTEXT // ---------------------------------------------------------------------------- // wxTextWrapper diff --git a/src/gtk/control.cpp b/src/gtk/control.cpp index 7369e8cd9e..ea16fae76a 100644 --- a/src/gtk/control.cpp +++ b/src/gtk/control.cpp @@ -22,8 +22,7 @@ #include "wx/fontutil.h" #include "wx/gtk/private.h" -#include "wx/private/stattext.h" - +#include "wx/gtk/private/mnemonics.h" // ============================================================================ // wxControl implementation @@ -151,121 +150,22 @@ void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget) // worker function implementing GTK*Mnemonics() functions // ---------------------------------------------------------------------------- -enum MnemonicsFlag -{ - MNEMONICS_REMOVE, - MNEMONICS_CONVERT, - MNEMONICS_CONVERT_MARKUP -}; - -static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag) -{ - wxString labelGTK; - labelGTK.reserve(label.length()); - for ( wxString::const_iterator i = label.begin(); i != label.end(); ++i ) - { - wxChar ch = *i; - - switch ( ch ) - { - case wxT('&'): - if ( i + 1 == label.end() ) - { - // "&" at the end of string is an error - wxLogDebug(wxT("Invalid label \"%s\"."), label); - break; - } - - if ( flag == MNEMONICS_CONVERT_MARKUP ) - { - bool isMnemonic = true; - size_t distanceFromEnd = label.end() - i; - - // is this ampersand introducing a mnemonic or rather an entity? - for (size_t j=0; j < wxMARKUP_ENTITY_MAX; j++) - { - const wxChar *entity = wxMarkupEntities[wxMARKUP_ELEMENT_NAME][j]; - size_t entityLen = wxStrlen(entity); - - if (distanceFromEnd >= entityLen && - wxString(i, i + entityLen) == entity) - { - labelGTK << entity; - i += entityLen - 1; // the -1 is because main for() - // loop already increments i - isMnemonic = false; - - break; - } - } - - if (!isMnemonic) - continue; - } - - ch = *(++i); // skip '&' itself - switch ( ch ) - { - case wxT('&'): - // special case: "&&" is not a mnemonic at all but just - // an escaped "&" - if ( flag == MNEMONICS_CONVERT_MARKUP ) - labelGTK += wxT("&"); - else - labelGTK += wxT('&'); - break; - - case wxT('_'): - if ( flag != MNEMONICS_REMOVE ) - { - // '_' can't be a GTK mnemonic apparently so - // replace it with something similar - labelGTK += wxT("_-"); - break; - } - //else: fall through - - default: - if ( flag != MNEMONICS_REMOVE ) - labelGTK += wxT('_'); - labelGTK += ch; - } - break; - - case wxT('_'): - if ( flag != MNEMONICS_REMOVE ) - { - // escape any existing underlines in the string so that - // they don't become mnemonics accidentally - labelGTK += wxT("__"); - break; - } - //else: fall through - - default: - labelGTK += ch; - } - } - - return labelGTK; -} - /* static */ wxString wxControl::GTKRemoveMnemonics(const wxString& label) { - return GTKProcessMnemonics(label, MNEMONICS_REMOVE); + return wxGTKRemoveMnemonics(label); } /* static */ wxString wxControl::GTKConvertMnemonics(const wxString& label) { - return GTKProcessMnemonics(label, MNEMONICS_CONVERT); + return wxConvertMnemonicsToGTK(label); } /* static */ wxString wxControl::GTKConvertMnemonicsWithMarkup(const wxString& label) { - return GTKProcessMnemonics(label, MNEMONICS_CONVERT_MARKUP); + return wxConvertMnemonicsToGTKMarkup(label); } // ---------------------------------------------------------------------------- diff --git a/src/gtk/menu.cpp b/src/gtk/menu.cpp index 6e1d23f4c3..7f04189b92 100644 --- a/src/gtk/menu.cpp +++ b/src/gtk/menu.cpp @@ -25,6 +25,7 @@ #include "wx/accel.h" #include "wx/stockitem.h" #include "wx/gtk/private.h" +#include "wx/gtk/private/mnemonics.h" // FIXME: is this right? somehow I don't think so (VZ) @@ -47,79 +48,6 @@ static const int wxGTK_TITLE_ID = -3; static wxString GetGtkHotKey( const wxMenuItem& item ); #endif -//----------------------------------------------------------------------------- -// idle system -//----------------------------------------------------------------------------- - -static wxString wxReplaceUnderscore( const wxString& title ) -{ - // GTK 1.2 wants to have "_" instead of "&" for accelerators - wxString str; - - for ( wxString::const_iterator pc = title.begin(); pc != title.end(); ++pc ) - { - if ((*pc == wxT('&')) && (pc+1 != title.end()) && (*(pc+1) == wxT('&'))) - { - // "&" is doubled to indicate "&" instead of accelerator - ++pc; - str << wxT('&'); - } - else if (*pc == wxT('&')) - { - str << wxT('_'); - } - else - { - if ( *pc == wxT('_') ) - { - // underscores must be doubled to prevent them from being - // interpreted as accelerator character prefix by GTK - str << *pc; - } - - str << *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 //----------------------------------------------------------------------------- @@ -367,7 +295,7 @@ bool wxMenuBar::Append( wxMenu *menu, const wxString &title ) bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos) { - wxString str( wxReplaceUnderscore( title ) ); + const wxString str(wxConvertMnemonicsToGTK(title)); // This doesn't have much effect right now. menu->SetTitle( str ); @@ -443,7 +371,7 @@ wxMenu *wxMenuBar::Remove(size_t pos) static int FindMenuItemRecursive( const wxMenu *menu, const wxString &menuString, const wxString &itemString ) { - if (wxMenuItem::GetLabelText(wxConvertFromGTKToWXLabel(menu->GetTitle())) == wxMenuItem::GetLabelText(menuString)) + if (wxMenuItem::GetLabelText(wxConvertMnemonicsFromGTK(menu->GetTitle())) == wxMenuItem::GetLabelText(menuString)) { int res = menu->FindItem( itemString ); if (res != wxNOT_FOUND) @@ -536,7 +464,7 @@ wxString wxMenuBar::GetMenuLabel( size_t pos ) const wxMenu* menu = node->GetData(); - return wxConvertFromGTKToWXLabel(menu->GetTitle()); + return wxConvertMnemonicsFromGTK(menu->GetTitle()); } void wxMenuBar::SetMenuLabel( size_t pos, const wxString& label ) @@ -547,7 +475,7 @@ void wxMenuBar::SetMenuLabel( size_t pos, const wxString& label ) wxMenu* menu = node->GetData(); - const wxString str( wxReplaceUnderscore( label ) ); + const wxString str(wxConvertMnemonicsToGTK(label)); menu->SetTitle( str ); @@ -785,9 +713,9 @@ wxString wxMenuItemBase::GetLabelText(const wxString& text) wxString wxMenuItem::GetItemLabel() const { - wxString label = wxConvertFromGTKToWXLabel(m_text); + wxString label = wxConvertMnemonicsFromGTK(m_text); if (!m_hotKey.IsEmpty()) - label = label + wxT("\t") + m_hotKey; + label << "\t" << m_hotKey; return label; } diff --git a/src/gtk/mnemonics.cpp b/src/gtk/mnemonics.cpp new file mode 100644 index 0000000000..e78bd5dd6d --- /dev/null +++ b/src/gtk/mnemonics.cpp @@ -0,0 +1,189 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/gtk/mnemonics.cpp +// Purpose: implementation of GTK mnemonics conversion functions +// Author: Vadim Zeitlin +// Created: 2007-11-12 +// RCS-ID: $Id$ +// Copyright: (c) 2007 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/private/stattext.h" // for wxMarkupEntities + +#include "wx/gtk/private/mnemonics.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// internal helper: apply the operation indicated by flag +// ---------------------------------------------------------------------------- + +enum MnemonicsFlag +{ + MNEMONICS_REMOVE, + MNEMONICS_CONVERT, + MNEMONICS_CONVERT_MARKUP +}; + +static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag) +{ + wxString labelGTK; + labelGTK.reserve(label.length()); + for ( wxString::const_iterator i = label.begin(); i != label.end(); ++i ) + { + wxChar ch = *i; + + switch ( ch ) + { + case wxT('&'): + if ( i + 1 == label.end() ) + { + // "&" at the end of string is an error + wxLogDebug(wxT("Invalid label \"%s\"."), label); + break; + } + + if ( flag == MNEMONICS_CONVERT_MARKUP ) + { + bool isMnemonic = true; + size_t distanceFromEnd = label.end() - i; + + // is this ampersand introducing a mnemonic or rather an entity? + for (size_t j=0; j < wxMARKUP_ENTITY_MAX; j++) + { + const wxChar *entity = wxMarkupEntities[wxMARKUP_ELEMENT_NAME][j]; + size_t entityLen = wxStrlen(entity); + + if (distanceFromEnd >= entityLen && + wxString(i, i + entityLen) == entity) + { + labelGTK << entity; + i += entityLen - 1; // the -1 is because main for() + // loop already increments i + isMnemonic = false; + + break; + } + } + + if (!isMnemonic) + continue; + } + + ch = *(++i); // skip '&' itself + switch ( ch ) + { + case wxT('&'): + // special case: "&&" is not a mnemonic at all but just + // an escaped "&" + if ( flag == MNEMONICS_CONVERT_MARKUP ) + labelGTK += wxT("&"); + else + labelGTK += wxT('&'); + break; + + case wxT('_'): + if ( flag != MNEMONICS_REMOVE ) + { + // '_' can't be a GTK mnemonic apparently so + // replace it with something similar + labelGTK += wxT("_-"); + break; + } + //else: fall through + + default: + if ( flag != MNEMONICS_REMOVE ) + labelGTK += wxT('_'); + labelGTK += ch; + } + break; + + case wxT('_'): + if ( flag != MNEMONICS_REMOVE ) + { + // escape any existing underlines in the string so that + // they don't become mnemonics accidentally + labelGTK += wxT("__"); + break; + } + //else: fall through + + default: + labelGTK += ch; + } + } + + return labelGTK; +} + +// ---------------------------------------------------------------------------- +// public functions +// ---------------------------------------------------------------------------- + +wxString wxGTKRemoveMnemonics(const wxString& label) +{ + return GTKProcessMnemonics(label, MNEMONICS_REMOVE); +} + +wxString wxConvertMnemonicsToGTK(const wxString& label) +{ + return GTKProcessMnemonics(label, MNEMONICS_CONVERT); +} + +wxString wxConvertMnemonicsToGTKMarkup(const wxString& label) +{ + return GTKProcessMnemonics(label, MNEMONICS_CONVERT_MARKUP); +} + +wxString wxConvertMnemonicsFromGTK(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; +} +