1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/radiobox.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  15 #include "wx/radiobox.h" 
  21 #include "wx/dialog.h" 
  24 #include "wx/gtk/private.h" 
  25 #include <gdk/gdkkeysyms.h> 
  27 #include "wx/gtk/win_gtk.h" 
  29 //----------------------------------------------------------------------------- 
  31 //----------------------------------------------------------------------------- 
  33 extern bool          g_blockEventsOnDrag
; 
  34 extern wxWindowGTK  
*g_delayedFocus
; 
  36 //----------------------------------------------------------------------------- 
  38 //----------------------------------------------------------------------------- 
  41 static void gtk_radiobutton_clicked_callback( GtkToggleButton 
*button
, wxRadioBox 
*rb 
) 
  43     if (g_isIdle
) wxapp_install_idle_handler(); 
  45     if (!rb
->m_hasVMT
) return; 
  46     if (g_blockEventsOnDrag
) return; 
  48     if (!button
->active
) return; 
  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
); 
  58 //----------------------------------------------------------------------------- 
  60 //----------------------------------------------------------------------------- 
  63 static gint 
gtk_radiobox_keypress_callback( GtkWidget 
*widget
, GdkEventKey 
*gdk_event
, wxRadioBox 
*rb 
) 
  66         wxapp_install_idle_handler(); 
  68     if (!rb
->m_hasVMT
) return FALSE
; 
  69     if (g_blockEventsOnDrag
) return FALSE
; 
  71     if ( ((gdk_event
->keyval 
== GDK_Tab
) || 
  72           (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) && 
  73          rb
->GetParent() && (rb
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
  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 
); 
  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
)) 
  93     wxList::compatibility_iterator node 
= rb
->m_buttons
.Find( (wxObject
*) widget 
); 
  99     g_signal_stop_emission_by_name (widget
, "key_press_event"); 
 101     if ((gdk_event
->keyval 
== GDK_Up
) || 
 102         (gdk_event
->keyval 
== GDK_Left
)) 
 104         if (node 
== rb
->m_buttons
.GetFirst()) 
 105             node 
= rb
->m_buttons
.GetLast(); 
 107             node 
= node
->GetPrevious(); 
 111         if (node 
== rb
->m_buttons
.GetLast()) 
 112             node 
= rb
->m_buttons
.GetFirst(); 
 114             node 
= node
->GetNext(); 
 117     GtkWidget 
*button 
= (GtkWidget
*) node
->GetData(); 
 119     gtk_widget_grab_focus( button 
); 
 126 static gint 
gtk_radiobutton_focus_in( GtkWidget 
*widget
, 
 127                                       GdkEvent 
*WXUNUSED(event
), 
 130     if ( win
->m_lostFocus 
) 
 132         // no, we didn't really lose it 
 133         win
->m_lostFocus 
= FALSE
; 
 135     else if ( !win
->m_hasFocus 
) 
 137         win
->m_hasFocus 
= true; 
 139         wxFocusEvent 
event( wxEVT_SET_FOCUS
, win
->GetId() ); 
 140         event
.SetEventObject( win 
); 
 142         // never stop the signal emission, it seems to break the kbd handling 
 143         // inside the radiobox 
 144         (void)win
->GetEventHandler()->ProcessEvent( event 
); 
 152 static gint 
gtk_radiobutton_focus_out( GtkWidget 
*widget
, 
 153                                        GdkEvent 
*WXUNUSED(event
), 
 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.") ); 
 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; 
 170 //----------------------------------------------------------------------------- 
 172 //----------------------------------------------------------------------------- 
 174 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
,wxControl
) 
 176 void wxRadioBox::Init() 
 179     m_acceptsFocus 
= true; 
 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 
) 
 192     wxCArrayString 
chs(choices
); 
 194     return Create( parent
, id
, title
, pos
, size
, chs
.GetCount(), 
 195                    chs
.GetStrings(), majorDim
, style
, validator
, name 
); 
 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 
) 
 204     if (!PreCreation( parent
, pos
, size 
) || 
 205         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 207         wxFAIL_MSG( wxT("wxRadioBox creation failed") ); 
 211     m_widget 
= GTKCreateFrame(title
); 
 212     wxControl::SetLabel(title
); 
 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
); 
 219     unsigned int num_of_cols 
