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