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 // 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 <gtk/gtk.h>
24 #include "wx/gtk/private.h"
25 #include "wx/gtk/private/list.h"
26 
27 extern bool      g_blockEventsOnDrag;
28 
29 extern "C" {
gtk_togglebutton_clicked_callback(GtkWidget * WXUNUSED (widget),wxToggleButton * cb)30 static void gtk_togglebutton_clicked_callback(GtkWidget *WXUNUSED(widget), wxToggleButton *cb)
31 {
32     if (g_blockEventsOnDrag)
33         return;
34 
35     // Generate a wx event.
36     wxCommandEvent event(wxEVT_TOGGLEBUTTON, cb->GetId());
37     event.SetInt(cb->GetValue());
38     event.SetEventObject(cb);
39     cb->HandleWindowEvent(event);
40 }
41 }
42 
43 wxDEFINE_EVENT( wxEVT_TOGGLEBUTTON, wxCommandEvent );
44 
45 // ------------------------------------------------------------------------
46 // wxBitmapToggleButton
47 // ------------------------------------------------------------------------
48 
IMPLEMENT_DYNAMIC_CLASS(wxBitmapToggleButton,wxToggleButton)49 IMPLEMENT_DYNAMIC_CLASS(wxBitmapToggleButton, wxToggleButton)
50 
51 bool wxBitmapToggleButton::Create(wxWindow *parent, wxWindowID id,
52                             const wxBitmap &bitmap, const wxPoint &pos,
53                             const wxSize &size, long style,
54                             const wxValidator& validator,
55                             const wxString &name)
56 {
57     if ( !wxToggleButton::Create(parent, id, wxEmptyString, pos, size, style | wxBU_NOTEXT | wxBU_EXACTFIT,
58                                  validator, name) )
59         return false;
60 
61     if ( bitmap.IsOk() )
62     {
63         SetBitmapLabel(bitmap);
64 
65         // we need to adjust the size after setting the bitmap as it may be too
66         // big for the default button size
67         SetInitialSize(size);
68     }
69 
70     return true;
71 }
72 
73 
74 // ------------------------------------------------------------------------
75 // wxToggleButton
76 // ------------------------------------------------------------------------
77 
IMPLEMENT_DYNAMIC_CLASS(wxToggleButton,wxControl)78 IMPLEMENT_DYNAMIC_CLASS(wxToggleButton, wxControl)
79 
80 bool wxToggleButton::Create(wxWindow *parent, wxWindowID id,
81                             const wxString &label, const wxPoint &pos,
82                             const wxSize &size, long style,
83                             const wxValidator& validator,
84                             const wxString &name)
85 {
86     if (!PreCreation(parent, pos, size) ||
87         !CreateBase(parent, id, pos, size, style, validator, name ))
88     {
89         wxFAIL_MSG(wxT("wxToggleButton creation failed"));
90         return false;
91     }
92 
93     // create either a standard toggle button with text label (which may still contain
94     // an image under GTK+ 2.6+) or a bitmap-only toggle button if we don't have any
95     // label
96     const bool
97         useLabel = !(style & wxBU_NOTEXT) && !label.empty();
98     if ( useLabel )
99     {
100         m_widget = gtk_toggle_button_new_with_mnemonic("");
101     }
102     else // no label, suppose we will have a bitmap
103     {
104         m_widget = gtk_toggle_button_new();
105 
106         GtkWidget *image = gtk_image_new();
107         gtk_widget_show(image);
108         gtk_container_add(GTK_CONTAINER(m_widget), image);
109     }
110 
111     g_object_ref(m_widget);
112 
113     if ( useLabel )
114         SetLabel(label);
115 
116     g_signal_connect (m_widget, "clicked",
117                       G_CALLBACK (gtk_togglebutton_clicked_callback),
118                       this);
119 
120     m_parent->DoAddChild(this);
121 
122     PostCreation(size);
123 
124     return true;
125 }
126 
GTKDisableEvents()127 void wxToggleButton::GTKDisableEvents()
128 {
129     g_signal_handlers_block_by_func(m_widget,
130                                 (gpointer) gtk_togglebutton_clicked_callback, this);
131 }
132 
GTKEnableEvents()133 void wxToggleButton::GTKEnableEvents()
134 {
135     g_signal_handlers_unblock_by_func(m_widget,
136                                 (gpointer) gtk_togglebutton_clicked_callback, this);
137 }
138 
139 // void SetValue(bool state)
140 // Set the value of the toggle button.
SetValue(bool state)141 void wxToggleButton::SetValue(bool state)
142 {
143     wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
144 
145     if (state == GetValue())
146         return;
147 
148     GTKDisableEvents();
149 
150     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_widget), state);
151 
152     GTKEnableEvents();
153 }
154 
155 // bool GetValue() const
156 // Get the value of the toggle button.
GetValue() const157 bool wxToggleButton::GetValue() const
158 {
159     wxCHECK_MSG(m_widget != NULL, false, wxT("invalid toggle button"));
160 
161     return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_widget)) != 0;
162 }
163 
SetLabel(const wxString & label)164 void wxToggleButton::SetLabel(const wxString& label)
165 {
166     wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
167 
168     wxAnyButton::SetLabel(label);
169 
170     if ( HasFlag(wxBU_NOTEXT) )
171     {
172         // Don't try to update the label for a button not showing it, this is
173         // unnecessary and can also actually replace the image we show with the
174         // label entirely breaking the button code, see #13693.
175         return;
176     }
177 
178     const wxString labelGTK = GTKConvertMnemonics(label);
179 
180     gtk_button_set_label(GTK_BUTTON(m_widget), wxGTK_CONV(labelGTK));
181 
182     GTKApplyWidgetStyle( false );
183 }
184 
185 #if wxUSE_MARKUP
DoSetLabelMarkup(const wxString & markup)186 bool wxToggleButton::DoSetLabelMarkup(const wxString& markup)
187 {
188     wxCHECK_MSG( m_widget != NULL, false, "invalid toggle button" );
189 
190     const wxString stripped = RemoveMarkup(markup);
191     if ( stripped.empty() && !markup.empty() )
192         return false;
193 
194     wxControl::SetLabel(stripped);
195 
196     if ( !HasFlag(wxBU_NOTEXT) )
197     {
198         GtkLabel * const label = GTKGetLabel();
199         wxCHECK_MSG( label, false, "no label in this toggle button?" );
200 
201         GTKSetLabelWithMarkupForLabel(label, markup);
202     }
203 
204     return true;
205 }
206 #endif // wxUSE_MARKUP
207 
GTKGetLabel() const208 GtkLabel *wxToggleButton::GTKGetLabel() const
209 {
210     GtkWidget* child = gtk_bin_get_child(GTK_BIN(m_widget));
211     return GTK_LABEL(child);
212 }
213 
DoApplyWidgetStyle(GtkRcStyle * style)214 void wxToggleButton::DoApplyWidgetStyle(GtkRcStyle *style)
215 {
216     GTKApplyStyle(m_widget, style);
217     GtkWidget* child = gtk_bin_get_child(GTK_BIN(m_widget));
218     GTKApplyStyle(child, style);
219 
220     // for buttons with images, the path to the label is (at least in 2.12)
221     // GtkButton -> GtkAlignment -> GtkHBox -> GtkLabel
222     if ( GTK_IS_ALIGNMENT(child) )
223     {
224         GtkWidget* box = gtk_bin_get_child(GTK_BIN(child));
225         if ( GTK_IS_BOX(box) )
226         {
227             wxGtkList list(gtk_container_get_children(GTK_CONTAINER(box)));
228             for (GList* item = list; item; item = item->next)
229             {
230                 GTKApplyStyle(GTK_WIDGET(item->data), style);
231             }
232         }
233     }
234 }
235 
236 // Get the "best" size for this control.
DoGetBestSize() const237 wxSize wxToggleButton::DoGetBestSize() const
238 {
239     wxSize ret(wxAnyButton::DoGetBestSize());
240 
241     if (!HasFlag(wxBU_EXACTFIT))
242     {
243         if (ret.x < 80) ret.x = 80;
244     }
245 
246     CacheBestSize(ret);
247     return ret;
248 }
249 
250 // static
251 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))252 wxToggleButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
253 {
254     return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new());
255 }
256 
257 #endif // wxUSE_TOGGLEBTN
258