Add mnemonics to wxGTK1
[wxWidgets.git] / src / gtk1 / mnemonics.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/mnemonics.cpp
3 // Purpose: implementation of GTK mnemonics conversion functions
4 // Author: Vadim Zeitlin
5 // Created: 2007-11-12
6 // RCS-ID: $Id: mnemonics.cpp 49885 2007-11-13 02:21:12Z PC $
7 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/log.h"
27 #include "wx/private/stattext.h" // for wxMarkupEntities
28
29 #include "wx/gtk1/private/mnemonics.h"
30
31 // ============================================================================
32 // implementation
33 // ============================================================================
34
35 // ----------------------------------------------------------------------------
36 // internal helper: apply the operation indicated by flag
37 // ----------------------------------------------------------------------------
38
39 enum MnemonicsFlag
40 {
41 MNEMONICS_REMOVE,
42 MNEMONICS_CONVERT,
43 MNEMONICS_CONVERT_MARKUP
44 };
45
46 static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag)
47 {
48 wxString labelGTK;
49 labelGTK.reserve(label.length());
50 for ( wxString::const_iterator i = label.begin(); i != label.end(); ++i )
51 {
52 wxChar ch = *i;
53
54 switch ( ch )
55 {
56 case wxT('&'):
57 if ( i + 1 == label.end() )
58 {
59 // "&" at the end of string is an error
60 wxLogDebug(wxT("Invalid label \"%s\"."), label);
61 break;
62 }
63
64 if ( flag == MNEMONICS_CONVERT_MARKUP )
65 {
66 bool isMnemonic = true;
67 size_t distanceFromEnd = label.end() - i;
68
69 // is this ampersand introducing a mnemonic or rather an entity?
70 for (size_t j=0; j < wxMARKUP_ENTITY_MAX; j++)
71 {
72 const wxChar *entity = wxMarkupEntities[wxMARKUP_ELEMENT_NAME][j];
73 size_t entityLen = wxStrlen(entity);
74
75 if (distanceFromEnd >= entityLen &&
76 wxString(i, i + entityLen) == entity)
77 {
78 labelGTK << entity;
79 i += entityLen - 1; // the -1 is because main for()
80 // loop already increments i
81 isMnemonic = false;
82
83 break;
84 }
85 }
86
87 if (!isMnemonic)
88 continue;
89 }
90
91 ch = *(++i); // skip '&' itself
92 switch ( ch )
93 {
94 case wxT('&'):
95 // special case: "&&" is not a mnemonic at all but just
96 // an escaped "&"
97 if ( flag == MNEMONICS_CONVERT_MARKUP )
98 labelGTK += wxT("&amp;");
99 else
100 labelGTK += wxT('&');
101 break;
102
103 case wxT('_'):
104 if ( flag != MNEMONICS_REMOVE )
105 {
106 // '_' can't be a GTK mnemonic apparently so
107 // replace it with something similar
108 labelGTK += wxT("_-");
109 break;
110 }
111 //else: fall through
112
113 default:
114 if ( flag != MNEMONICS_REMOVE )
115 labelGTK += wxT('_');
116 labelGTK += ch;
117 }
118 break;
119
120 case wxT('_'):
121 if ( flag != MNEMONICS_REMOVE )
122 {
123 // escape any existing underlines in the string so that
124 // they don't become mnemonics accidentally
125 labelGTK += wxT("__");
126 break;
127 }
128 //else: fall through
129
130 default:
131 labelGTK += ch;
132 }
133 }
134
135 return labelGTK;
136 }
137
138 // ----------------------------------------------------------------------------
139 // public functions
140 // ----------------------------------------------------------------------------
141
142 wxString wxGTKRemoveMnemonics(const wxString& label)
143 {
144 return GTKProcessMnemonics(label, MNEMONICS_REMOVE);
145 }
146
147 wxString wxConvertMnemonicsToGTK(const wxString& label)
148 {
149 return GTKProcessMnemonics(label, MNEMONICS_CONVERT);
150 }
151
152 wxString wxConvertMnemonicsToGTKMarkup(const wxString& label)
153 {
154 return GTKProcessMnemonics(label, MNEMONICS_CONVERT_MARKUP);
155 }
156
157 wxString wxConvertMnemonicsFromGTK(const wxString& gtkLabel)
158 {
159 wxString label;
160 for ( const wxChar *pc = gtkLabel.c_str(); *pc; pc++ )
161 {
162 // '_' is the escape character for GTK+.
163
164 if ( *pc == wxT('_') && *(pc+1) == wxT('_'))
165 {
166 // An underscore was escaped.
167 label += wxT('_');
168 pc++;
169 }
170 else if ( *pc == wxT('_') )
171 {
172 // Convert GTK+ hotkey symbol to wxWidgets/Windows standard
173 label += wxT('&');
174 }
175 else if ( *pc == wxT('&') )
176 {
177 // Double the ampersand to escape it as far as wxWidgets is concerned
178 label += wxT("&&");
179 }
180 else
181 {
182 // don't remove ampersands '&' since if we have them in the menu title
183 // it means that they were doubled to indicate "&" instead of accelerator
184 label += *pc;
185 }
186 }
187
188 return label;
189 }
190