moved wxapp_install_idle_handler and g_isIdle from many cpp files into gtk/private...
[wxWidgets.git] / src / gtk / tglbtn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/gtk/tglbtn.cpp
3 // Purpose: Definition of the wxToggleButton class, which implements a
4 // toggle button under wxGTK.
5 // Author: John Norris, minor changes by Axel Schlueter
6 // Modified by:
7 // Created: 08.02.01
8 // RCS-ID: $Id$
9 // Copyright: (c) 2000 Johnny C. Norris II
10 // License: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15
16 #include "wx/tglbtn.h"
17 #include "wx/button.h"
18
19 #if wxUSE_TOGGLEBTN
20
21 // FIXME: Use GtkImage instead of GtkPixmap.
22 #include <gtk/gtkversion.h>
23 #ifdef GTK_DISABLE_DEPRECATED
24 #undef GTK_DISABLE_DEPRECATED
25 #endif
26
27 #include "wx/gtk/private.h"
28
29 extern bool g_blockEventsOnDrag;
30 extern wxCursor g_globalCursor;
31
32 extern "C" {
33 static void gtk_togglebutton_clicked_callback(GtkWidget *WXUNUSED(widget), wxToggleButton *cb)
34 {
35 if (g_isIdle)
36 wxapp_install_idle_handler();
37
38 if (!cb->m_hasVMT || g_blockEventsOnDrag)
39 return;
40
41 if (cb->m_blockEvent) return;
42
43 // Generate a wx event.
44 wxCommandEvent event(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, cb->GetId());
45 event.SetInt(cb->GetValue());
46 event.SetEventObject(cb);
47 cb->GetEventHandler()->ProcessEvent(event);
48 }
49 }
50
51 DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED)
52
53 // ------------------------------------------------------------------------
54 // wxToggleBitmapButton
55 // ------------------------------------------------------------------------
56
57 IMPLEMENT_DYNAMIC_CLASS(wxToggleBitmapButton, wxControl)
58
59 bool wxToggleBitmapButton::Create(wxWindow *parent, wxWindowID id,
60 const wxBitmap &label, const wxPoint &pos,
61 const wxSize &size, long style,
62 const wxValidator& validator,
63 const wxString &name)
64 {
65 m_needParent = true;
66 m_acceptsFocus = true;
67
68 m_blockEvent = false;
69
70 if (!PreCreation(parent, pos, size) ||
71 !CreateBase(parent, id, pos, size, style, validator, name ))
72 {
73 wxFAIL_MSG(wxT("wxToggleBitmapButton creation failed"));
74 return false;
75 }
76
77 m_bitmap = label;
78
79 // Create the gtk widget.
80 m_widget = gtk_toggle_button_new();
81
82 if (style & wxNO_BORDER)
83 gtk_button_set_relief( GTK_BUTTON(m_widget), GTK_RELIEF_NONE );
84
85 if (m_bitmap.Ok())
86 {
87 OnSetBitmap();
88 }
89
90 g_signal_connect (m_widget, "clicked",
91 G_CALLBACK (gtk_togglebutton_clicked_callback),
92 this);
93
94 m_parent->DoAddChild(this);
95
96 PostCreation(size);
97
98 return true;
99 }
100
101 // void SetValue(bool state)
102 // Set the value of the toggle button.
103 void wxToggleBitmapButton::SetValue(bool state)
104 {
105 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
106
107 if (state == GetValue())
108 return;
109
110 m_blockEvent = true;
111
112 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_widget), state);
113
114 m_blockEvent = false;
115 }
116
117 // bool GetValue() const
118 // Get the value of the toggle button.
119 bool wxToggleBitmapButton::GetValue() const
120 {
121 wxCHECK_MSG(m_widget != NULL, false, wxT("invalid toggle button"));
122
123 return GTK_TOGGLE_BUTTON(m_widget)->active;
124 }
125
126 void wxToggleBitmapButton::SetLabel(const wxBitmap& label)
127 {
128 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
129
130 m_bitmap = label;
131 InvalidateBestSize();
132
133 OnSetBitmap();
134 }
135
136 void wxToggleBitmapButton::OnSetBitmap()
137 {
138 if (!m_bitmap.Ok()) return;
139
140 GdkBitmap *mask = (GdkBitmap *) NULL;
141 if (m_bitmap.GetMask()) mask = m_bitmap.GetMask()->GetBitmap();
142
143 GtkWidget *child = GTK_BIN(m_widget)->child;
144 if (child == NULL)
145 {
146 // initial bitmap
147 GtkWidget *pixmap = gtk_pixmap_new(m_bitmap.GetPixmap(), mask);
148 gtk_widget_show(pixmap);
149 gtk_container_add(GTK_CONTAINER(m_widget), pixmap);
150 }
151 else
152 { // subsequent bitmaps
153 GtkPixmap *g_pixmap = GTK_PIXMAP(child);
154 gtk_pixmap_set(g_pixmap, m_bitmap.GetPixmap(), mask);
155 }
156 }
157
158 bool wxToggleBitmapButton::Enable(bool enable /*=true*/)
159 {
160 if (!wxControl::Enable(enable))
161 return false;
162
163 gtk_widget_set_sensitive(GTK_BIN(m_widget)->child, enable);
164
165 return true;
166 }
167
168 void wxToggleBitmapButton::DoApplyWidgetStyle(GtkRcStyle *style)
169 {
170 gtk_widget_modify_style(m_widget, style);
171 gtk_widget_modify_style(GTK_BIN(m_widget)->child, style);
172 }
173
174 bool wxToggleBitmapButton::IsOwnGtkWindow(GdkWindow *window)
175 {
176 return window == GTK_BUTTON(m_widget)->event_window;
177 }
178
179 void wxToggleBitmapButton::OnInternalIdle()
180 {
181 wxCursor cursor = m_cursor;
182
183 if (g_globalCursor.Ok())
184 cursor = g_globalCursor;
185
186 GdkWindow *win = GTK_BUTTON(m_widget)->event_window;
187 if ( win && cursor.Ok() )
188 {
189 /* I now set the cursor the anew in every OnInternalIdle call
190 as setting the cursor in a parent window also effects the
191 windows above so that checking for the current cursor is
192 not possible. */
193
194 gdk_window_set_cursor(win, cursor.GetCursor());
195 }
196
197 if (wxUpdateUIEvent::CanUpdate(this))
198 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
199 }
200
201
202 // Get the "best" size for this control.
203 wxSize wxToggleBitmapButton::DoGetBestSize() const
204 {
205 wxSize best;
206
207 if (m_bitmap.Ok())
208 {
209 int border = HasFlag(wxNO_BORDER) ? 4 : 10;
210 best.x = m_bitmap.GetWidth()+border;
211 best.y = m_bitmap.GetHeight()+border;
212 }
213 CacheBestSize(best);
214 return best;
215 }
216
217
218 // static
219 wxVisualAttributes
220 wxToggleBitmapButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
221 {
222 return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new);
223 }
224
225
226 // ------------------------------------------------------------------------
227 // wxToggleButton
228 // ------------------------------------------------------------------------
229
230 IMPLEMENT_DYNAMIC_CLASS(wxToggleButton, wxControl)
231
232 bool wxToggleButton::Create(wxWindow *parent, wxWindowID id,
233 const wxString &label, const wxPoint &pos,
234 const wxSize &size, long style,
235 const wxValidator& validator,
236 const wxString &name)
237 {
238 m_needParent = true;
239 m_acceptsFocus = true;
240
241 m_blockEvent = false;
242
243 if (!PreCreation(parent, pos, size) ||
244 !CreateBase(parent, id, pos, size, style, validator, name )) {
245 wxFAIL_MSG(wxT("wxToggleButton creation failed"));
246 return false;
247 }
248
249 wxControl::SetLabel(label);
250
251 // Create the gtk widget.
252 m_widget = gtk_toggle_button_new_with_label( wxGTK_CONV( m_label ) );
253
254 g_signal_connect (m_widget, "clicked",
255 G_CALLBACK (gtk_togglebutton_clicked_callback),
256 this);
257
258 m_parent->DoAddChild(this);
259
260 PostCreation(size);
261
262 return true;
263 }
264
265 // void SetValue(bool state)
266 // Set the value of the toggle button.
267 void wxToggleButton::SetValue(bool state)
268 {
269 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
270
271 if (state == GetValue())
272 return;
273
274 m_blockEvent = true;
275
276 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_widget), state);
277
278 m_blockEvent = false;
279 }
280
281 // bool GetValue() const
282 // Get the value of the toggle button.
283 bool wxToggleButton::GetValue() const
284 {
285 wxCHECK_MSG(m_widget != NULL, false, wxT("invalid toggle button"));
286
287 return GTK_TOGGLE_BUTTON(m_widget)->active;
288 }
289
290 void wxToggleButton::SetLabel(const wxString& label)
291 {
292 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
293
294 wxControl::SetLabel(label);
295
296 gtk_label_set_text(GTK_LABEL(GTK_BIN(m_widget)->child), wxGTK_CONV(GetLabel()));
297 }
298
299 bool wxToggleButton::Enable(bool enable /*=true*/)
300 {
301 if (!wxControl::Enable(enable))
302 return false;
303
304 gtk_widget_set_sensitive(GTK_BIN(m_widget)->child, enable);
305
306 return true;
307 }
308
309 void wxToggleButton::DoApplyWidgetStyle(GtkRcStyle *style)
310 {
311 gtk_widget_modify_style(m_widget, style);
312 gtk_widget_modify_style(GTK_BIN(m_widget)->child, style);
313 }
314
315 bool wxToggleButton::IsOwnGtkWindow(GdkWindow *window)
316 {
317 return window == GTK_BUTTON(m_widget)->event_window;
318 }
319
320 void wxToggleButton::OnInternalIdle()
321 {
322 wxCursor cursor = m_cursor;
323
324 if (g_globalCursor.Ok())
325 cursor = g_globalCursor;
326
327 GdkWindow *win = GTK_BUTTON(m_widget)->event_window;
328 if ( win && cursor.Ok() )
329 {
330 /* I now set the cursor the anew in every OnInternalIdle call
331 as setting the cursor in a parent window also effects the
332 windows above so that checking for the current cursor is
333 not possible. */
334
335 gdk_window_set_cursor(win, cursor.GetCursor());
336 }
337
338 if (wxUpdateUIEvent::CanUpdate(this))
339 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
340 }
341
342
343 // Get the "best" size for this control.
344 wxSize wxToggleButton::DoGetBestSize() const
345 {
346 wxSize ret(wxControl::DoGetBestSize());
347
348 if (!HasFlag(wxBU_EXACTFIT))
349 {
350 if (ret.x < 80) ret.x = 80;
351 }
352
353 CacheBestSize(ret);
354 return ret;
355 }
356
357 // static
358 wxVisualAttributes
359 wxToggleButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
360 {
361 return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new);
362 }
363
364 #endif // wxUSE_TOGGLEBTN
365