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