1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk1/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" 
  20     #include "wx/dialog.h" 
  23 #include "wx/gtk1/private.h" 
  24 #include <gdk/gdkkeysyms.h> 
  26 #include "wx/gtk1/win_gtk.h" 
  28 //----------------------------------------------------------------------------- 
  30 //----------------------------------------------------------------------------- 
  32 extern void wxapp_install_idle_handler(); 
  35 //----------------------------------------------------------------------------- 
  37 //----------------------------------------------------------------------------- 
  39 extern bool          g_blockEventsOnDrag
; 
  40 extern wxWindowGTK  
*g_delayedFocus
; 
  42 //----------------------------------------------------------------------------- 
  44 //----------------------------------------------------------------------------- 
  47 static void gtk_radiobutton_clicked_callback( GtkToggleButton 
*button
, wxRadioBox 
*rb 
) 
  49     if (g_isIdle
) wxapp_install_idle_handler(); 
  51     if (!rb
->m_hasVMT
) return; 
  52     if (g_blockEventsOnDrag
) return; 
  54     if (!button
->active
) return; 
  56     wxCommandEvent 
event( wxEVT_COMMAND_RADIOBOX_SELECTED
, rb
->GetId() ); 
  57     event
.SetInt( rb
->GetSelection() ); 
  58     event
.SetString( rb
->GetStringSelection() ); 
  59     event
.SetEventObject( rb 
); 
  60     rb
->HandleWindowEvent(event
); 
  64 //----------------------------------------------------------------------------- 
  66 //----------------------------------------------------------------------------- 
  69 static gint 
gtk_radiobox_keypress_callback( GtkWidget 
*widget
, GdkEventKey 
*gdk_event
, wxRadioBox 
*rb 
) 
  72         wxapp_install_idle_handler(); 
  74     if (!rb
->m_hasVMT
) return FALSE
; 
  75     if (g_blockEventsOnDrag
) return FALSE
; 
  77     if ((gdk_event
->keyval 
!= GDK_Up
) && 
  78         (gdk_event
->keyval 
!= GDK_Down
) && 
  79         (gdk_event
->keyval 
!= GDK_Left
) && 
  80         (gdk_event
->keyval 
!= GDK_Right
)) 
  85     wxList::compatibility_iterator node 
= rb
->m_boxes
.Find( (wxObject
*) widget 
); 
  91     gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" ); 
  93     if ((gdk_event
->keyval 
== GDK_Up
) || 
  94         (gdk_event
->keyval 
== GDK_Left
)) 
  96         if (node 
== rb
->m_boxes
.GetFirst()) 
  97             node 
= rb
->m_boxes
.GetLast(); 
  99             node 
= node
->GetPrevious(); 
 103         if (node 
== rb
->m_boxes
.GetLast()) 
 104             node 
= rb
->m_boxes
.GetFirst(); 
 106             node 
= node
->GetNext(); 
 109     GtkWidget 
*button 
= (GtkWidget
*) node
->GetData(); 
 111     gtk_widget_grab_focus( button 
); 
 118 static gint 