= GetColumnCount(); 
 220     unsigned int num_of_rows 
= GetRowCount(); 
 222     GtkRadioButton 
*rbtn 
= (GtkRadioButton
*) NULL
; 
 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 
); 
 231     GSList 
*radio_button_group 
= (GSList 
*) NULL
; 
 232     for (unsigned int i 
= 0; i 
< (unsigned int)n
; i
++) 
 235             radio_button_group 
= gtk_radio_button_get_group( GTK_RADIO_BUTTON(rbtn
) ); 
 238         for ( const wxChar 
*pc 
= choices
[i
]; *pc
; pc
++ ) 
 240             if ( *pc 
!= wxT('&') ) 
 244         rbtn 
= GTK_RADIO_BUTTON( gtk_radio_button_new_with_label( radio_button_group
, wxGTK_CONV( label 
) ) ); 
 245         gtk_widget_show( GTK_WIDGET(rbtn
) ); 
 247         g_signal_connect (rbtn
, "key_press_event", 
 248                           G_CALLBACK (gtk_radiobox_keypress_callback
), this); 
 250         m_buttons
.Append( (wxObject
*) rbtn 
); 
 252         if (HasFlag(wxRA_SPECIFY_COLS
)) 
 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 ); 
 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 ); 
 271         ConnectWidget( GTK_WIDGET(rbtn
) ); 
 274             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(rbtn
), TRUE 
); 
 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); 
 284     m_parent
->DoAddChild( this ); 
 291 wxRadioBox::~wxRadioBox() 
 293     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 296         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 297         gtk_widget_destroy( button 
); 
 298         node 
= node
->GetNext(); 
 302 bool wxRadioBox::Show( bool show 
) 
 304     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 306     if (!wxControl::Show(show
)) 
 312     if ( HasFlag(wxNO_BORDER
) ) 
 313         gtk_widget_hide( m_widget 
); 
 315     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 318         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 321             gtk_widget_show( button 
); 
 323             gtk_widget_hide( button 
); 
 325         node 
= node
->GetNext(); 
 331 void wxRadioBox::SetFocus() 
 333     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 335     if (m_buttons
.GetCount() == 0) return; 
 337     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 340         GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 343             gtk_widget_grab_focus( GTK_WIDGET(button
) ); 
 346         node 
= node
->GetNext(); 
 350 void wxRadioBox::SetSelection( int n 
) 
 352     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 354     wxList::compatibility_iterator node 
= m_buttons
.Item( n 
); 
 356     wxCHECK_RET( node
, wxT("radiobox wrong index") ); 
 358     GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 362     gtk_toggle_button_set_active( button
, 1 ); 
 367 int wxRadioBox::GetSelection(void) const 
 369     wxCHECK_MSG( m_widget 
!= NULL
, wxNOT_FOUND
, wxT("invalid radiobox") ); 
 373     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 376         GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 377         if (button
->active
) return count
; 
 379         node 
= node
->GetNext(); 
 382     wxFAIL_MSG( wxT("wxRadioBox none selected") ); 
 387 wxString 
wxRadioBox::GetString(unsigned int n
) const 
 389     wxCHECK_MSG( m_widget 
!= NULL
, wxEmptyString
, wxT("invalid radiobox") ); 
 391     wxList::compatibility_iterator node 
= m_buttons
.Item( n 
); 
 393     wxCHECK_MSG( node
, wxEmptyString
, wxT("radiobox wrong index") ); 
 395     GtkLabel 
*label 
= GTK_LABEL(GTK_BIN(node
->GetData())->child
); 
 397     wxString 
str( wxGTK_CONV_BACK( gtk_label_get_text(label
) ) ); 
 402 void wxRadioBox::SetLabel( const wxString
& label 
) 
 404     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 406     GTKSetLabelForFrame(GTK_FRAME(m_widget
), label
); 
 409 void wxRadioBox::SetString(unsigned int item
, const wxString
& label
) 
 411     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 413     wxList::compatibility_iterator node 
= m_buttons
.Item( item 
); 
 415     wxCHECK_RET( node
, wxT("radiobox wrong index") ); 
 417     GtkLabel 
