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" 
  17 #include "wx/dialog.h" 
  21 #include "wx/gtk/private.h" 
  22 #include <gdk/gdkkeysyms.h> 
  24 #include "wx/gtk/win_gtk.h" 
  26 //----------------------------------------------------------------------------- 
  28 //----------------------------------------------------------------------------- 
  30 extern bool          g_blockEventsOnDrag
; 
  31 extern wxWindowGTK  
*g_delayedFocus
; 
  33 //----------------------------------------------------------------------------- 
  35 //----------------------------------------------------------------------------- 
  38 static void gtk_radiobutton_clicked_callback( GtkToggleButton 
*button
, wxRadioBox 
*rb 
) 
  40     if (g_isIdle
) wxapp_install_idle_handler(); 
  42     if (!rb
->m_hasVMT
) return; 
  43     if (g_blockEventsOnDrag
) return; 
  45     if (!button
->active
) return; 
  47     wxCommandEvent 
event( wxEVT_COMMAND_RADIOBOX_SELECTED
, rb
->GetId() ); 
  48     event
.SetInt( rb
->GetSelection() ); 
  49     event
.SetString( rb
->GetStringSelection() ); 
  50     event
.SetEventObject( rb 
); 
  51     rb
->GetEventHandler()->ProcessEvent(event
); 
  55 //----------------------------------------------------------------------------- 
  57 //----------------------------------------------------------------------------- 
  60 static gint 
gtk_radiobox_keypress_callback( GtkWidget 
*widget
, GdkEventKey 
*gdk_event
, wxRadioBox 
*rb 
) 
  63         wxapp_install_idle_handler(); 
  65     if (!rb
->m_hasVMT
) return FALSE
; 
  66     if (g_blockEventsOnDrag
) return FALSE
; 
  68     if ( ((gdk_event
->keyval 
== GDK_Tab
) || 
  69           (gdk_event
->keyval 
== GDK_ISO_Left_Tab
)) && 
  70          rb
->GetParent() && (rb
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) ) 
  72         wxNavigationKeyEvent new_event
; 
  73         new_event
.SetEventObject( rb
->GetParent() ); 
  74         // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB 
  75         new_event
.SetDirection( (gdk_event
->keyval 
== GDK_Tab
) ); 
  76         // CTRL-TAB changes the (parent) window, i.e. switch notebook page 
  77         new_event
.SetWindowChange( (gdk_event
->state 
& GDK_CONTROL_MASK
) ); 
  78         new_event
.SetCurrentFocus( rb 
); 
  79         return rb
->GetParent()->GetEventHandler()->ProcessEvent( new_event 
); 
  82     if ((gdk_event
->keyval 
!= GDK_Up
) && 
  83         (gdk_event
->keyval 
!= GDK_Down
) && 
  84         (gdk_event
->keyval 
!= GDK_Left
) && 
  85         (gdk_event
->keyval 
!= GDK_Right
)) 
  90     wxList::compatibility_iterator node 
= rb
->m_boxes
.Find( (wxObject
*) widget 
); 
  96     g_signal_stop_emission_by_name (widget
, "key_press_event"); 
  98     if ((gdk_event
->keyval 
== GDK_Up
) || 
  99         (gdk_event
->keyval 
== GDK_Left
)) 
 101         if (node 
== rb
->m_boxes
.GetFirst()) 
 102             node 
= rb
->m_boxes
.GetLast(); 
 104             node 
= node
->GetPrevious(); 
 108         if (node 
== rb
->m_boxes
.GetLast()) 
 109             node 
= rb
->m_boxes
.GetFirst(); 
 111             node 
= node
->GetNext(); 
 114     GtkWidget 
*button 
= (GtkWidget
*) node
->GetData(); 
 116     gtk_widget_grab_focus( button 
); 
 123 static gint 
