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