]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/control.cpp
correction to last commit: don't test unsetenv() return value, it's void under Darwin
[wxWidgets.git] / src / gtk / control.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/control.cpp
3 // Purpose: wxControl implementation for wxGTK
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart and Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_CONTROLS
14
15 #include "wx/control.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/log.h"
19 #include "wx/settings.h"
20 #endif
21
22 #include "wx/fontutil.h"
23 #include "wx/gtk/private.h"
24
25 #include "wx/private/stattext.h"
26
27
28 // ============================================================================
29 // wxControl implementation
30 // ============================================================================
31
32 // ----------------------------------------------------------------------------
33 // wxControl creation
34 // ----------------------------------------------------------------------------
35
36 IMPLEMENT_DYNAMIC_CLASS(wxControl, wxWindow)
37
38 wxControl::wxControl()
39 {
40 }
41
42 bool wxControl::Create( wxWindow *parent,
43 wxWindowID id,
44 const wxPoint &pos,
45 const wxSize &size,
46 long style,
47 const wxValidator& validator,
48 const wxString &name )
49 {
50 bool ret = wxWindow::Create(parent, id, pos, size, style, name);
51
52 #if wxUSE_VALIDATORS
53 SetValidator(validator);
54 #endif
55
56 return ret;
57 }
58
59 wxSize wxControl::DoGetBestSize() const
60 {
61 // Do not return any arbitrary default value...
62 wxASSERT_MSG( m_widget, wxT("DoGetBestSize called before creation") );
63
64 GtkRequisition req;
65 req.width = 2;
66 req.height = 2;
67 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_widget) )->size_request )
68 (m_widget, &req );
69
70 wxSize best(req.width, req.height);
71 CacheBestSize(best);
72 return best;
73 }
74
75 void wxControl::PostCreation(const wxSize& size)
76 {
77 wxWindow::PostCreation();
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);
85
86 ApplyWidgetStyle();
87 SetInitialSize(size);
88 }
89
90 // ----------------------------------------------------------------------------
91 // wxControl dealing with labels
92 // ----------------------------------------------------------------------------
93
94 void wxControl::GTKSetLabelForLabel(GtkLabel *w, const wxString& label)
95 {
96 // save the original label
97 wxControlBase::SetLabel(label);
98
99 const wxString labelGTK = GTKConvertMnemonics(label);
100 gtk_label_set_text_with_mnemonic(w, wxGTK_CONV(labelGTK));
101 }
102
103 void wxControl::GTKSetLabelWithMarkupForLabel(GtkLabel *w, const wxString& label)
104 {
105 const wxString labelGTK = GTKConvertMnemonicsWithMarkup(label);
106 gtk_label_set_markup_with_mnemonic(w, wxGTK_CONV(labelGTK));
107 }
108
109
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
118 GtkWidget* 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
127 return framewidget; // note that the label is already set so you'll
128 // only need to call wxControl::SetLabel afterwards
129 }
130
131 void wxControl::GTKSetLabelForFrame(GtkFrame *w, const wxString& label)
132 {
133 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
134 GTKSetLabelForLabel(labelwidget, label);
135 }
136
137 void 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 }
142
143 void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget)
144 {
145 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
146
147 gtk_label_set_mnemonic_widget(labelwidget, widget);
148 }
149
150 // ----------------------------------------------------------------------------
151 // worker function implementing GTK*Mnemonics() functions
152 // ----------------------------------------------------------------------------
153
154 enum MnemonicsFlag
155 {
156 MNEMONICS_REMOVE,
157 MNEMONICS_CONVERT,
158 MNEMONICS_CONVERT_MARKUP
159 };
160
161 static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag)
162 {
163 wxString labelGTK;
164 labelGTK.reserve(label.length());
165 for ( wxString::const_iterator i = label.begin(); i != label.end(); ++i )
166 {
167 wxChar ch = *i;
168
169 switch ( ch )
170 {
171 case wxT('&'):
172 if ( i + 1 == label.end() )
173 {
174 // "&" at the end of string is an error
175 wxLogDebug(wxT("Invalid label \"%s\"."), label);
176 break;
177 }
178
179 if ( flag == MNEMONICS_CONVERT_MARKUP )
180 {
181 bool isMnemonic = true;
182 size_t distanceFromEnd = label.end() - i;
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
190 if (distanceFromEnd >= entityLen &&
191 wxString(i, i + entityLen) == entity)
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
206 ch = *(++i); // skip '&' itself
207 switch ( ch )
208 {
209 case wxT('&'):
210 // special case: "&&" is not a mnemonic at all but just
211 // an escaped "&"
212 if ( flag == MNEMONICS_CONVERT_MARKUP )
213 labelGTK += wxT("&amp;");
214 else
215 labelGTK += wxT('&');
216 break;
217
218 case wxT('_'):
219 if ( flag != MNEMONICS_REMOVE )
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:
229 if ( flag != MNEMONICS_REMOVE )
230 labelGTK += wxT('_');
231 labelGTK += ch;
232 }
233 break;
234
235 case wxT('_'):
236 if ( flag != MNEMONICS_REMOVE )
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;
247 }
248 }
249
250 return labelGTK;
251 }
252
253 /* static */
254 wxString wxControl::GTKRemoveMnemonics(const wxString& label)
255 {
256 return GTKProcessMnemonics(label, MNEMONICS_REMOVE);
257 }
258
259 /* static */
260 wxString wxControl::GTKConvertMnemonics(const wxString& label)
261 {
262 return GTKProcessMnemonics(label, MNEMONICS_CONVERT);
263 }
264
265 /* static */
266 wxString wxControl::GTKConvertMnemonicsWithMarkup(const wxString& label)
267 {
268 return GTKProcessMnemonics(label, MNEMONICS_CONVERT_MARKUP);
269 }
270
271 // ----------------------------------------------------------------------------
272 // wxControl styles (a.k.a. attributes)
273 // ----------------------------------------------------------------------------
274
275 wxVisualAttributes wxControl::GetDefaultAttributes() const
276 {
277 return GetDefaultAttributesFromGTKWidget(m_widget,
278 UseGTKStyleBase());
279 }
280
281 // static
282 wxVisualAttributes
283 wxControl::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;
301
302 // get the style's colours
303 attr.colFg = wxColour(style->fg[state]);
304 if (useBase)
305 attr.colBg = wxColour(style->base[state]);
306 else
307 attr.colBg = wxColour(style->bg[state]);
308
309 // get the style's font
310 if ( !style->font_desc )
311 style = gtk_widget_get_default_style();
312 if ( style && style->font_desc )
313 {
314 wxNativeFontInfo info;
315 info.description = pango_font_description_copy(style->font_desc);
316 attr.font = wxFont(info);
317 }
318 else
319 {
320 GtkSettings *settings = gtk_settings_get_default();
321 gchar *font_name = NULL;
322 g_object_get ( settings,
323 "gtk-font-name",
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);
331 }
332
333 return attr;
334 }
335
336
337 //static
338 wxVisualAttributes
339 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNew_t widget_new,
340 bool useBase,
341 int state)
342 {
343 wxVisualAttributes attr;
344 // NB: we need toplevel window so that GTK+ can find the right style
345 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
346 GtkWidget* widget = widget_new();
347 gtk_container_add(GTK_CONTAINER(wnd), widget);
348 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
349 gtk_widget_destroy(wnd);
350 return attr;
351 }
352
353 //static
354 wxVisualAttributes
355 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromStr_t widget_new,
356 bool useBase,
357 int state)
358 {
359 wxVisualAttributes attr;
360 // NB: we need toplevel window so that GTK+ can find the right style
361 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
362 GtkWidget* widget = widget_new("");
363 gtk_container_add(GTK_CONTAINER(wnd), widget);
364 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
365 gtk_widget_destroy(wnd);
366 return attr;
367 }
368
369
370 //static
371 wxVisualAttributes
372 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromAdj_t widget_new,
373 bool useBase,
374 int state)
375 {
376 wxVisualAttributes attr;
377 // NB: we need toplevel window so that GTK+ can find the right style
378 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
379 GtkWidget* widget = widget_new(NULL);
380 gtk_container_add(GTK_CONTAINER(wnd), widget);
381 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
382 gtk_widget_destroy(wnd);
383 return attr;
384 }
385
386 // ----------------------------------------------------------------------------
387 // idle handling
388 // ----------------------------------------------------------------------------
389
390 void wxControl::OnInternalIdle()
391 {
392 if ( GtkShowFromOnIdle() )
393 return;
394
395 if ( GTK_WIDGET_REALIZED(m_widget) )
396 {
397 GTKUpdateCursor();
398
399 GTKSetDelayedFocusIfNeeded();
400 }
401
402 if ( wxUpdateUIEvent::CanUpdate(this) )
403 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
404 }
405
406 #endif // wxUSE_CONTROLS