]>
Commit | Line | Data |
---|---|---|
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 | |
526954c5 | 10 | // Licence: 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 | |
26 | extern void wxapp_install_idle_handler(); | |
27 | extern bool g_isIdle; | |
28 | extern bool g_blockEventsOnDrag; | |
29 | extern wxCursor g_globalCursor; | |
30 | ||
865bb325 | 31 | extern "C" { |
9864c56d | 32 | static 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. | |
ce7fe42e | 43 | wxCommandEvent event(wxEVT_TOGGLEBUTTON, cb->GetId()); |
91af0895 WS |
44 | event.SetInt(cb->GetValue()); |
45 | event.SetEventObject(cb); | |
937013e0 | 46 | cb->HandleWindowEvent(event); |
1db8dc4a | 47 | } |
865bb325 | 48 | } |
1db8dc4a | 49 | |
ce7fe42e | 50 | wxDEFINE_EVENT( wxEVT_TOGGLEBUTTON, wxCommandEvent ); |
1db8dc4a | 51 | |
4f856067 RR |
52 | // ------------------------------------------------------------------------ |
53 | // wxToggleBitmapButton | |
54 | // ------------------------------------------------------------------------ | |
55 | ||
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 | { | |
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 | ||
a1b806b9 | 84 | if (m_bitmap.IsOk()) |
4f856067 | 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. | |
102 | void 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. | |
118 | bool 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 | ||
125 | void 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 | ||
135 | void wxToggleBitmapButton::OnSetBitmap() | |
136 | { | |
a1b806b9 | 137 | if (!m_bitmap.IsOk()) return; |
4f856067 | 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 | 157 | bool 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 | 167 | void 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 | ||
173 | bool wxToggleBitmapButton::IsOwnGtkWindow(GdkWindow *window) | |
174 | { | |
175 | return window == TOGGLE_BUTTON_EVENT_WIN(m_widget); | |
176 | } | |
177 | ||
178 | void wxToggleBitmapButton::OnInternalIdle() | |
179 | { | |
180 | wxCursor cursor = m_cursor; | |
91af0895 | 181 | |
a1b806b9 | 182 | if (g_globalCursor.IsOk()) |
4f856067 RR |
183 | cursor = g_globalCursor; |
184 | ||
185 | GdkWindow *win = TOGGLE_BUTTON_EVENT_WIN(m_widget); | |
a1b806b9 | 186 | if ( win && cursor.IsOk() ) |
4f856067 RR |
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. |
202 | wxSize wxToggleBitmapButton::DoGetBestSize() const | |
203 | { | |
abdeb9e7 | 204 | wxSize best; |
91af0895 | 205 | |
a1b806b9 | 206 | if (m_bitmap.IsOk()) |
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 | |
218 | wxVisualAttributes | |
219 | wxToggleBitmapButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) | |
220 | { | |
221 | return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new); | |
222 | } | |
223 | ||
224 | ||
4f856067 RR |
225 | // ------------------------------------------------------------------------ |
226 | // wxToggleButton | |
227 | // ------------------------------------------------------------------------ | |
228 | ||
229 | IMPLEMENT_DYNAMIC_CLASS(wxToggleButton, wxControl) | |
230 | ||
1db8dc4a VZ |
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 | { | |
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. | |
266 | void 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. | |
282 | bool 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 |
289 | void 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 | 298 | bool 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 | 308 | void 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 |
314 | bool wxToggleButton::IsOwnGtkWindow(GdkWindow *window) |
315 | { | |
9e691f46 | 316 | return window == TOGGLE_BUTTON_EVENT_WIN(m_widget); |
1db8dc4a VZ |
317 | } |
318 | ||
1db8dc4a VZ |
319 | void wxToggleButton::OnInternalIdle() |
320 | { | |
8ab696e0 | 321 | wxCursor cursor = m_cursor; |
91af0895 | 322 | |
a1b806b9 | 323 | if (g_globalCursor.IsOk()) |
8ab696e0 | 324 | cursor = g_globalCursor; |
1db8dc4a | 325 | |
9e691f46 | 326 | GdkWindow *win = TOGGLE_BUTTON_EVENT_WIN(m_widget); |
a1b806b9 | 327 | if ( win && cursor.IsOk() ) |
9e691f46 | 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. |
343 | wxSize 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 |
357 | wxVisualAttributes | |
358 | wxToggleButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) | |
359 | { | |
360 | return GetDefaultAttributesFromGTKWidget(gtk_toggle_button_new); | |
361 | } | |
362 | ||
1db8dc4a | 363 | #endif // wxUSE_TOGGLEBTN |