*g_label 
= GTK_LABEL(GTK_BIN(node
->GetData())->child
); 
 419     gtk_label_set_text( g_label
, wxGTK_CONV( label 
) ); 
 422 bool wxRadioBox::Enable( bool enable 
) 
 424     if ( !wxControl::Enable( enable 
) ) 
 427     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 430         GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 431         GtkLabel 
*label 
= GTK_LABEL(GTK_BIN(button
)->child
); 
 433         gtk_widget_set_sensitive( GTK_WIDGET(button
), enable 
); 
 434         gtk_widget_set_sensitive( GTK_WIDGET(label
), enable 
); 
 435         node 
= node
->GetNext(); 
 441 bool wxRadioBox::Enable(unsigned int item
, bool enable
) 
 443     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 445     wxList::compatibility_iterator node 
= m_buttons
.Item( item 
); 
 447     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 449     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 450     GtkLabel 
*label 
= GTK_LABEL(GTK_BIN(button
)->child
); 
 452     gtk_widget_set_sensitive( GTK_WIDGET(button
), enable 
); 
 453     gtk_widget_set_sensitive( GTK_WIDGET(label
), enable 
); 
 458 bool wxRadioBox::IsItemEnabled(unsigned int item
) const 
 460     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 462     wxList::compatibility_iterator node 
= m_buttons
.Item( item 
); 
 464     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 466     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 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
)); 
 473 bool wxRadioBox::Show(unsigned int item
, bool show
) 
 475     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 477     wxList::compatibility_iterator node 
= m_buttons
.Item( item 
); 
 479     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 481     GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 484         gtk_widget_show( button 
); 
 486         gtk_widget_hide( button 
); 
 491 bool wxRadioBox::IsItemShown(unsigned int item
) const 
 493     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 495     wxList::compatibility_iterator node 
= m_buttons
.Item( item 
); 
 497     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 499     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 501     return GTK_WIDGET_VISIBLE(GTK_WIDGET(button
)); 
 504 unsigned int wxRadioBox::GetCount() const 
 506     return m_buttons
.GetCount(); 
 509 void wxRadioBox::GtkDisableEvents() 
 511     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 514         g_signal_handlers_disconnect_by_func (node
->GetData(), 
 515                                               (gpointer
) gtk_radiobutton_clicked_callback
, 
 518         node 
= node
->GetNext(); 
 522 void wxRadioBox::GtkEnableEvents() 
 524     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 527         g_signal_connect (node
->GetData(), "clicked", 
 528                           G_CALLBACK (gtk_radiobutton_clicked_callback
), this); 
 530         node 
= node
->GetNext(); 
 534 void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
 536     GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget
), style
); 
 538     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 541         GtkWidget 
*widget 
= GTK_WIDGET( node
->GetData() ); 
 543         gtk_widget_modify_style( widget
, style 
); 
 544         gtk_widget_modify_style(GTK_BIN(widget
)->child
, style
); 
 546         node 
= node
->GetNext(); 
 550 bool wxRadioBox::GTKWidgetNeedsMnemonic() const 
 555 void wxRadioBox::GTKWidgetDoSetMnemonic(GtkWidget
* w
) 
 557     GTKFrameSetMnemonicWidget(GTK_FRAME(m_widget
), w
); 
 561 void wxRadioBox::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
 563     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 566         GtkWidget 
*widget 
= GTK_WIDGET( node
->GetData() ); 
 567         gtk_tooltips_set_tip( tips
, widget
, wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL 
); 
 568         node 
= node
->GetNext(); 
 571 #endif // wxUSE_TOOLTIPS 
 573 bool wxRadioBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 575     if (window 
== m_widget
->window
) 
 578     wxList::compatibility_iterator node 
= m_buttons
.GetFirst(); 
 581         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 583         if (window 
== button
->window
) 
 586         node 
= node
->GetNext(); 
 592 void wxRadioBox::OnInternalIdle() 
 599         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetId() ); 
 600         event
.SetEventObject( this ); 
 602         (void)GetEventHandler()->ProcessEvent( event 
); 
 605     if (g_delayedFocus 
== this) 
 607         if (GTK_WIDGET_REALIZED(m_widget
)) 
 609             g_delayedFocus 
= NULL
; 
 617 wxRadioBox::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 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
); 
 629 #endif // wxUSE_RADIOBOX