gtk_radiobutton_focus_in( GtkWidget 
*widget
, 
 124                                       GdkEvent 
*WXUNUSED(event
), 
 127     if ( win
->m_lostFocus 
) 
 129         // no, we didn't really lose it 
 130         win
->m_lostFocus 
= FALSE
; 
 132     else if ( !win
->m_hasFocus 
) 
 134         win
->m_hasFocus 
= true; 
 136         wxFocusEvent 
event( wxEVT_SET_FOCUS
, win
->GetId() ); 
 137         event
.SetEventObject( win 
); 
 139         // never stop the signal emission, it seems to break the kbd handling 
 140         // inside the radiobox 
 141         (void)win
->GetEventHandler()->ProcessEvent( event 
); 
 149 static gint 
gtk_radiobutton_focus_out( GtkWidget 
*widget
, 
 150                                        GdkEvent 
*WXUNUSED(event
), 
 153   //    wxASSERT_MSG( win->m_hasFocus, _T("got focus out without any focus in?") ); 
 154   // Replace with a warning, else we dump core a lot! 
 155   //  if (!win->m_hasFocus) 
 156   //      wxLogWarning(_T("Radiobox got focus out without any focus in.") ); 
 158     // we might have lost the focus, but may be not - it may have just gone to 
 159     // another button in the same radiobox, so we'll check for it in the next 
 160     // idle iteration (leave m_hasFocus == true for now) 
 161     win
->m_lostFocus 
= true; 
 167 //----------------------------------------------------------------------------- 
 169 //----------------------------------------------------------------------------- 
 171 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
,wxControl
) 
 173 void wxRadioBox::Init() 
 176     m_acceptsFocus 
= true; 
 182 bool wxRadioBox::Create( wxWindow 
*parent
, wxWindowID id
, 
 183                          const wxString
& title
, 
 184                          const wxPoint 
&pos
, const wxSize 
&size
, 
 185                          const wxArrayString
& choices
, int majorDim
, 
 186                          long style
, const wxValidator
& validator
, 
 187                          const wxString 
&name 
) 
 189     wxCArrayString 
chs(choices
); 
 191     return Create( parent
, id
, title
, pos
, size
, chs
.GetCount(), 
 192                    chs
.GetStrings(), majorDim
, style
, validator
, name 
); 
 195 bool wxRadioBox::Create( wxWindow 
*parent
, wxWindowID id
, const wxString
& title
, 
 196                          const wxPoint 
&pos
, const wxSize 
&size
, 
 197                          int n
, const wxString choices
[], int majorDim
, 
 198                          long style
, const wxValidator
& validator
, 
 199                          const wxString 
&name 
) 
 201     if (!PreCreation( parent
, pos
, size 
) || 
 202         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 204         wxFAIL_MSG( wxT("wxRadioBox creation failed") ); 
 208     m_widget 
= GTKCreateFrame(title
); 
 209     wxControl::SetLabel(title
); 
 211     // majorDim may be 0 if all trailing parameters were omitted, so don't 
 212     // assert here but just use the correct value for it 
 213     SetMajorDim(majorDim 
== 0 ? n 
: majorDim
, style
); 
 216     unsigned int num_of_cols 
= GetColumnCount(); 
 217     unsigned int num_of_rows 
= GetRowCount(); 
 219     GtkRadioButton 
*m_radio 
= (GtkRadioButton
*) NULL
; 
 221     GtkWidget 
*table 
= gtk_table_new( num_of_rows
, num_of_cols
, FALSE 
); 
 222     gtk_table_set_col_spacings( GTK_TABLE(table
), 1 ); 
 223     gtk_table_set_row_spacings( GTK_TABLE(table
), 1 ); 
 224     gtk_widget_show( table 
); 
 225     gtk_container_add( GTK_CONTAINER(m_widget
), table 
); 
 228     GSList 
*radio_button_group 
= (GSList 
*) NULL
; 
 229     for (unsigned int i 
= 0; i 
< (unsigned int)n
; i
++) 
 232             radio_button_group 
= gtk_radio_button_get_group( GTK_RADIO_BUTTON(m_radio
) ); 
 235         for ( const wxChar 
*pc 
= choices
[i
]; *pc
; pc
++ ) 
 237             if ( *pc 
!= wxT('&') ) 
 241         m_radio 
= GTK_RADIO_BUTTON( gtk_radio_button_new_with_label( radio_button_group
, wxGTK_CONV( label 
) ) ); 
 242         gtk_widget_show( GTK_WIDGET(m_radio
) ); 
 244         g_signal_connect (m_radio
, "key_press_event", 
 245                           G_CALLBACK (gtk_radiobox_keypress_callback
), this); 
 247         m_boxes
.Append( (wxObject
*) m_radio 
); 
 249         if (HasFlag(wxRA_SPECIFY_COLS
)) 
 251             int left 
= i%num_of_cols
; 
 252             int right 
= (i%num_of_cols
) + 1; 
 253             int top 
= i
/num_of_cols
; 
 254             int bottom 
= (i
/num_of_cols
)+1; 
 255             gtk_table_attach( GTK_TABLE(table
), GTK_WIDGET(m_radio
), left
, right
, top
, bottom
, 
 256                   GTK_FILL
, GTK_FILL
, 1, 1 ); 
 260             int left 
= i
/num_of_rows
; 
 261             int right 
= (i
/num_of_rows
) + 1; 
 262             int top 
= i%num_of_rows
; 
 263             int bottom 
= (i%num_of_rows
)+1; 
 264             gtk_table_attach( GTK_TABLE(table
), GTK_WIDGET(m_radio
), left
, right
, top
, bottom
, 
 265                   GTK_FILL
, GTK_FILL
, 1, 1 ); 
 268         ConnectWidget( GTK_WIDGET(m_radio
) ); 
 271             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(m_radio
), TRUE 
); 
 273         g_signal_connect (m_radio
, "clicked", 
 274                           G_CALLBACK (gtk_radiobutton_clicked_callback
), this); 
 275         g_signal_connect (m_radio
, "focus_in_event", 
 276                           G_CALLBACK (gtk_radiobutton_focus_in
), this); 
 277         g_signal_connect (m_radio
, "focus_out_event", 
 278                           G_CALLBACK (gtk_radiobutton_focus_out
), this); 
 281     m_parent
->DoAddChild( this ); 
 288 wxRadioBox::~wxRadioBox() 
 290     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 293         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 294         gtk_widget_destroy( button 
); 
 295         node 
= node
->GetNext(); 
 299 bool wxRadioBox::Show( bool show 
) 
 301     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 303     if (!wxControl::Show(show
)) 
 309     if ( HasFlag(wxNO_BORDER
) ) 
 310         gtk_widget_hide( m_widget 
); 
 312     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 315         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 318             gtk_widget_show( button 
); 
 320             gtk_widget_hide( button 
); 
 322         node 
= node
->GetNext(); 
 328 void wxRadioBox::SetFocus() 
 330     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 332     if (m_boxes
.GetCount() == 0) return; 
 334     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 337         GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 340             gtk_widget_grab_focus( GTK_WIDGET(button
) ); 
 343         node 
= node
->GetNext(); 
 347 void wxRadioBox::SetSelection( int n 
) 
 349     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 351     wxList::compatibility_iterator node 
= m_boxes
.Item( n 
); 
 353     wxCHECK_RET( node
, wxT("radiobox wrong index") ); 
 355     GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 359     gtk_toggle_button_set_active( button
, 1 ); 
 364 int wxRadioBox::GetSelection(void) const 
 366     wxCHECK_MSG( m_widget 
!= NULL
, wxNOT_FOUND
, wxT("invalid radiobox") ); 
 370     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 373         GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 374         if (button
->active
) return count
; 
 376         node 
= node
->GetNext(); 
 379     wxFAIL_MSG( wxT("wxRadioBox none selected") ); 
 384 wxString 
wxRadioBox::GetString(unsigned int n
) const 
 386     wxCHECK_MSG( m_widget 
!= NULL
, wxEmptyString
, wxT("invalid radiobox") ); 
 388     wxList::compatibility_iterator node 
= m_boxes
.Item( n 
); 
 390     wxCHECK_MSG( node
, wxEmptyString
, wxT("radiobox wrong index") ); 
 392     GtkLabel 
*label 
= GTK_LABEL(GTK_BIN(node
->GetData())->child
); 
 394     wxString 
str( wxGTK_CONV_BACK( gtk_label_get_text(label
) ) ); 
 399 void wxRadioBox::SetLabel( const wxString
& label 
) 
 401     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 403     GTKSetLabelForFrame(GTK_FRAME(m_widget
), label
); 
 406 void wxRadioBox::SetString(unsigned int item
, const wxString
& label
) 
 408     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 410     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 412     wxCHECK_RET( node
, wxT("radiobox wrong index") ); 
 414     GtkLabel 
*g_label 
= GTK_LABEL(GTK_BIN(node
->GetData())->child
); 
 416     gtk_label_set_text( g_label
, wxGTK_CONV( label 
) ); 
 419 bool wxRadioBox::Enable( bool enable 
) 
 421     if ( !wxControl::Enable( enable 
) ) 
 424     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 427         GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 428         GtkLabel 
*label 
= GTK_LABEL(GTK_BIN(button
)->child
); 
 430         gtk_widget_set_sensitive( GTK_WIDGET(button
), enable 
); 
 431         gtk_widget_set_sensitive( GTK_WIDGET(label
), enable 
); 
 432         node 
= node
->GetNext(); 
 438 bool wxRadioBox::Enable(unsigned int item
, bool enable
) 
 440     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 442     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 444     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 446     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 447     GtkLabel 
*label 
= GTK_LABEL(GTK_BIN(button
)->child
); 
 449     gtk_widget_set_sensitive( GTK_WIDGET(button
), enable 
); 
 450     gtk_widget_set_sensitive( GTK_WIDGET(label
), enable 
); 
 455 bool wxRadioBox::IsItemEnabled(unsigned int item
) const 
 457     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 459     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 461     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 463     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 465     // don't use GTK_WIDGET_IS_SENSITIVE() here, we want to return true even if 
 466     // the parent radiobox is disabled 
 467     return GTK_WIDGET_SENSITIVE(GTK_WIDGET(button
)); 
 470 bool wxRadioBox::Show(unsigned int item
, bool show
) 
 472     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 474     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 476     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 478     GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 481         gtk_widget_show( button 
); 
 483         gtk_widget_hide( button 
); 
 488 bool wxRadioBox::IsItemShown(unsigned int item
) const 
 490     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 492     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 494     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 496     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 498     return GTK_WIDGET_VISIBLE(GTK_WIDGET(button
)); 
 501 unsigned int wxRadioBox::GetCount() const 
 503     return m_boxes
.GetCount(); 
 506 void wxRadioBox::GtkDisableEvents() 
 508     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 511         g_signal_handlers_disconnect_by_func (node
->GetData(), 
 512                                               (gpointer
) gtk_radiobutton_clicked_callback
, 
 515         node 
= node
->GetNext(); 
 519 void wxRadioBox::GtkEnableEvents() 
 521     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 524         g_signal_connect (node
->GetData(), "clicked", 
 525                           G_CALLBACK (gtk_radiobutton_clicked_callback
), this); 
 527         node 
= node
->GetNext(); 
 531 void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
 533     GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget
), style
); 
 535     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 538         GtkWidget 
