]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/control.cpp
rebaked after adding new string-related headers
[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 // ============================================================================
26 // wxControl implementation
27 // ============================================================================
28
29 // ----------------------------------------------------------------------------
30 // wxControl creation
31 // ----------------------------------------------------------------------------
32
33 IMPLEMENT_DYNAMIC_CLASS(wxControl, wxWindow)
34
35 wxControl::wxControl()
36 {
37 m_needParent = true;
38 }
39
40 bool wxControl::Create( wxWindow *parent,
41 wxWindowID id,
42 const wxPoint &pos,
43 const wxSize &size,
44 long style,
45 const wxValidator& validator,
46 const wxString &name )
47 {
48 bool ret = wxWindow::Create(parent, id, pos, size, style, name);
49
50 #if wxUSE_VALIDATORS
51 SetValidator(validator);
52 #endif
53
54 return ret;
55 }
56
57 wxSize wxControl::DoGetBestSize() const
58 {
59 // Do not return any arbitrary default value...
60 wxASSERT_MSG( m_widget, wxT("DoGetBestSize called before creation") );
61
62 GtkRequisition req;
63 req.width = 2;
64 req.height = 2;
65 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_widget) )->size_request )
66 (m_widget, &req );
67
68 wxSize best(req.width, req.height);
69 CacheBestSize(best);
70 return best;
71 }
72
73 void wxControl::PostCreation(const wxSize& size)
74 {
75 wxWindow::PostCreation();
76
77 // NB: GetBestSize needs to know the style, otherwise it will assume
78 // default font and if the user uses a different font, determined
79 // best size will be different (typically, smaller) than the desired
80 // size. This call ensure that a style is available at the time
81 // GetBestSize is called.
82 gtk_widget_ensure_style(m_widget);
83
84 ApplyWidgetStyle();
85 SetInitialSize(size);
86 }
87
88 // ----------------------------------------------------------------------------
89 // wxControl dealing with labels
90 // ----------------------------------------------------------------------------
91
92 void wxControl::SetLabel( const wxString &label )
93 {
94 // keep the original string internally to be able to return it later (for
95 // consistency with the other ports)
96 m_label = label;
97
98 InvalidateBestSize();
99 }
100
101 wxString wxControl::GetLabel() const
102 {
103 return m_label;
104 }
105
106 void wxControl::GTKSetLabelForLabel(GtkLabel *w, const wxString& label)
107 {
108 // don't call the virtual function which might call this one back again
109 wxControl::SetLabel(label);
110
111 const wxString labelGTK = GTKConvertMnemonics(label);
112
113 gtk_label_set_text_with_mnemonic(w, wxGTK_CONV(labelGTK));
114 }
115
116 // ----------------------------------------------------------------------------
117 // GtkFrame helpers
118 //
119 // GtkFrames do in fact support mnemonics in GTK2+ but not through
120 // gtk_frame_set_label, rather you need to use a custom label widget
121 // instead (idea gleaned from the native gtk font dialog code in GTK)
122 // ----------------------------------------------------------------------------
123
124 GtkWidget* wxControl::GTKCreateFrame(const wxString& label)
125 {
126 const wxString labelGTK = GTKConvertMnemonics(label);
127 GtkWidget* labelwidget = gtk_label_new_with_mnemonic(wxGTK_CONV(labelGTK));
128 gtk_widget_show(labelwidget); // without this it won't show...
129
130 GtkWidget* framewidget = gtk_frame_new(NULL);
131 gtk_frame_set_label_widget(GTK_FRAME(framewidget), labelwidget);
132
133 return framewidget; //note that the label is already set so you'll
134 //only need to call wxControl::SetLabel afterwards
135 }
136
137 void wxControl::GTKSetLabelForFrame(GtkFrame *w, const wxString& label)
138 {
139 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
140 GTKSetLabelForLabel(labelwidget, label);
141 }
142
143 void wxControl::GTKFrameApplyWidgetStyle(GtkFrame* w, GtkRcStyle* style)
144 {
145 gtk_widget_modify_style(GTK_WIDGET(w), style);
146 gtk_widget_modify_style(gtk_frame_get_label_widget (w), style);
147 }
148
149 void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget)
150 {
151 GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w));
152
153 gtk_label_set_mnemonic_widget(labelwidget, widget);
154 }
155
156 // ----------------------------------------------------------------------------
157 // worker function implementing both GTKConvert/RemoveMnemonics()
158 //
159 // notice that under GTK+ 1 we only really need to support MNEMONICS_REMOVE as
160 // it doesn't support mnemonics anyhow but this would make the code so ugly
161 // that we do the same thing for GKT+ 1 and 2
162 // ----------------------------------------------------------------------------
163
164 enum MnemonicsFlag
165 {
166 MNEMONICS_REMOVE,
167 MNEMONICS_CONVERT
168 };
169
170 static wxString GTKProcessMnemonics(const wxString& label, MnemonicsFlag flag)
171 {
172 const size_t len = label.length();
173 wxString labelGTK;
174 labelGTK.reserve(len);
175 for ( size_t i = 0; i < len; i++ )
176 {
177 wxChar ch = label[i];
178
179 switch ( ch )
180 {
181 case wxT('&'):
182 if ( i == len - 1 )
183 {
184 // "&" at the end of string is an error
185 wxLogDebug(wxT("Invalid label \"%s\"."), label.c_str());
186 break;
187 }
188
189 ch = label[++i]; // skip '&' itself
190 switch ( ch )
191 {
192 case wxT('&'):
193 // special case: "&&" is not a mnemonic at all but just
194 // an escaped "&"
195 labelGTK += wxT('&');
196 break;
197
198 case wxT('_'):
199 if ( flag == MNEMONICS_CONVERT )
200 {
201 // '_' can't be a GTK mnemonic apparently so
202 // replace it with something similar
203 labelGTK += wxT("_-");
204 break;
205 }
206 //else: fall through
207
208 default:
209 if ( flag == MNEMONICS_CONVERT )
210 labelGTK += wxT('_');
211 labelGTK += ch;
212 }
213 break;
214
215 case wxT('_'):
216 if ( flag == MNEMONICS_CONVERT )
217 {
218 // escape any existing underlines in the string so that
219 // they don't become mnemonics accidentally
220 labelGTK += wxT("__");
221 break;
222 }
223 //else: fall through
224
225 default:
226 labelGTK += ch;
227 }
228 }
229
230 return labelGTK;
231 }
232
233 /* static */
234 wxString wxControl::GTKRemoveMnemonics(const wxString& label)
235 {
236 return GTKProcessMnemonics(label, MNEMONICS_REMOVE);
237 }
238
239 /* static */
240 wxString wxControl::GTKConvertMnemonics(const wxString& label)
241 {
242 return GTKProcessMnemonics(label, MNEMONICS_CONVERT);
243 }
244
245 // ----------------------------------------------------------------------------
246 // wxControl styles (a.k.a. attributes)
247 // ----------------------------------------------------------------------------
248
249 wxVisualAttributes wxControl::GetDefaultAttributes() const
250 {
251 return GetDefaultAttributesFromGTKWidget(m_widget,
252 UseGTKStyleBase());
253 }
254
255 // static
256 wxVisualAttributes
257 wxControl::GetDefaultAttributesFromGTKWidget(GtkWidget* widget,
258 bool useBase,
259 int state)
260 {
261 GtkStyle* style;
262 wxVisualAttributes attr;
263
264 style = gtk_rc_get_style(widget);
265 if (!style)
266 style = gtk_widget_get_default_style();
267
268 if (!style)
269 {
270 return wxWindow::GetClassDefaultAttributes(wxWINDOW_VARIANT_NORMAL);
271 }
272
273 if (state == -1)
274 state = GTK_STATE_NORMAL;
275
276 // get the style's colours
277 attr.colFg = wxColour(style->fg[state]);
278 if (useBase)
279 attr.colBg = wxColour(style->base[state]);
280 else
281 attr.colBg = wxColour(style->bg[state]);
282
283 // get the style's font
284 if ( !style->font_desc )
285 style = gtk_widget_get_default_style();
286 if ( style && style->font_desc )
287 {
288 wxNativeFontInfo info;
289 info.description = pango_font_description_copy(style->font_desc);
290 attr.font = wxFont(info);
291 }
292 else
293 {
294 GtkSettings *settings = gtk_settings_get_default();
295 gchar *font_name = NULL;
296 g_object_get ( settings,
297 "gtk-font-name",
298 &font_name,
299 NULL);
300 if (!font_name)
301 attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
302 else
303 attr.font = wxFont(wxString::FromAscii(font_name));
304 g_free (font_name);
305 }
306
307 return attr;
308 }
309
310
311 //static
312 wxVisualAttributes
313 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNew_t widget_new,
314 bool useBase,
315 int state)
316 {
317 wxVisualAttributes attr;
318 // NB: we need toplevel window so that GTK+ can find the right style
319 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
320 GtkWidget* widget = widget_new();
321 gtk_container_add(GTK_CONTAINER(wnd), widget);
322 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
323 gtk_widget_destroy(wnd);
324 return attr;
325 }
326
327 //static
328 wxVisualAttributes
329 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromStr_t widget_new,
330 bool useBase,
331 int state)
332 {
333 wxVisualAttributes attr;
334 // NB: we need toplevel window so that GTK+ can find the right style
335 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
336 GtkWidget* widget = widget_new("");
337 gtk_container_add(GTK_CONTAINER(wnd), widget);
338 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
339 gtk_widget_destroy(wnd);
340 return attr;
341 }
342
343
344 //static
345 wxVisualAttributes
346 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromAdj_t widget_new,
347 bool useBase,
348 int state)
349 {
350 wxVisualAttributes attr;
351 // NB: we need toplevel window so that GTK+ can find the right style
352 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
353 GtkWidget* widget = widget_new(NULL);
354 gtk_container_add(GTK_CONTAINER(wnd), widget);
355 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
356 gtk_widget_destroy(wnd);
357 return attr;
358 }
359
360 // ----------------------------------------------------------------------------
361 // idle handling
362 // ----------------------------------------------------------------------------
363
364 void wxControl::OnInternalIdle()
365 {
366 if ( GtkShowFromOnIdle() )
367 return;
368
369 if ( GTK_WIDGET_REALIZED(m_widget) )
370 {
371 GTKUpdateCursor();
372
373 GTKSetDelayedFocusIfNeeded();
374 }
375
376 if ( wxUpdateUIEvent::CanUpdate(this) )
377 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
378 }
379
380 #endif // wxUSE_CONTROLS