1 ///////////////////////////////////////////////////////////////////////////// 
   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" 
  17 #include "wx/checkbox.h" 
  19 #include "wx/gtk/private.h" 
  21 //----------------------------------------------------------------------------- 
  23 //----------------------------------------------------------------------------- 
  25 extern bool           g_blockEventsOnDrag
; 
  26 extern wxCursor       g_globalCursor
; 
  27 extern wxWindowGTK   
*g_delayedFocus
; 
  29 //----------------------------------------------------------------------------- 
  31 //----------------------------------------------------------------------------- 
  34 static void gtk_checkbox_toggled_callback(GtkWidget 
*widget
, wxCheckBox 
*cb
) 
  36     if (g_isIdle
) wxapp_install_idle_handler(); 
  38     if (!cb
->m_hasVMT
) return; 
  40     if (g_blockEventsOnDrag
) return; 
  42     if (cb
->m_blockEvent
) return; 
  44     // Transitions for 3state checkbox must be done manually, GTK's checkbox 
  45     // is 2state with additional "undetermined state" flag which isn't 
  46     // changed automatically: 
  49         GtkToggleButton 
*toggle 
= GTK_TOGGLE_BUTTON(widget
); 
  51         if (cb
->Is3rdStateAllowedForUser()) 
  53             // The 3 states cycle like this when clicked: 
  54             // checked -> undetermined -> unchecked -> checked -> ... 
  55             bool active 
= gtk_toggle_button_get_active(toggle
); 
  56             bool inconsistent 
= gtk_toggle_button_get_inconsistent(toggle
); 
  58             cb
->m_blockEvent 
= true; 
  60             if (!active 
&& !inconsistent
) 
  62                 // checked -> undetermined 
  63                 gtk_toggle_button_set_active(toggle
, true); 
  64                 gtk_toggle_button_set_inconsistent(toggle
, true); 
  66             else if (!active 
&& inconsistent
) 
  68                 // undetermined -> unchecked 
  69                 gtk_toggle_button_set_inconsistent(toggle
, false); 
  71             else if (active 
&& !inconsistent
) 
  73                 // unchecked -> checked 
  78                 wxFAIL_MSG(_T("3state wxCheckBox in unexpected state!")); 
  81             cb
->m_blockEvent 
= false; 
  85             // user's action unsets undetermined state: 
  86             gtk_toggle_button_set_inconsistent(toggle
, false); 
  90     wxCommandEvent 
event(wxEVT_COMMAND_CHECKBOX_CLICKED
, cb
->GetId()); 
  91     event
.SetInt(cb
->Get3StateValue()); 
  92     event
.SetEventObject(cb
); 
  93     cb
->GetEventHandler()->ProcessEvent(event
); 
  97 //----------------------------------------------------------------------------- 
  99 //----------------------------------------------------------------------------- 
 101 IMPLEMENT_DYNAMIC_CLASS(wxCheckBox
,wxControl
) 
 103 wxCheckBox::wxCheckBox() 
 107 bool wxCheckBox::Create(wxWindow 
*parent
, 
 109                         const wxString 
&label
, 
 113                         const wxValidator
& validator
, 
 114                         const wxString 
&name 
) 
 117     m_acceptsFocus 
= TRUE
; 
 118     m_blockEvent 
