Move GDK_META_MASK definition in the header in which it is also used.
[wxWidgets.git] / src / gtk / anybutton.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/anybutton.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Created: 1998-05-20 (extracted from button.cpp)
6 // Id: $Id: anybutton.cpp 67326 2011-03-28 06:27:49Z PC $
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef wxHAS_ANY_BUTTON
15
16 #ifndef WX_PRECOMP
17 #include "wx/anybutton.h"
18 #endif
19
20 #include "wx/stockitem.h"
21
22 #include "wx/gtk/private.h"
23
24 // ----------------------------------------------------------------------------
25 // GTK callbacks
26 // ----------------------------------------------------------------------------
27
28 extern "C"
29 {
30
31 static void
32 wxgtk_button_enter_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
33 {
34 if ( button->GTKShouldIgnoreEvent() )
35 return;
36
37 button->GTKMouseEnters();
38 }
39
40 static void
41 wxgtk_button_leave_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
42 {
43 if ( button->GTKShouldIgnoreEvent() )
44 return;
45
46 button->GTKMouseLeaves();
47 }
48
49 static void
50 wxgtk_button_press_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
51 {
52 if ( button->GTKShouldIgnoreEvent() )
53 return;
54
55 button->GTKPressed();
56 }
57
58 static void
59 wxgtk_button_released_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
60 {
61 if ( button->GTKShouldIgnoreEvent() )
62 return;
63
64 button->GTKReleased();
65 }
66
67 } // extern "C"
68
69 //-----------------------------------------------------------------------------
70 // wxAnyButton
71 //-----------------------------------------------------------------------------
72
73 bool wxAnyButton::Enable( bool enable )
74 {
75 if (!base_type::Enable(enable))
76 return false;
77
78 gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(m_widget)), enable);
79
80 if (enable)
81 GTKFixSensitivity();
82
83 GTKUpdateBitmap();
84
85 return true;
86 }
87
88 GdkWindow *wxAnyButton::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
89 {
90 return GTK_BUTTON(m_widget)->event_window;
91 }
92
93 // static
94 wxVisualAttributes
95 wxAnyButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
96 {
97 return GetDefaultAttributesFromGTKWidget(gtk_button_new);
98 }
99
100 // ----------------------------------------------------------------------------
101 // bitmaps support
102 // ----------------------------------------------------------------------------
103
104 void wxAnyButton::GTKMouseEnters()
105 {
106 m_isCurrent = true;
107
108 GTKUpdateBitmap();
109 }
110
111 void wxAnyButton::GTKMouseLeaves()
112 {
113 m_isCurrent = false;
114
115 GTKUpdateBitmap();
116 }
117
118 void wxAnyButton::GTKPressed()
119 {
120 m_isPressed = true;
121
122 GTKUpdateBitmap();
123 }
124
125 void wxAnyButton::GTKReleased()
126 {
127 m_isPressed = false;
128
129 GTKUpdateBitmap();
130 }
131
132 void wxAnyButton::GTKOnFocus(wxFocusEvent& event)
133 {
134 event.Skip();
135
136 GTKUpdateBitmap();
137 }
138
139 wxAnyButton::State wxAnyButton::GTKGetCurrentState() const
140 {
141 if ( !IsThisEnabled() )
142 return m_bitmaps[State_Disabled].IsOk() ? State_Disabled : State_Normal;
143
144 if ( m_isPressed && m_bitmaps[State_Pressed].IsOk() )
145 return State_Pressed;
146
147 if ( m_isCurrent && m_bitmaps[State_Current].IsOk() )
148 return State_Current;
149
150 if ( HasFocus() && m_bitmaps[State_Focused].IsOk() )
151 return State_Focused;
152
153 return State_Normal;
154 }
155
156 void wxAnyButton::GTKUpdateBitmap()
157 {
158 // if we don't show bitmaps at all, there is nothing to update
159 if ( m_bitmaps[State_Normal].IsOk() )
160 {
161 // if we do show them, this will return a state for which we do have a
162 // valid bitmap
163 State state = GTKGetCurrentState();
164
165 GTKDoShowBitmap(m_bitmaps[state]);
166 }
167 }
168
169 void wxAnyButton::GTKDoShowBitmap(const wxBitmap& bitmap)
170 {
171 wxASSERT_MSG( bitmap.IsOk(), "invalid bitmap" );
172
173 GtkWidget *image;
174 if ( DontShowLabel() )
175 {
176 image = gtk_bin_get_child(GTK_BIN(m_widget));
177 }
178 else // have both label and bitmap
179 {
180 #ifdef __WXGTK26__
181 if ( !gtk_check_version(2,6,0) )
182 {
183 image = gtk_button_get_image(GTK_BUTTON(m_widget));
184 }
185 else
186 #endif // __WXGTK26__
187 {
188 // buttons with both label and bitmap are only supported with GTK+
189 // 2.6 so far
190 //
191 // it shouldn't be difficult to implement them ourselves for the
192 // previous GTK+ versions by stuffing a container with a label and
193 // an image inside GtkButton but there doesn't seem to be much
194 // point in doing this for ancient GTK+ versions
195 return;
196 }
197 }
198
199 wxCHECK_RET( image && GTK_IS_IMAGE(image), "must have image widget" );
200
201 gtk_image_set_from_pixbuf(GTK_IMAGE(image), bitmap.GetPixbuf());
202 }
203
204 wxBitmap wxAnyButton::DoGetBitmap(State which) const
205 {
206 return m_bitmaps[which];
207 }
208
209 void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which)
210 {
211 switch ( which )
212 {
213 case State_Normal:
214 if ( DontShowLabel() )
215 {
216 // we only have the bitmap in this button, never remove it but
217 // do invalidate the best size when the bitmap (and presumably
218 // its size) changes
219 InvalidateBestSize();
220 }
221 #ifdef __WXGTK26__
222 // normal image is special: setting it enables images for the button and
223 // resetting it to nothing disables all of them
224 else if ( !gtk_check_version(2,6,0) )
225 {
226 GtkWidget *image = gtk_button_get_image(GTK_BUTTON(m_widget));
227 if ( image && !bitmap.IsOk() )
228 {
229 gtk_container_remove(GTK_CONTAINER(m_widget), image);
230 }
231 else if ( !image && bitmap.IsOk() )
232 {
233 image = gtk_image_new();
234 gtk_button_set_image(GTK_BUTTON(m_widget), image);
235 }
236 else // image presence or absence didn't change
237 {
238 // don't invalidate best size below
239 break;
240 }
241
242 InvalidateBestSize();
243 }
244 #endif // GTK+ 2.6+
245 break;
246
247 case State_Pressed:
248 if ( bitmap.IsOk() )
249 {
250 if ( !m_bitmaps[which].IsOk() )
251 {
252 // we need to install the callbacks to be notified about
253 // the button pressed state change
254 g_signal_connect
255 (
256 m_widget,
257 "pressed",
258 G_CALLBACK(wxgtk_button_press_callback),
259 this
260 );
261
262 g_signal_connect
263 (
264 m_widget,
265 "released",
266 G_CALLBACK(wxgtk_button_released_callback),
267 this
268 );
269 }
270 }
271 else // no valid bitmap
272 {
273 if ( m_bitmaps[which].IsOk() )
274 {
275 // we don't need to be notified about the button pressed
276 // state changes any more
277 g_signal_handlers_disconnect_by_func
278 (
279 m_widget,
280 (gpointer)wxgtk_button_press_callback,
281 this
282 );
283
284 g_signal_handlers_disconnect_by_func
285 (
286 m_widget,
287 (gpointer)wxgtk_button_released_callback,
288 this
289 );
290
291 // also make sure we don't remain stuck in pressed state
292 if ( m_isPressed )
293 {
294 m_isPressed = false;
295 GTKUpdateBitmap();
296 }
297 }
298 }
299 break;
300
301 case State_Current:
302 // the logic here is the same as above for State_Pressed: we need
303 // to connect the handlers if we must be notified about the changes
304 // in the button current state and we disconnect them when/if we
305 // don't need them any more
306 if ( bitmap.IsOk() )
307 {
308 if ( !m_bitmaps[which].IsOk() )
309 {
310 g_signal_connect
311 (
312 m_widget,
313 "enter",
314 G_CALLBACK(wxgtk_button_enter_callback),
315 this
316 );
317
318 g_signal_connect
319 (
320 m_widget,
321 "leave",
322 G_CALLBACK(wxgtk_button_leave_callback),
323 this
324 );
325 }
326 }
327 else // no valid bitmap
328 {
329 if ( m_bitmaps[which].IsOk() )
330 {
331 g_signal_handlers_disconnect_by_func
332 (
333 m_widget,
334 (gpointer)wxgtk_button_enter_callback,
335 this
336 );
337
338 g_signal_handlers_disconnect_by_func
339 (
340 m_widget,
341 (gpointer)wxgtk_button_leave_callback,
342 this
343 );
344
345 if ( m_isCurrent )
346 {
347 m_isCurrent = false;
348 GTKUpdateBitmap();
349 }
350 }
351 }
352 break;
353
354 case State_Focused:
355 if ( bitmap.IsOk() )
356 {
357 Connect(wxEVT_SET_FOCUS,
358 wxFocusEventHandler(wxAnyButton::GTKOnFocus));
359 Connect(wxEVT_KILL_FOCUS,
360 wxFocusEventHandler(wxAnyButton::GTKOnFocus));
361 }
362 else // no valid focused bitmap
363 {
364 Disconnect(wxEVT_SET_FOCUS,
365 wxFocusEventHandler(wxAnyButton::GTKOnFocus));
366 Disconnect(wxEVT_KILL_FOCUS,
367 wxFocusEventHandler(wxAnyButton::GTKOnFocus));
368 }
369 break;
370
371 default:
372 // no callbacks to connect/disconnect
373 ;
374 }
375
376 m_bitmaps[which] = bitmap;
377
378 // update the bitmap immediately if necessary, otherwise it will be done
379 // when the bitmap for the corresponding state is needed the next time by
380 // GTKUpdateBitmap()
381 if ( bitmap.IsOk() && which == GTKGetCurrentState() )
382 {
383 GTKDoShowBitmap(bitmap);
384 }
385 }
386
387 void wxAnyButton::DoSetBitmapPosition(wxDirection dir)
388 {
389 #ifdef __WXGTK210__
390 if ( !gtk_check_version(2,10,0) )
391 {
392 GtkPositionType gtkpos;
393 switch ( dir )
394 {
395 default:
396 wxFAIL_MSG( "invalid position" );
397 // fall through
398
399 case wxLEFT:
400 gtkpos = GTK_POS_LEFT;
401 break;
402
403 case wxRIGHT:
404 gtkpos = GTK_POS_RIGHT;
405 break;
406
407 case wxTOP:
408 gtkpos = GTK_POS_TOP;
409 break;
410
411 case wxBOTTOM:
412 gtkpos = GTK_POS_BOTTOM;
413 break;
414 }
415
416 gtk_button_set_image_position(GTK_BUTTON(m_widget), gtkpos);
417 InvalidateBestSize();
418 }
419 #endif // GTK+ 2.10+
420 }
421
422 #endif // wxHAS_ANY_BUTTON