gtk_radiobutton_focus_in( GtkWidget 
*WXUNUSED(widget
), 
 119                                       GdkEvent 
*WXUNUSED(event
), 
 122     if ( win
->m_lostFocus 
) 
 124         // no, we didn't really lose it 
 125         win
->m_lostFocus 
= FALSE
; 
 127     else if ( !win
->m_hasFocus 
) 
 129         win
->m_hasFocus 
= true; 
 131         wxFocusEvent 
event( wxEVT_SET_FOCUS
, win
->GetId() ); 
 132         event
.SetEventObject( win 
); 
 134         // never stop the signal emission, it seems to break the kbd handling 
 135         // inside the radiobox 
 136         (void)win
->HandleWindowEvent( event 
); 
 144 static gint 
gtk_radiobutton_focus_out( GtkWidget 
*WXUNUSED(widget
), 
 145                                        GdkEvent 
*WXUNUSED(event
), 
 148   //    wxASSERT_MSG( win->m_hasFocus, wxT("got focus out without any focus in?") ); 
 149   // Replace with a warning, else we dump core a lot! 
 150   //  if (!win->m_hasFocus) 
 151   //      wxLogWarning(wxT("Radiobox got focus out without any focus in.") ); 
 153     // we might have lost the focus, but may be not - it may have just gone to 
 154     // another button in the same radiobox, so we'll check for it in the next 
 155     // idle iteration (leave m_hasFocus == true for now) 
 156     win
->m_lostFocus 
= true; 
 162 //----------------------------------------------------------------------------- 
 164 //----------------------------------------------------------------------------- 
 166 IMPLEMENT_DYNAMIC_CLASS(wxRadioBox
,wxControl
) 
 168 void wxRadioBox::Init() 
 171     m_acceptsFocus 
= true; 
 177 bool wxRadioBox::Create( wxWindow 
*parent
, wxWindowID id
, 
 178                          const wxString
& title
, 
 179                          const wxPoint 
&pos
, const wxSize 
&size
, 
 180                          const wxArrayString
& choices
, int majorDim
, 
 181                          long style
, const wxValidator
& validator
, 
 182                          const wxString 
&name 
) 
 184     wxCArrayString 
chs(choices
); 
 186     return Create( parent
, id
, title
, pos
, size
, chs
.GetCount(), 
 187                    chs
.GetStrings(), majorDim
, style
, validator
, name 
); 
 190 bool wxRadioBox::Create( wxWindow 
*parent
, wxWindowID id
, const wxString
& title
, 
 191                          const wxPoint 
&pos
, const wxSize 
&size
, 
 192                          int n
, const wxString choices
[], int majorDim
, 
 193                          long style
, const wxValidator
& validator
, 
 194                          const wxString 
&name 
) 
 196     if (!PreCreation( parent
, pos
, size 
) || 
 197         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 199         wxFAIL_MSG( wxT("wxRadioBox creation failed") ); 
 203     m_widget 
= gtk_frame_new(NULL
); 
 205     if ( HasFlag(wxNO_BORDER
) ) 
 207         // If we don't do this here, the wxNO_BORDER style is ignored in Show() 
 208         gtk_frame_set_shadow_type(GTK_FRAME(m_widget
), GTK_SHADOW_NONE
); 
 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 
= 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 
= NULL
; 
 229     for (int i 
= 0; i 
< n
; i
++) 
 232             radio_button_group 
= gtk_radio_button_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         gtk_signal_connect( GTK_OBJECT(m_radio
), "key_press_event", 
 245            GTK_SIGNAL_FUNC(gtk_radiobox_keypress_callback
), (gpointer
)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
) ); 
 270         if (!i
) gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(m_radio
), TRUE 
); 
 272         gtk_signal_connect( GTK_OBJECT(m_radio
), "clicked", 
 273             GTK_SIGNAL_FUNC(gtk_radiobutton_clicked_callback
), (gpointer
*)this ); 
 275         gtk_signal_connect( GTK_OBJECT(m_radio
), "focus_in_event", 
 276             GTK_SIGNAL_FUNC(gtk_radiobutton_focus_in
), (gpointer
)this ); 
 278         gtk_signal_connect( GTK_OBJECT(m_radio
), "focus_out_event", 
 279             GTK_SIGNAL_FUNC(gtk_radiobutton_focus_out
), (gpointer
)this ); 
 282     m_parent
->DoAddChild( this ); 
 289 wxRadioBox::~wxRadioBox() 
 291     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 294         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 295         gtk_widget_destroy( button 
); 
 296         node 
= node
->GetNext(); 
 300 bool wxRadioBox::Show(bool show
) 
 302     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 304     if (!wxControl::Show(show
)) 
 310     if ( HasFlag(wxNO_BORDER
) ) 
 311         gtk_widget_hide( m_widget 
); 
 313     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 316         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 319             gtk_widget_show( button 
); 
 321             gtk_widget_hide( button 
); 
 323         node 
= node
->GetNext(); 
 329 void wxRadioBox::SetFocus() 
 331     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 333     if (m_boxes
.GetCount() == 0) return; 
 335     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 338         GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 341             gtk_widget_grab_focus( GTK_WIDGET(button
) ); 
 344         node 
= node
->GetNext(); 
 348 void wxRadioBox::SetSelection( int n 
) 
 350     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 352     wxList::compatibility_iterator node 
= m_boxes
.Item( n 
); 
 354     wxCHECK_RET( node
, wxT("radiobox wrong index") ); 
 356     GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 360     gtk_toggle_button_set_active( button
, 1 ); 
 365 int wxRadioBox::GetSelection(void) const 
 367     wxCHECK_MSG( m_widget 
!= NULL
, wxNOT_FOUND
, wxT("invalid radiobox") ); 
 371     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 374         GtkToggleButton 
*button 
= GTK_TOGGLE_BUTTON( node
->GetData() ); 
 375         if (button
->active
) return count
; 
 377         node 
= node
->GetNext(); 
 380     wxFAIL_MSG( wxT("wxRadioBox none selected") ); 
 385 wxString 
wxRadioBox::GetString(unsigned int n
) const 
 387     wxCHECK_MSG( m_widget 
!= NULL
, wxEmptyString
, wxT("invalid radiobox") ); 
 389     wxList::compatibility_iterator node 
= m_boxes
.Item( n 
); 
 391     wxCHECK_MSG( node
, wxEmptyString
, wxT("radiobox wrong index") ); 
 393     GtkLabel 
*label 
= GTK_LABEL( BUTTON_CHILD(node
->GetData()) ); 
 395     wxString 
str( label
->label 
); 
 400 void wxRadioBox::SetLabel( const wxString
& label 
) 
 402     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 404     GTKSetLabelForFrame(GTK_FRAME(m_widget
), label
); 
 407 void wxRadioBox::SetString(unsigned int item
, const wxString
& label
) 
 409     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid radiobox") ); 
 411     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 413     wxCHECK_RET( node
, wxT("radiobox wrong index") ); 
 415     GtkLabel 
*g_label 
= GTK_LABEL( BUTTON_CHILD(node
->GetData()) ); 
 417     gtk_label_set( g_label
, wxGTK_CONV( label 
) ); 
 420 bool wxRadioBox::Enable( bool enable 
) 
 422     if ( !wxControl::Enable( enable 
) ) 
 425     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 428         GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 429         GtkLabel 
*label 
= GTK_LABEL( BUTTON_CHILD(button
) ); 
 431         gtk_widget_set_sensitive( GTK_WIDGET(button
), enable 
); 
 432         gtk_widget_set_sensitive( GTK_WIDGET(label
), enable 
); 
 433         node 
= node
->GetNext(); 
 439 bool wxRadioBox::Enable(unsigned int item
, bool enable
) 
 441     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 443     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 445     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 447     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 448     GtkLabel 
*label 
= GTK_LABEL( BUTTON_CHILD(button
) ); 
 450     gtk_widget_set_sensitive( GTK_WIDGET(button
), enable 
); 
 451     gtk_widget_set_sensitive( GTK_WIDGET(label
), enable 
); 
 456 bool wxRadioBox::IsItemEnabled(unsigned int item
) const 
 458     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 460     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 462     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 464     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 466     // don't use GTK_WIDGET_IS_SENSITIVE() here, we want to return true even if 
 467     // the parent radiobox is disabled 
 468     return GTK_WIDGET_SENSITIVE(GTK_WIDGET(button
)); 
 471 bool wxRadioBox::Show(unsigned int item
, bool show
) 
 473     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 475     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 477     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 479     GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 482         gtk_widget_show( button 
); 
 484         gtk_widget_hide( button 
); 
 489 bool wxRadioBox::IsItemShown(unsigned int item
) const 
 491     wxCHECK_MSG( m_widget 
!= NULL
, false, wxT("invalid radiobox") ); 
 493     wxList::compatibility_iterator node 
= m_boxes
.Item( item 
); 
 495     wxCHECK_MSG( node
, false, wxT("radiobox wrong index") ); 
 497     GtkButton 
*button 
= GTK_BUTTON( node
->GetData() ); 
 499     return GTK_WIDGET_VISIBLE(GTK_WIDGET(button
)); 
 502 unsigned int wxRadioBox::GetCount() const 
 504     return m_boxes
.GetCount(); 
 507 void wxRadioBox::GtkDisableEvents() 
 509     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 512         gtk_signal_disconnect_by_func( GTK_OBJECT(node
->GetData()), 
 513            GTK_SIGNAL_FUNC(gtk_radiobutton_clicked_callback
), (gpointer
*)this ); 
 515         node 
= node
->GetNext(); 
 519 void wxRadioBox::GtkEnableEvents() 
 521     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 524         gtk_signal_connect( GTK_OBJECT(node
->GetData()), "clicked", 
 525            GTK_SIGNAL_FUNC(gtk_radiobutton_clicked_callback
), (gpointer
*)this ); 
 527         node 
= node
->GetNext(); 
 531 void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
 533     gtk_widget_modify_style( 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( BUTTON_CHILD(node
->GetData()), style 
); 
 543         node 
= node
->GetNext(); 
 548 void wxRadioBox::ApplyToolTip( GtkTooltips 
*tips
, const wxChar 
*tip 
) 
 550     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 553         GtkWidget 
*widget 
= GTK_WIDGET( node
->GetData() ); 
 554         gtk_tooltips_set_tip( tips
, widget
, wxConvCurrent
->cWX2MB(tip
), NULL 
); 
 555         node 
= node
->GetNext(); 
 558 #endif // wxUSE_TOOLTIPS 
 560 bool wxRadioBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 562     if (window 
== m_widget
->window
) 
 565     wxList::compatibility_iterator node 
= m_boxes
.GetFirst(); 
 568         GtkWidget 
*button 
= GTK_WIDGET( node
->GetData() ); 
 570         if (window 
== button
->window
) 
 573         node 
= node
->GetNext(); 
 579 void wxRadioBox::OnInternalIdle() 
 586         wxFocusEvent 
event( wxEVT_KILL_FOCUS
, GetId() ); 
 587         event
.SetEventObject( this ); 
 589         (void)HandleWindowEvent( event 
); 
 592     if (g_delayedFocus 
== this) 
 594         if (GTK_WIDGET_REALIZED(m_widget
)) 
 596             g_delayedFocus 
= NULL
; 
 604 wxRadioBox::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 606     wxVisualAttributes attr
; 
 607     // NB: we need toplevel window so that GTK+ can find the right style 
 608     GtkWidget 
*wnd 
= gtk_window_new(GTK_WINDOW_TOPLEVEL
); 
 609     GtkWidget
* widget 
= gtk_radio_button_new_with_label(NULL
, ""); 
 610     gtk_container_add(GTK_CONTAINER(wnd
), widget
); 
 611     attr 
= GetDefaultAttributesFromGTKWidget(widget
); 
 612     gtk_widget_destroy(wnd
); 
 616 #endif // wxUSE_RADIOBOX