= FALSE
; 
 120     if (!PreCreation( parent
, pos
, size 
) || 
 121         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 123         wxFAIL_MSG( wxT("wxCheckBox creation failed") ); 
 127     wxASSERT_MSG( (style 
& wxCHK_ALLOW_3RD_STATE_FOR_USER
) == 0 || 
 128                   (style 
& wxCHK_3STATE
) != 0, 
 129                   wxT("Using wxCHK_ALLOW_3RD_STATE_FOR_USER") 
 130                   wxT(" style flag for a 2-state checkbox is useless") ); 
 132     if ( style 
& wxALIGN_RIGHT 
) 
 134         // VZ: as I don't know a way to create a right aligned checkbox with 
 135         //     GTK we will create a checkbox without label and a label at the 
 137         m_widgetCheckbox 
= gtk_check_button_new(); 
 139         m_widgetLabel 
= gtk_label_new(""); 
 140         gtk_misc_set_alignment(GTK_MISC(m_widgetLabel
), 0.0, 0.5); 
 142         m_widget 
= gtk_hbox_new(FALSE
, 0); 
 143         gtk_box_pack_start(GTK_BOX(m_widget
), m_widgetLabel
, FALSE
, FALSE
, 3); 
 144         gtk_box_pack_start(GTK_BOX(m_widget
), m_widgetCheckbox
, FALSE
, FALSE
, 3); 
 146         gtk_widget_show( m_widgetLabel 
); 
 147         gtk_widget_show( m_widgetCheckbox 
); 
 151         m_widgetCheckbox 
= gtk_check_button_new_with_label(""); 
 152         m_widgetLabel 
= GTK_BIN(m_widgetCheckbox
)->child
; 
 153         m_widget 
= m_widgetCheckbox
; 
 157     g_signal_connect (m_widgetCheckbox
, "toggled", 
 158                       G_CALLBACK (gtk_checkbox_toggled_callback
), this); 
 160     m_parent
->DoAddChild( this ); 
 167 void wxCheckBox::SetValue( bool state 
) 
 169     wxCHECK_RET( m_widgetCheckbox 
!= NULL
, wxT("invalid checkbox") ); 
 171     if (state 
== GetValue()) 
 176     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(m_widgetCheckbox
), state 
); 
 178     m_blockEvent 
= FALSE
; 
 181 bool wxCheckBox::GetValue() const 
 183     wxCHECK_MSG( m_widgetCheckbox 
!= NULL
, FALSE
, wxT("invalid checkbox") ); 
 185     return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m_widgetCheckbox
)); 
 188 void wxCheckBox::DoSet3StateValue(wxCheckBoxState state
) 
 190     SetValue(state 
!= wxCHK_UNCHECKED
); 
 191     gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(m_widgetCheckbox
), 
 192                                        state 
== wxCHK_UNDETERMINED
); 
 195 wxCheckBoxState 
wxCheckBox::DoGet3StateValue() const 
 197     if (gtk_toggle_button_get_inconsistent(GTK_TOGGLE_BUTTON(m_widgetCheckbox
))) 
 199         return wxCHK_UNDETERMINED
; 
 203         return GetValue() ? wxCHK_CHECKED 
: wxCHK_UNCHECKED
; 
 207 void wxCheckBox::SetLabel( const wxString
& label 
) 
 209     wxCHECK_RET( m_widgetLabel 
!= NULL
, wxT("invalid checkbox") ); 
 211     GTKSetLabelForLabel(GTK_LABEL(m_widgetLabel
), label
); 
 214 bool wxCheckBox::Enable( bool enable 
) 
 216     if ( !wxControl::Enable( enable 
) ) 
 219     gtk_widget_set_sensitive( m_widgetLabel
, enable 
); 
 224 void wxCheckBox::DoApplyWidgetStyle(GtkRcStyle 
*style
) 
 226     gtk_widget_modify_style(m_widgetCheckbox
, style
); 
 227     gtk_widget_modify_style(m_widgetLabel
, style
); 
 230 bool wxCheckBox::IsOwnGtkWindow( GdkWindow 
*window 
) 
 232     return window 
== GTK_BUTTON(m_widget
)->event_window
; 
 235 void wxCheckBox::OnInternalIdle() 
 237     wxCursor cursor 
= m_cursor
; 
 238     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
 240     GdkWindow 
*event_window 
= GTK_BUTTON(m_widgetCheckbox
)->event_window
; 
 241     if ( event_window 
&& cursor
.Ok() ) 
 243         /* I now set the cursor the anew in every OnInternalIdle call 
 244            as setting the cursor in a parent window also effects the 
 245            windows above so that checking for the current cursor is 
 248        gdk_window_set_cursor( event_window
, cursor
.GetCursor() ); 
 251     if (g_delayedFocus 
== this) 
 253         if (GTK_WIDGET_REALIZED(m_widget
)) 
 255             gtk_widget_grab_focus( m_widget 
); 
 256             g_delayedFocus 
= NULL
; 
 260     if (wxUpdateUIEvent::CanUpdate(this)) 
 261         UpdateWindowUI(wxUPDATE_UI_FROMIDLE
); 
 264 wxSize 
wxCheckBox::DoGetBestSize() const 
 266     return wxControl::DoGetBestSize(); 
 271 wxCheckBox::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 273     return GetDefaultAttributesFromGTKWidget(gtk_check_button_new
);