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