shouldn't update cursor for hidden windows
[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 SetInitialBestSize(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
256 #define SHIFT (8*(sizeof(short int)-sizeof(char)))
257
258 // static
259 wxVisualAttributes
260 wxControl::GetDefaultAttributesFromGTKWidget(GtkWidget* widget,
261 bool useBase,
262 int state)
263 {
264 GtkStyle* style;
265 wxVisualAttributes attr;
266
267 style = gtk_rc_get_style(widget);
268 if (!style)
269 style = gtk_widget_get_default_style();
270
271 if (!style)
272 {
273 return wxWindow::GetClassDefaultAttributes(wxWINDOW_VARIANT_NORMAL);
274 }
275
276 if (state == -1)
277 state = GTK_STATE_NORMAL;
278
279 // get the style's colours
280 attr.colFg = wxColour(style->fg[state].red >> SHIFT,
281 style->fg[state].green >> SHIFT,
282 style->fg[state].blue >> SHIFT);
283 if (useBase)
284 attr.colBg = wxColour(style->base[state].red >> SHIFT,
285 style->base[state].green >> SHIFT,
286 style->base[state].blue >> SHIFT);
287 else
288 attr.colBg = wxColour(style->bg[state].red >> SHIFT,
289 style->bg[state].green >> SHIFT,
290 style->bg[state].blue >> SHIFT);
291
292 // get the style's font
293 if ( !style->font_desc )
294 style = gtk_widget_get_default_style();
295 if ( style && style->font_desc )
296 {
297 wxNativeFontInfo info;
298 info.description = pango_font_description_copy(style->font_desc);
299 attr.font = wxFont(info);
300 }
301 else
302 {
303 GtkSettings *settings = gtk_settings_get_default();
304 gchar *font_name = NULL;
305 g_object_get ( settings,
306 "gtk-font-name",
307 &font_name,
308 NULL);
309 if (!font_name)
310 attr.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
311 else
312 attr.font = wxFont(wxString::FromAscii(font_name));
313 g_free (font_name);
314 }
315
316 return attr;
317 }
318
319
320 //static
321 wxVisualAttributes
322 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNew_t widget_new,
323 bool useBase,
324 int state)
325 {
326 wxVisualAttributes attr;
327 // NB: we need toplevel window so that GTK+ can find the right style
328 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
329 GtkWidget* widget = widget_new();
330 gtk_container_add(GTK_CONTAINER(wnd), widget);
331 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
332 gtk_widget_destroy(wnd);
333 return attr;
334 }
335
336 //static
337 wxVisualAttributes
338 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromStr_t widget_new,
339 bool useBase,
340 int state)
341 {
342 wxVisualAttributes attr;
343 // NB: we need toplevel window so that GTK+ can find the right style
344 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
345 GtkWidget* widget = widget_new("");
346 gtk_container_add(GTK_CONTAINER(wnd), widget);
347 attr = GetDefaultAttributesFromGTKWidget(widget, useBase, state);
348 gtk_widget_destroy(wnd);
349 return attr;
350 }
351
352
353 //static
354 wxVisualAttributes
355 wxControl::GetDefaultAttributesFromGTKWidget(wxGtkWidgetNewFromAdj_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(NULL);
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 // idle handling
371 // ----------------------------------------------------------------------------
372
373 void wxControl::OnInternalIdle()
374 {
375 if ( GtkShowFromOnIdle() )
376 return;
377
378 if ( IsShown() )
379 {
380 GTKUpdateCursor();
381
382 GTKSetDelayedFocusIfNeeded();
383 }
384
385 if ( wxUpdateUIEvent::CanUpdate(this) )
386 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
387 }
388
389 #endif // wxUSE_CONTROLS