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