*widget 
= GTK_WIDGET( node
->GetData() ); 
 540         gtk_widget_modify_style( widget
, style 
); 
 541         gtk_widget_modify_style(GTK_BIN(widget
)->child
, style
); 
 543         node 
= node
->GetNext(); 
 547 bool wxRadioBox::GTKWidgetNeedsMnemonic() const 
 552 void wxRadioBox::GTKWidgetDoSetMnemonic(GtkWidget
* w
) 
 554     GTKFrameSetMnemonicWidget(GTK_FRAME(m_widget
), w
); 
 558 void wxRadioBox::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
 560     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 563         GtkWidget 
*widget 
= GTK_WIDGET( node
->GetData() ); 
 564         gtk_tooltips_set_tip( tips
, widget
, wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL 
); 
 565         node 
= node
->GetNext(); 
 568 #endif // wxUSE_TOOLTIPS 
 570 bool wxRadioBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 572     if (window 
== m_widget
->window
) 
 575     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 578         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 580         if (window 
== button
->window
) 
 583         node 
= node
->GetNext(); 
 589 void wxRadioBox::OnInternalIdle() 
 596         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetId() ); 
 597         event
.SetEventObject( this ); 
 599         (void)GetEventHandler()->ProcessEvent( event 
); 
 602     if (g_delayedFocus 
== this) 
 604         if (GTK_WIDGET_REALIZED(m_widget
)) 
 606             g_delayedFocus 
= NULL
; 
 614 wxRadioBox::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 616     wxVisualAttributes attr
; 
 617     // NB: we need toplevel window so that GTK+ can find the right style 
 618     GtkWidget 
*wnd 
= gtk_window_new(GTK_WINDOW_TOPLEVEL
); 
 619     GtkWidget
* widget 
= gtk_radio_button_new_with_label(NULL
, ""); 
 620     gtk_container_add(GTK_CONTAINER(wnd
), widget
); 
 621     attr 
= GetDefaultAttributesFromGTKWidget(widget
); 
 622     gtk_widget_destroy(wnd
); 
 626 #endif // wxUSE_RADIOBOX