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