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