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