]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/tglbtn.cpp
Fix best size computation for buttons without image and with empty label.
[wxWidgets.git] / src / gtk1 / tglbtn.cpp
CommitLineData
1db8dc4a 1/////////////////////////////////////////////////////////////////////////////
f1e01716 2// Name: src/gtk1/tglbtn.cpp
1db8dc4a
VZ
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
706fb893 10// License: wxWindows licence
1db8dc4a
VZ
11/////////////////////////////////////////////////////////////////////////////
12
14f355c2
VS
13// For compilers that support precompilation, includes "wx.h".
14#include "wx/wxprec.h"
15
f1e01716
WS
16#if wxUSE_TOGGLEBTN
17
1db8dc4a
VZ
18#include "wx/tglbtn.h"
19
f1e01716
WS
20#ifndef WX_PRECOMP
21 #include "wx/button.h"
22#endif
1db8dc4a 23
3cbab641 24#include "wx/gtk1/private.h"
1db8dc4a
VZ
25
26extern void wxapp_install_idle_handler();
27extern bool g_isIdle;
28extern bool g_blockEventsOnDrag;
29extern wxCursor g_globalCursor;
30
865bb325 31extern "C" {
9864c56d 32static void gtk_togglebutton_clicked_callback(GtkWidget *WXUNUSED(widget), wxToggleButton *cb)
1db8dc4a 33{
91af0895
WS
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);
937013e0 46 cb->HandleWindowEvent(event);
1db8dc4a 47}
865bb325 48}
1db8dc4a 49
9b11752c 50wxDEFINE_EVENT( wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEvent );
1db8dc4a 51
4f856067
RR
52// ------------------------------------------------------------------------
53// wxToggleBitmapButton
54// ------------------------------------------------------------------------
55
56IMPLEMENT_DYNAMIC_CLASS(wxToggleBitmapButton, wxControl)
57
58bool 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{
91af0895
WS
64 m_needParent = true;
65 m_acceptsFocus = true;
66
67 m_blockEvent = false;
4f856067
RR
68
69 if (!PreCreation(parent, pos, size) ||
70 !CreateBase(parent, id, pos, size, style, validator, name ))
71 {
72 wxFAIL_MSG(wxT("wxToggleBitmapButton creation failed"));
91af0895 73 return false;
4f856067 74 }
91af0895 75
4f856067
RR
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 {
4f856067
RR
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
abdeb9e7 95 PostCreation(size);
4f856067 96
91af0895 97 return true;
4f856067
RR
98}
99
100// void SetValue(bool state)
101// Set the value of the toggle button.
102void wxToggleBitmapButton::SetValue(bool state)
103{
91af0895 104 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
4f856067 105
91af0895
WS
106 if (state == GetValue())
107 return;
4f856067 108
91af0895 109 m_blockEvent = true;
4f856067 110
91af0895 111 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_widget), state);
4f856067 112
91af0895 113 m_blockEvent = false;
4f856067
RR
114}
115
116// bool GetValue() const
117// Get the value of the toggle button.
118bool wxToggleBitmapButton::GetValue() const
119{
91af0895 120 wxCHECK_MSG(m_widget != NULL, false, wxT("invalid toggle button"));
4f856067 121
91af0895 122 return GTK_TOGGLE_BUTTON(m_widget)->active;
4f856067
RR
123}
124
125void wxToggleBitmapButton::SetLabel(const wxBitmap& label)
126{
127 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
128
129 m_bitmap = label;
9f884528 130 InvalidateBestSize();
91af0895 131
4f856067
RR
132 OnSetBitmap();
133}
134
135void wxToggleBitmapButton::OnSetBitmap()
136{
137 if (!m_bitmap.Ok()) return;
138
d3b9f782 139 GdkBitmap *mask = NULL;
4f856067
RR
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
91af0895 157bool wxToggleBitmapButton::Enable(bool enable /*=true*/)
4f856067
RR
158{
159 if (!wxControl::Enable(enable))
91af0895 160 return false;
4f856067
RR
161
162 gtk_widget_set_sensitive(BUTTON_CHILD(m_widget), enable);
163
91af0895 164 return true;
4f856067
RR
165}
166
f40fdaa3 167void wxToggleBitmapButton::DoApplyWidgetStyle(GtkRcStyle *style)
4f856067 168{
f40fdaa3
VS
169 gtk_widget_modify_style(m_widget, style);
170 gtk_widget_modify_style(BUTTON_CHILD(m_widget), style);
4f856067
RR
171}
172
173bool wxToggleBitmapButton::IsOwnGtkWindow(GdkWindow *window)
174{
175 return window == TOGGLE_BUTTON_EVENT_WIN(m_widget);
176}
177
178void wxToggleBitmapButton::OnInternalIdle()
179{
180 wxCursor cursor = m_cursor;
91af0895 181
4f856067
RR
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
9f884528 200
4f856067
RR
201// Get the "best" size for this control.
202wxSize wxToggleBitmapButton::DoGetBestSize() const
203{
abdeb9e7 204 wxSize best;
91af0895 205
abdeb9e7 206 if (m_bitmap.Ok())
4f856067 207 {
abdeb9e7
RD
208 int border = HasFlag(wxNO_BORDER) ? 4 : 10;
209 best.x = m_bitmap.GetWidth()+border;
210 best.y = m_bitmap.GetHeight()+border;
4f856067 211 }
9f884528 212 CacheBestSize(best);
abdeb9e7 213 return best;
4f856067 214}
9d522606
RD
215
216
217// static
218wxVisualAttributes
219wxToggleBitmapButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
220{
221 return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new);
222}
223
224
4f856067
RR
225// ------------------------------------------------------------------------
226// wxToggleButton
227// ------------------------------------------------------------------------
228
229IMPLEMENT_DYNAMIC_CLASS(wxToggleButton, wxControl)
230
1db8dc4a
VZ
231bool 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{
91af0895
WS
237 m_needParent = true;
238 m_acceptsFocus = true;
1db8dc4a 239
91af0895 240 m_blockEvent = false;
1db8dc4a 241
91af0895
WS
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 }
1db8dc4a 247
91af0895 248 wxControl::SetLabel(label);
1db8dc4a 249
91af0895
WS
250 // Create the gtk widget.
251 m_widget = gtk_toggle_button_new_with_label( wxGTK_CONV( m_label ) );
1db8dc4a 252
91af0895
WS
253 gtk_signal_connect(GTK_OBJECT(m_widget), "clicked",
254 GTK_SIGNAL_FUNC(gtk_togglebutton_clicked_callback),
255 (gpointer *)this);
1db8dc4a 256
91af0895 257 m_parent->DoAddChild(this);
1db8dc4a 258
91af0895
WS
259 PostCreation(size);
260
261 return true;
1db8dc4a
VZ
262}
263
264// void SetValue(bool state)
265// Set the value of the toggle button.
266void wxToggleButton::SetValue(bool state)
267{
91af0895 268 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
1db8dc4a 269
91af0895
WS
270 if (state == GetValue())
271 return;
1db8dc4a 272
91af0895 273 m_blockEvent = true;
1db8dc4a 274
91af0895 275 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_widget), state);
1db8dc4a 276
91af0895 277 m_blockEvent = false;
1db8dc4a
VZ
278}
279
280// bool GetValue() const
281// Get the value of the toggle button.
282bool wxToggleButton::GetValue() const
283{
91af0895 284 wxCHECK_MSG(m_widget != NULL, false, wxT("invalid toggle button"));
1db8dc4a 285
91af0895 286 return GTK_TOGGLE_BUTTON(m_widget)->active;
1db8dc4a
VZ
287}
288
1db8dc4a
VZ
289void wxToggleButton::SetLabel(const wxString& label)
290{
8ab696e0 291 wxCHECK_RET(m_widget != NULL, wxT("invalid toggle button"));
1db8dc4a 292
8ab696e0 293 wxControl::SetLabel(label);
1db8dc4a 294
fab591c5 295 gtk_label_set(GTK_LABEL(BUTTON_CHILD(m_widget)), wxGTK_CONV( GetLabel() ) );
1db8dc4a
VZ
296}
297
91af0895 298bool wxToggleButton::Enable(bool enable /*=true*/)
1db8dc4a 299{
8ab696e0 300 if (!wxControl::Enable(enable))
91af0895 301 return false;
1db8dc4a 302
9e691f46 303 gtk_widget_set_sensitive(BUTTON_CHILD(m_widget), enable);
1db8dc4a 304
91af0895 305 return true;
1db8dc4a
VZ
306}
307
f40fdaa3 308void wxToggleButton::DoApplyWidgetStyle(GtkRcStyle *style)
1db8dc4a 309{
f40fdaa3
VS
310 gtk_widget_modify_style(m_widget, style);
311 gtk_widget_modify_style(BUTTON_CHILD(m_widget), style);
1db8dc4a
VZ
312}
313
1db8dc4a
VZ
314bool wxToggleButton::IsOwnGtkWindow(GdkWindow *window)
315{
9e691f46 316 return window == TOGGLE_BUTTON_EVENT_WIN(m_widget);
1db8dc4a
VZ
317}
318
1db8dc4a
VZ
319void wxToggleButton::OnInternalIdle()
320{
8ab696e0 321 wxCursor cursor = m_cursor;
91af0895 322
8ab696e0
RR
323 if (g_globalCursor.Ok())
324 cursor = g_globalCursor;
1db8dc4a 325
9e691f46
VZ
326 GdkWindow *win = TOGGLE_BUTTON_EVENT_WIN(m_widget);
327 if ( win && cursor.Ok() )
328 {
1db8dc4a
VZ
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
9e691f46 334 gdk_window_set_cursor(win, cursor.GetCursor());
8ab696e0 335 }
1db8dc4a 336
e39af974
JS
337 if (wxUpdateUIEvent::CanUpdate(this))
338 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1db8dc4a
VZ
339}
340
9f884528 341
1db8dc4a
VZ
342// Get the "best" size for this control.
343wxSize wxToggleButton::DoGetBestSize() const
344{
8ab696e0 345 wxSize ret(wxControl::DoGetBestSize());
91af0895 346
8ab696e0
RR
347 if (!HasFlag(wxBU_EXACTFIT))
348 {
349 if (ret.x < 80) ret.x = 80;
350 }
91af0895 351
9f884528
RD
352 CacheBestSize(ret);
353 return ret;
1db8dc4a
VZ
354}
355
9d522606
RD
356// static
357wxVisualAttributes
358wxToggleButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
359{
360 return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new);
361}
362
1db8dc4a 363#endif // wxUSE_TOGGLEBTN