]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/control.cpp
Preserve original menu label for later retrieval
[wxWidgets.git] / src / gtk / control.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
634fb750
VZ
2// Name: src/gtk/control.cpp
3// Purpose: wxControl implementation for wxGTK
c801d85f 4// Author: Robert Roebling
dbf858b5 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart and Vadim Zeitlin
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
1e6feb95
VZ
13#if wxUSE_CONTROLS
14
c801d85f 15#include "wx/control.h"
e4db172a
WS
16
17#ifndef WX_PRECOMP
18 #include "wx/log.h"
9eddec69 19 #include "wx/settings.h"
e4db172a
WS
20#endif
21
9d522606 22#include "wx/fontutil.h"
b2ff89d6 23#include "wx/gtk/private.h"
034be888 24
39bc0347
VZ
25#include "wx/private/stattext.h"
26
27
634fb750
VZ
28// ============================================================================
29// wxControl implementation
30// ============================================================================
31
32// ----------------------------------------------------------------------------
33// wxControl creation
34// ----------------------------------------------------------------------------
c801d85f 35
9abe166a 36IMPLEMENT_DYNAMIC_CLASS(wxControl, wxWindow)
c801d85f 37
31528cd3 38wxControl::wxControl()
c801d85f 39{
6de97a3b 40}
c801d85f 41
04165bec 42bool wxControl::Create( wxWindow *parent,
31528cd3
VZ
43 wxWindowID id,
44 const wxPoint &pos,
45 const wxSize &size,
46 long style,
8d772832 47 const wxValidator& validator,
04165bec 48 const wxString &name )
8d772832 49{
04165bec 50 bool ret = wxWindow::Create(parent, id, pos, size, style, name);
b2ff89d6 51
04165bec 52#if wxUSE_VALIDATORS
8d772832 53 SetValidator(validator);
8d772832
RD
54#endif
55
04165bec
RR
56 return ret;
57}
58
f68586e5
VZ
59wxSize wxControl::DoGetBestSize() const
60{
0279e844
RR
61 // Do not return any arbitrary default value...
62 wxASSERT_MSG( m_widget, wxT("DoGetBestSize called before creation") );
63
f68586e5 64 GtkRequisition req;
33720b2d
RR
65 req.width = 2;
66 req.height = 2;
2afa14f2 67 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_widget) )->size_request )
f68586e5
VZ
68 (m_widget, &req );
69
9f884528
RD
70 wxSize best(req.width, req.height);
71 CacheBestSize(best);
72 return best;
f68586e5
VZ
73}
74
abdeb9e7
RD
75void wxControl::PostCreation(const wxSize& size)
76{
77 wxWindow::PostCreation();
f40fdaa3
VS
78
79 // NB: GetBestSize needs to know the style, otherwise it will assume
80 // default font and if the user uses a different font, determined
81 // best size will be different (typically, smaller) than the desired
82 // size. This call ensure that a style is available at the time
83 // GetBestSize is called.
84 gtk_widget_ensure_style(m_widget);
b2ff89d6 85
abdeb9e7 86 ApplyWidgetStyle();
170acdc9 87 SetInitialSize(size);
abdeb9e7
RD
88}
89
b2ff89d6
VZ
90// ----------------------------------------------------------------------------
91// wxControl dealing with labels
92// ----------------------------------------------------------------------------
93
39bc0347 94void wxControl::GTKSetLabelForLabel(GtkLabel *w, const wxString& label)
b2ff89d6 95{
39bc0347
VZ
96 // save the original label
97 wxControlBase::SetLabel(label);
b2ff89d6 98
39bc0347
VZ
99 const wxString labelGTK = GTKConvertMnemonics(label);
100 gtk_label_set_text_with_mnemonic(w, wxGTK_CONV(labelGTK));
b2ff89d6
VZ
101}
102
39bc0347 103void wxControl::GTKSetLabelWithMarkupForLabel(GtkLabel *w, const wxString& label)
b2ff89d6 104{
39bc0347
VZ
105 const wxString labelGTK = GTKConvertMnemonicsWithMarkup(label);
106 gtk_label_set_markup_with_mnemonic(w, wxGTK_CONV(labelGTK));
b2ff89d6
VZ
107}
108
b2ff89d6 109
2e1f5012
VZ
110// ----------------------------------------------------------------------------
111// GtkFrame helpers
112//
113// GtkFrames do in fact support mnemonics in GTK2+ but not through
114// gtk_frame_set_label, rather you need to use a custom label widget
115// instead (idea gleaned from the native gtk font dialog code in GTK)
116// ----------------------------------------------------------------------------
117
118GtkWidget* wxControl::GTKCreateFrame(const wxString& label)
119{
120 const wxString labelGTK = GTKConvertMnemonics(label);
121 GtkWidget* labelwidget = gtk_label_new_with_mnemonic(wxGTK_CONV(labelGTK));
122 gtk_widget_show(labelwidget); // without this it won't show...
123
124 GtkWidget* framewidget = gtk_frame_new(NULL);
125 gtk_frame_set_label_widget(GTK_FRAME(framewidget), labelwidget);
126
39bc0347
VZ
127 return framewidget; // note that the label is already set so you'll
128 // only need to call wxControl::SetLabel afterwards
2e1f5012
VZ
129}
130
b2ff89d6
VZ
131void wxControl::GTKSetLabelForFrame(GtkFrame *w, const wxString& label)
132{
2e1f5012
VZ
133 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
134 GTKSetLabelForLabel(labelwidget, label);
135}
136
137void wxControl::GTKFrameApplyWidgetStyle(GtkFrame* w, GtkRcStyle* style)
138{
139 gtk_widget_modify_style(GTK_WIDGET(w), style);
140 gtk_widget_modify_style(gtk_frame_get_label_widget (w), style);
141}
b2ff89d6 142
2e1f5012
VZ
143void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget)
144{
145 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
b2ff89d6 146
2e1f5012 147 gtk_label_set_mnemonic_widget(labelwidget, widget);
b2ff89d6
VZ
148}
149
2e1f5012 150// ----------------------------------------------------------------------------
39bc0347 151// worker function implementing GTK*Mnemonics() functions
2e1f5012
VZ
152// ----------------------------------------------------------------------------
153
b2ff89d6 154enum MnemonicsFlag
eaafd2f8 155{
b2ff89d6 156 MNEMONICS_REMOVE,
39bc0347
VZ
157 MNEMONICS_CONVERT,
158 MNEMONICS_CONVERT_MARKUP
b2ff89d6
VZ
159};
160
e0a050e3 161static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag)
b2ff89d6 162{
b2ff89d6 163 wxString labelGTK;
e0a050e3
VS
164 labelGTK.reserve(label.length());
165 for ( wxString::const_iterator i = label.begin(); i != label.end(); ++i )
eaafd2f8 166 {
e0a050e3 167 wxChar ch = *i;
b2ff89d6
VZ
168
169 switch ( ch )
eaafd2f8 170 {
b2ff89d6 171 case wxT('&'):
e0a050e3 172 if ( i + 1 == label.end() )
b2ff89d6
VZ
173 {
174 // "&" at the end of string is an error
39bc0347 175 wxLogDebug(wxT("Invalid label \"%s\"."), label);
b2ff89d6
VZ
176 break;
177 }
178
39bc0347
VZ
179 if ( flag == MNEMONICS_CONVERT_MARKUP )
180 {
181 bool isMnemonic = true;
e0a050e3 182 size_t distanceFromEnd = label.end() - i;
39bc0347
VZ
183
184 // is this ampersand introducing a mnemonic or rather an entity?
185 for (size_t j=0; j < wxMARKUP_ENTITY_MAX; j++)
186 {
187 const wxChar *entity = wxMarkupEntities[wxMARKUP_ELEMENT_NAME][j];
188 size_t entityLen = wxStrlen(entity);
189
e0a050e3
VS
190 if (distanceFromEnd >= entityLen &&
191 wxString(i, i + entityLen) == entity)
39bc0347
VZ
192 {
193 labelGTK << entity;
194 i += entityLen - 1; // the -1 is because main for()
195 // loop already increments i
196 isMnemonic = false;
197
198 break;
199 }
200 }
201
202 if (!isMnemonic)
203 continue;
204 }
205
e0a050e3 206 ch = *(++i); // skip '&' itself
b2ff89d6
VZ
207 switch ( ch )
208 {
209 case wxT('&'):
210 // special case: "&&" is not a mnemonic at all but just
211 // an escaped "&"
39bc0347
VZ
212 if ( flag == MNEMONICS_CONVERT_MARKUP )
213 labelGTK += wxT("&amp;");
214 else
215 labelGTK += wxT('&');
b2ff89d6
VZ
216 break;
217
218 case wxT('_'):
39bc0347 219 if ( flag != MNEMONICS_REMOVE )
b2ff89d6
VZ
220 {
221 // '_' can't be a GTK mnemonic apparently so
222 // replace it with something similar
223 labelGTK += wxT("_-");
224 break;
225 }
226 //else: fall through
227
228 default:
39bc0347 229 if ( flag != MNEMONICS_REMOVE )
b2ff89d6
VZ
230 labelGTK += wxT('_');
231 labelGTK += ch;
232 }
233 break;
234
235 case wxT('_'):
39bc0347 236 if ( flag != MNEMONICS_REMOVE )
b2ff89d6
VZ
237 {
238 // escape any existing underlines in the string so that
239 // they don't become mnemonics accidentally
240 labelGTK += wxT("__");
241 break;
242 }
243 //else: fall through
244
245 default:
246 labelGTK += ch;
eaafd2f8
VS
247 }
248 }
b2ff89d6
VZ
249
250 return labelGTK;
251}
252
253/* static */
254wxString wxControl::GTKRemoveMnemonics(const wxString& label)
255{
256 return GTKProcessMnemonics(label, MNEMONICS_REMOVE);
257}
258
259/* static */
260wxString wxControl::GTKConvertMnemonics(const wxString& label)
261{
262 return GTKProcessMnemonics(label, MNEMONICS_CONVERT);
eaafd2f8
VS
263}
264
39bc0347
VZ
265/* static */
266wxString wxControl::GTKConvertMnemonicsWithMarkup(const wxString& label)
267{
268 return GTKProcessMnemonics(label, MNEMONICS_CONVERT_MARKUP);
269}
270
b2ff89d6
VZ
271// ----------------------------------------------------------------------------
272// wxControl styles (a.k.a. attributes)
273// ----------------------------------------------------------------------------
9d522606
RD
274
275wxVisualAttributes wxControl::GetDefaultAttributes() const
276{
277 return GetDefaultAttributesFromGTKWidget(m_widget,
278 UseGTKStyleBase());
279}
280
9d522606
RD
281// static
282wxVisualAttributes
283wxControl::GetDefaultAttributesFromGTKWidget(GtkWidget* widget,
284 bool useBase,
285 int state)
286{
287 GtkStyle* style;
288 wxVisualAttributes attr;
289
290 style = gtk_rc_get_style(widget);
291 if (!style)
292 style = gtk_widget_get_default_style();
293
294 if (!style)
295 {
296 return wxWindow::GetClassDefaultAttributes(wxWINDOW_VARIANT_NORMAL);
297 }
298
299 if (state == -1)
300 state = GTK_STATE_NORMAL;
b2ff89d6 301
9d522606 302 // get the style's colours
cdf068a4 303 attr.colFg = wxColour(style->fg[state]);
9d522606 304 if (useBase)
cdf068a4 305 attr.colBg = wxColour(style->base[state]);
9d522606 306 else
cdf068a4 307 attr.colBg = wxColour(style->bg[state]);
9d522606
RD
308
309 // get the style's font
9d522606 310 if ( !style->font_desc )
b2ff89d6 311 style = gtk_widget_get_default_style();
9d522606 312 if ( style && style->font_desc )
b2ff89d6
VZ
313 {
314 wxNativeFontInfo info;
fdf7514a 315 info.description = pango_font_description_copy(style->font_desc);
b2ff89d6
VZ
316 attr.font = wxFont(info);
317 }
318 else
319 {
9d522606
RD
320 GtkSettings *settings = gtk_settings_get_default();
321 gchar *font_name = NULL;
322 g_object_get ( settings,
b2ff89d6 323 "gtk-font-name",
9d522606
RD
324 &font_name,
325 NULL);
326 if (!font_name)
327 attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
328 else
329 attr.font = wxFont(wxString::FromAscii(font_name));
330 g_free (font_name);
b2ff89d6 331 }
b2ff89d6 332
9d522606
RD
333 return attr;
334}
335
336
337//static
338wxVisualAttributes
865bb325 339wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNew_t widget_new,
9d522606
RD
340 bool useBase,
341 int state)
342{
343 wxVisualAttributes attr;
66d8fe77
VS
344 // NB: we need toplevel window so that GTK+ can find the right style
345 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9d522606 346 GtkWidget* widget = widget_new();
66d8fe77 347 gtk_container_add(GTK_CONTAINER(wnd), widget);
9d522606 348 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
66d8fe77 349 gtk_widget_destroy(wnd);
9d522606
RD
350 return attr;
351}
352
353//static
354wxVisualAttributes
865bb325 355wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromStr_t widget_new,
9d522606
RD
356 bool useBase,
357 int state)
358{
359 wxVisualAttributes attr;
66d8fe77
VS
360 // NB: we need toplevel window so that GTK+ can find the right style
361 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9d522606 362 GtkWidget* widget = widget_new("");
66d8fe77 363 gtk_container_add(GTK_CONTAINER(wnd), widget);
9d522606 364 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
66d8fe77 365 gtk_widget_destroy(wnd);
9d522606
RD
366 return attr;
367}
368
369
370//static
371wxVisualAttributes
865bb325 372wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromAdj_t widget_new,
9d522606
RD
373 bool useBase,
374 int state)
375{
376 wxVisualAttributes attr;
66d8fe77
VS
377 // NB: we need toplevel window so that GTK+ can find the right style
378 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9d522606 379 GtkWidget* widget = widget_new(NULL);
66d8fe77 380 gtk_container_add(GTK_CONTAINER(wnd), widget);
9d522606 381 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
66d8fe77 382 gtk_widget_destroy(wnd);
9d522606
RD
383 return attr;
384}
385
ef5c70f9
VZ
386// ----------------------------------------------------------------------------
387// idle handling
388// ----------------------------------------------------------------------------
389
390void wxControl::OnInternalIdle()
391{
392 if ( GtkShowFromOnIdle() )
393 return;
ef5c70f9 394
1f5cf9cc 395 if ( GTK_WIDGET_REALIZED(m_widget) )
6c6a3e8a
VZ
396 {
397 GTKUpdateCursor();
398
399 GTKSetDelayedFocusIfNeeded();
400 }
06a7419e 401
ef5c70f9
VZ
402 if ( wxUpdateUIEvent::CanUpdate(this) )
403 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
404}
405
1e6feb95 406#endif // wxUSE_CONTROLS