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