]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/anybutton.cpp
Force wide char environment version initialization in wxGetEnvMap().
[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
22#include "wx/gtk/private.h"
23
24// ----------------------------------------------------------------------------
25// GTK callbacks
26// ----------------------------------------------------------------------------
27
28extern "C"
29{
30
31static void
32wxgtk_button_enter_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
33{
34 if ( button->GTKShouldIgnoreEvent() )
35 return;
36
37 button->GTKMouseEnters();
38}
39
40static void
41wxgtk_button_leave_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
42{
43 if ( button->GTKShouldIgnoreEvent() )
44 return;
45
46 button->GTKMouseLeaves();
47}
48
49static void
50wxgtk_button_press_callback(GtkWidget *WXUNUSED(widget), wxAnyButton *button)
51{
52 if ( button->GTKShouldIgnoreEvent() )
53 return;
54
55 button->GTKPressed();
56}
57
58static void
59wxgtk_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
73bool 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
88GdkWindow *wxAnyButton::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
89{
90 return GTK_BUTTON(m_widget)->event_window;
91}
92
93// static
94wxVisualAttributes
95wxAnyButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
96{
97 return GetDefaultAttributesFromGTKWidget(gtk_button_new);
98}
99
100// ----------------------------------------------------------------------------
101// bitmaps support
102// ----------------------------------------------------------------------------
103
104void wxAnyButton::GTKMouseEnters()
105{
106 m_isCurrent = true;
107
108 GTKUpdateBitmap();
109}
110
111void wxAnyButton::GTKMouseLeaves()
112{
113 m_isCurrent = false;
114
115 GTKUpdateBitmap();
116}
117
118void wxAnyButton::GTKPressed()
119{
120 m_isPressed = true;
121
122 GTKUpdateBitmap();
123}
124
125void wxAnyButton::GTKReleased()
126{
127 m_isPressed = false;
128
129 GTKUpdateBitmap();
130}
131
132void wxAnyButton::GTKOnFocus(wxFocusEvent& event)
133{
134 event.Skip();
135
136 GTKUpdateBitmap();
137}
138
139wxAnyButton::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
156void 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
169void 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
204wxBitmap wxAnyButton::DoGetBitmap(State which) const
205{
206 return m_bitmaps[which];
207}
208
209void 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
387void 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