renamed local variable named m_radio as the m_ prefix was very confusing
[wxWidgets.git] / src / gtk / radiobox.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/radiobox.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_RADIOBOX
14
15 #include "wx/radiobox.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/log.h"
19 #endif
20
21 #include "wx/dialog.h"
22 #include "wx/frame.h"
23
24 #include "wx/gtk/private.h"
25 #include <gdk/gdkkeysyms.h>
26
27 #include "wx/gtk/win_gtk.h"
28
29 //-----------------------------------------------------------------------------
30 // data
31 //-----------------------------------------------------------------------------
32
33 extern bool g_blockEventsOnDrag;
34 extern wxWindowGTK *g_delayedFocus;
35
36 //-----------------------------------------------------------------------------
37 // "clicked"
38 //-----------------------------------------------------------------------------
39
40 extern "C" {
41 static void gtk_radiobutton_clicked_callback( GtkToggleButton *button, wxRadioBox *rb )
42 {
43 if (g_isIdle) wxapp_install_idle_handler();
44
45 if (!rb->m_hasVMT) return;
46 if (g_blockEventsOnDrag) return;
47
48 if (!button->active) return;
49
50 wxCommandEvent event( wxEVT_COMMAND_RADIOBOX_SELECTED, rb->GetId() );
51 event.SetInt( rb->GetSelection() );
52 event.SetString( rb->GetStringSelection() );
53 event.SetEventObject( rb );
54 rb->GetEventHandler()->ProcessEvent(event);
55 }
56 }
57
58 //-----------------------------------------------------------------------------
59 // "key_press_event"
60 //-----------------------------------------------------------------------------
61
62 extern "C" {
63 static gint gtk_radiobox_keypress_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxRadioBox *rb )
64 {
65 if (g_isIdle)
66 wxapp_install_idle_handler();
67
68 if (!rb->m_hasVMT) return FALSE;
69 if (g_blockEventsOnDrag) return FALSE;
70
71 if ( ((gdk_event->keyval == GDK_Tab) ||
72 (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
73 rb->GetParent() && (rb->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
74 {
75 wxNavigationKeyEvent new_event;
76 new_event.SetEventObject( rb->GetParent() );
77 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
78 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
79 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
80 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
81 new_event.SetCurrentFocus( rb );
82 return rb->GetParent()->GetEventHandler()->ProcessEvent( new_event );
83 }
84
85 if ((gdk_event->keyval != GDK_Up) &&
86 (gdk_event->keyval != GDK_Down) &&
87 (gdk_event->keyval != GDK_Left) &&
88 (gdk_event->keyval != GDK_Right))
89 {
90 return FALSE;
91 }
92
93 wxList::compatibility_iterator node = rb->m_boxes.Find( (wxObject*) widget );
94 if (!node)
95 {
96 return FALSE;
97 }
98
99 g_signal_stop_emission_by_name (widget, "key_press_event");
100
101 if ((gdk_event->keyval == GDK_Up) ||
102 (gdk_event->keyval == GDK_Left))
103 {
104 if (node == rb->m_boxes.GetFirst())
105 node = rb->m_boxes.GetLast();
106 else
107 node = node->GetPrevious();
108 }
109 else
110 {
111 if (node == rb->m_boxes.GetLast())
112 node = rb->m_boxes.GetFirst();
113 else
114 node = node->GetNext();
115 }
116
117 GtkWidget *button = (GtkWidget*) node->GetData();
118
119 gtk_widget_grab_focus( button );
120
121 return TRUE;
122 }
123 }
124
125 extern "C" {
126 static gint gtk_radiobutton_focus_in( GtkWidget *widget,
127 GdkEvent *WXUNUSED(event),
128 wxRadioBox *win )
129 {
130 if ( win->m_lostFocus )
131 {
132 // no, we didn't really lose it
133 win->m_lostFocus = FALSE;
134 }
135 else if ( !win->m_hasFocus )
136 {
137 win->m_hasFocus = true;
138
139 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
140 event.SetEventObject( win );
141
142 // never stop the signal emission, it seems to break the kbd handling
143 // inside the radiobox
144 (void)win->GetEventHandler()->ProcessEvent( event );
145 }
146
147 return FALSE;
148 }
149 }
150
151 extern "C" {
152 static gint gtk_radiobutton_focus_out( GtkWidget *widget,
153 GdkEvent *WXUNUSED(event),
154 wxRadioBox *win )
155 {
156 // wxASSERT_MSG( win->m_hasFocus, _T("got focus out without any focus in?") );
157 // Replace with a warning, else we dump core a lot!
158 // if (!win->m_hasFocus)
159 // wxLogWarning(_T("Radiobox got focus out without any focus in.") );
160
161 // we might have lost the focus, but may be not - it may have just gone to
162 // another button in the same radiobox, so we'll check for it in the next
163 // idle iteration (leave m_hasFocus == true for now)
164 win->m_lostFocus = true;
165
166 return FALSE;
167 }
168 }
169
170 //-----------------------------------------------------------------------------
171 // wxRadioBox
172 //-----------------------------------------------------------------------------
173
174 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox,wxControl)
175
176 void wxRadioBox::Init()
177 {
178 m_needParent = true;
179 m_acceptsFocus = true;
180
181 m_hasFocus =
182 m_lostFocus = false;
183 }
184
185 bool wxRadioBox::Create( wxWindow *parent, wxWindowID id,
186 const wxString& title,
187 const wxPoint &pos, const wxSize &size,
188 const wxArrayString& choices, int majorDim,
189 long style, const wxValidator& validator,
190 const wxString &name )
191 {
192 wxCArrayString chs(choices);
193
194 return Create( parent, id, title, pos, size, chs.GetCount(),
195 chs.GetStrings(), majorDim, style, validator, name );
196 }
197
198 bool wxRadioBox::Create( wxWindow *parent, wxWindowID id, const wxString& title,
199 const wxPoint &pos, const wxSize &size,
200 int n, const wxString choices[], int majorDim,
201 long style, const wxValidator& validator,
202 const wxString &name )
203 {
204 if (!PreCreation( parent, pos, size ) ||
205 !CreateBase( parent, id, pos, size, style, validator, name ))
206 {
207 wxFAIL_MSG( wxT("wxRadioBox creation failed") );
208 return false;
209 }
210
211 m_widget = GTKCreateFrame(title);
212 wxControl::SetLabel(title);
213
214 // majorDim may be 0 if all trailing parameters were omitted, so don't
215 // assert here but just use the correct value for it
216 SetMajorDim(majorDim == 0 ? n : majorDim, style);
217
218
219 unsigned int num_of_cols = GetColumnCount();
220 unsigned int num_of_rows = GetRowCount();
221
222 GtkRadioButton *rbtn = (GtkRadioButton*) NULL;
223
224 GtkWidget *table = gtk_table_new( num_of_rows, num_of_cols, FALSE );
225 gtk_table_set_col_spacings( GTK_TABLE(table), 1 );
226 gtk_table_set_row_spacings( GTK_TABLE(table), 1 );
227 gtk_widget_show( table );
228 gtk_container_add( GTK_CONTAINER(m_widget), table );
229
230 wxString label;
231 GSList *radio_button_group = (GSList *) NULL;
232 for (unsigned int i = 0; i < (unsigned int)n; i++)
233 {
234 if ( i != 0 )
235 radio_button_group = gtk_radio_button_get_group( GTK_RADIO_BUTTON(rbtn) );
236
237 label.Empty();
238 for ( const wxChar *pc = choices[i]; *pc; pc++ )
239 {
240 if ( *pc != wxT('&') )
241 label += *pc;
242 }
243
244 rbtn = GTK_RADIO_BUTTON( gtk_radio_button_new_with_label( radio_button_group, wxGTK_CONV( label ) ) );
245 gtk_widget_show( GTK_WIDGET(rbtn) );
246
247 g_signal_connect (rbtn, "key_press_event",
248 G_CALLBACK (gtk_radiobox_keypress_callback), this);
249
250 m_boxes.Append( (wxObject*) rbtn );
251
252 if (HasFlag(wxRA_SPECIFY_COLS))
253 {
254 int left = i%num_of_cols;
255 int right = (i%num_of_cols) + 1;
256 int top = i/num_of_cols;
257 int bottom = (i/num_of_cols)+1;
258 gtk_table_attach( GTK_TABLE(table), GTK_WIDGET(rbtn), left, right, top, bottom,
259 GTK_FILL, GTK_FILL, 1, 1 );
260 }
261 else
262 {
263 int left = i/num_of_rows;
264 int right = (i/num_of_rows) + 1;
265 int top = i%num_of_rows;
266 int bottom = (i%num_of_rows)+1;
267 gtk_table_attach( GTK_TABLE(table), GTK_WIDGET(rbtn), left, right, top, bottom,
268 GTK_FILL, GTK_FILL, 1, 1 );
269 }
270
271 ConnectWidget( GTK_WIDGET(rbtn) );
272
273 if (!i)
274 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(rbtn), TRUE );
275
276 g_signal_connect (rbtn, "clicked",
277 G_CALLBACK (gtk_radiobutton_clicked_callback), this);
278 g_signal_connect (rbtn, "focus_in_event",
279 G_CALLBACK (gtk_radiobutton_focus_in), this);
280 g_signal_connect (rbtn, "focus_out_event",
281 G_CALLBACK (gtk_radiobutton_focus_out), this);
282 }
283
284 m_parent->DoAddChild( this );
285
286 PostCreation(size);
287
288 return true;
289 }
290
291 wxRadioBox::~wxRadioBox()
292 {
293 wxList::compatibility_iterator node = m_boxes.GetFirst();
294 while (node)
295 {
296 GtkWidget *button = GTK_WIDGET( node->GetData() );
297 gtk_widget_destroy( button );
298 node = node->GetNext();
299 }
300 }
301
302 bool wxRadioBox::Show( bool show )
303 {
304 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
305
306 if (!wxControl::Show(show))
307 {
308 // nothing to do
309 return false;
310 }
311
312 if ( HasFlag(wxNO_BORDER) )
313 gtk_widget_hide( m_widget );
314
315 wxList::compatibility_iterator node = m_boxes.GetFirst();
316 while (node)
317 {
318 GtkWidget *button = GTK_WIDGET( node->GetData() );
319
320 if (show)
321 gtk_widget_show( button );
322 else
323 gtk_widget_hide( button );
324
325 node = node->GetNext();
326 }
327
328 return true;
329 }
330
331 void wxRadioBox::SetFocus()
332 {
333 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
334
335 if (m_boxes.GetCount() == 0) return;
336
337 wxList::compatibility_iterator node = m_boxes.GetFirst();
338 while (node)
339 {
340 GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData() );
341 if (button->active)
342 {
343 gtk_widget_grab_focus( GTK_WIDGET(button) );
344 return;
345 }
346 node = node->GetNext();
347 }
348 }
349
350 void wxRadioBox::SetSelection( int n )
351 {
352 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
353
354 wxList::compatibility_iterator node = m_boxes.Item( n );
355
356 wxCHECK_RET( node, wxT("radiobox wrong index") );
357
358 GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData() );
359
360 GtkDisableEvents();
361
362 gtk_toggle_button_set_active( button, 1 );
363
364 GtkEnableEvents();
365 }
366
367 int wxRadioBox::GetSelection(void) const
368 {
369 wxCHECK_MSG( m_widget != NULL, wxNOT_FOUND, wxT("invalid radiobox") );
370
371 int count = 0;
372
373 wxList::compatibility_iterator node = m_boxes.GetFirst();
374 while (node)
375 {
376 GtkToggleButton *button = GTK_TOGGLE_BUTTON( node->GetData() );
377 if (button->active) return count;
378 count++;
379 node = node->GetNext();
380 }
381
382 wxFAIL_MSG( wxT("wxRadioBox none selected") );
383
384 return wxNOT_FOUND;
385 }
386
387 wxString wxRadioBox::GetString(unsigned int n) const
388 {
389 wxCHECK_MSG( m_widget != NULL, wxEmptyString, wxT("invalid radiobox") );
390
391 wxList::compatibility_iterator node = m_boxes.Item( n );
392
393 wxCHECK_MSG( node, wxEmptyString, wxT("radiobox wrong index") );
394
395 GtkLabel *label = GTK_LABEL(GTK_BIN(node->GetData())->child);
396
397 wxString str( wxGTK_CONV_BACK( gtk_label_get_text(label) ) );
398
399 return str;
400 }
401
402 void wxRadioBox::SetLabel( const wxString& label )
403 {
404 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
405
406 GTKSetLabelForFrame(GTK_FRAME(m_widget), label);
407 }
408
409 void wxRadioBox::SetString(unsigned int item, const wxString& label)
410 {
411 wxCHECK_RET( m_widget != NULL, wxT("invalid radiobox") );
412
413 wxList::compatibility_iterator node = m_boxes.Item( item );
414
415 wxCHECK_RET( node, wxT("radiobox wrong index") );
416
417 GtkLabel *g_label = GTK_LABEL(GTK_BIN(node->GetData())->child);
418
419 gtk_label_set_text( g_label, wxGTK_CONV( label ) );
420 }
421
422 bool wxRadioBox::Enable( bool enable )
423 {
424 if ( !wxControl::Enable( enable ) )
425 return false;
426
427 wxList::compatibility_iterator node = m_boxes.GetFirst();
428 while (node)
429 {
430 GtkButton *button = GTK_BUTTON( node->GetData() );
431 GtkLabel *label = GTK_LABEL(GTK_BIN(button)->child);
432
433 gtk_widget_set_sensitive( GTK_WIDGET(button), enable );
434 gtk_widget_set_sensitive( GTK_WIDGET(label), enable );
435 node = node->GetNext();
436 }
437
438 return true;
439 }
440
441 bool wxRadioBox::Enable(unsigned int item, bool enable)
442 {
443 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
444
445 wxList::compatibility_iterator node = m_boxes.Item( item );
446
447 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
448
449 GtkButton *button = GTK_BUTTON( node->GetData() );
450 GtkLabel *label = GTK_LABEL(GTK_BIN(button)->child);
451
452 gtk_widget_set_sensitive( GTK_WIDGET(button), enable );
453 gtk_widget_set_sensitive( GTK_WIDGET(label), enable );
454
455 return true;
456 }
457
458 bool wxRadioBox::IsItemEnabled(unsigned int item) const
459 {
460 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
461
462 wxList::compatibility_iterator node = m_boxes.Item( item );
463
464 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
465
466 GtkButton *button = GTK_BUTTON( node->GetData() );
467
468 // don't use GTK_WIDGET_IS_SENSITIVE() here, we want to return true even if
469 // the parent radiobox is disabled
470 return GTK_WIDGET_SENSITIVE(GTK_WIDGET(button));
471 }
472
473 bool wxRadioBox::Show(unsigned int item, bool show)
474 {
475 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
476
477 wxList::compatibility_iterator node = m_boxes.Item( item );
478
479 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
480
481 GtkWidget *button = GTK_WIDGET( node->GetData() );
482
483 if (show)
484 gtk_widget_show( button );
485 else
486 gtk_widget_hide( button );
487
488 return true;
489 }
490
491 bool wxRadioBox::IsItemShown(unsigned int item) const
492 {
493 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid radiobox") );
494
495 wxList::compatibility_iterator node = m_boxes.Item( item );
496
497 wxCHECK_MSG( node, false, wxT("radiobox wrong index") );
498
499 GtkButton *button = GTK_BUTTON( node->GetData() );
500
501 return GTK_WIDGET_VISIBLE(GTK_WIDGET(button));
502 }
503
504 unsigned int wxRadioBox::GetCount() const
505 {
506 return m_boxes.GetCount();
507 }
508
509 void wxRadioBox::GtkDisableEvents()
510 {
511 wxList::compatibility_iterator node = m_boxes.GetFirst();
512 while (node)
513 {
514 g_signal_handlers_disconnect_by_func (node->GetData(),
515 (gpointer) gtk_radiobutton_clicked_callback,
516 this);
517
518 node = node->GetNext();
519 }
520 }
521
522 void wxRadioBox::GtkEnableEvents()
523 {
524 wxList::compatibility_iterator node = m_boxes.GetFirst();
525 while (node)
526 {
527 g_signal_connect (node->GetData(), "clicked",
528 G_CALLBACK (gtk_radiobutton_clicked_callback), this);
529
530 node = node->GetNext();
531 }
532 }
533
534 void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle *style)
535 {
536 GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style);
537
538 wxList::compatibility_iterator node = m_boxes.GetFirst();
539 while (node)
540 {
541 GtkWidget *widget = GTK_WIDGET( node->GetData() );
542
543 gtk_widget_modify_style( widget, style );
544 gtk_widget_modify_style(GTK_BIN(widget)->child, style);
545
546 node = node->GetNext();
547 }
548 }
549
550 bool wxRadioBox::GTKWidgetNeedsMnemonic() const
551 {
552 return true;
553 }
554
555 void wxRadioBox::GTKWidgetDoSetMnemonic(GtkWidget* w)
556 {
557 GTKFrameSetMnemonicWidget(GTK_FRAME(m_widget), w);
558 }
559
560 #if wxUSE_TOOLTIPS
561 void wxRadioBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
562 {
563 wxList::compatibility_iterator node = m_boxes.GetFirst();
564 while (node)
565 {
566 GtkWidget *widget = GTK_WIDGET( node->GetData() );
567 gtk_tooltips_set_tip( tips, widget, wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
568 node = node->GetNext();
569 }
570 }
571 #endif // wxUSE_TOOLTIPS
572
573 bool wxRadioBox::IsOwnGtkWindow( GdkWindow *window )
574 {
575 if (window == m_widget->window)
576 return true;
577
578 wxList::compatibility_iterator node = m_boxes.GetFirst();
579 while (node)
580 {
581 GtkWidget *button = GTK_WIDGET( node->GetData() );
582
583 if (window == button->window)
584 return true;
585
586 node = node->GetNext();
587 }
588
589 return false;
590 }
591
592 void wxRadioBox::OnInternalIdle()
593 {
594 if ( m_lostFocus )
595 {
596 m_hasFocus = false;
597 m_lostFocus = false;
598
599 wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
600 event.SetEventObject( this );
601
602 (void)GetEventHandler()->ProcessEvent( event );
603 }
604
605 if (g_delayedFocus == this)
606 {
607 if (GTK_WIDGET_REALIZED(m_widget))
608 {
609 g_delayedFocus = NULL;
610 SetFocus();
611 }
612 }
613 }
614
615 // static
616 wxVisualAttributes
617 wxRadioBox::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
618 {
619 wxVisualAttributes attr;
620 // NB: we need toplevel window so that GTK+ can find the right style
621 GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
622 GtkWidget* widget = gtk_radio_button_new_with_label(NULL, "");
623 gtk_container_add(GTK_CONTAINER(wnd), widget);
624 attr = GetDefaultAttributesFromGTKWidget(widget);
625 gtk_widget_destroy(wnd);
626 return attr;
627 }
628
629 #endif // wxUSE_RADIOBOX