1 ///////////////////////////////////////////////////////////////////////////// 
   7 // Copyright:   (c) Robert Roebling 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  12 #pragma implementation "spinctrl.h" 
  15 #include "wx/spinctrl.h" 
  21 #include "wx/textctrl.h"    // for wxEVT_COMMAND_TEXT_UPDATED 
  28 //----------------------------------------------------------------------------- 
  30 //----------------------------------------------------------------------------- 
  32 extern void wxapp_install_idle_handler(); 
  35 static const float sensitivity 
= 0.02; 
  37 //----------------------------------------------------------------------------- 
  39 //----------------------------------------------------------------------------- 
  41 extern bool   g_blockEventsOnDrag
; 
  43 //----------------------------------------------------------------------------- 
  45 //----------------------------------------------------------------------------- 
  47 static void gtk_spinctrl_callback( GtkWidget 
*WXUNUSED(widget
), wxSpinCtrl 
*win 
) 
  49     if (g_isIdle
) wxapp_install_idle_handler(); 
  51     if (!win
->m_hasVMT
) return; 
  52     if (g_blockEventsOnDrag
) return; 
  54     wxCommandEvent 
event( wxEVT_COMMAND_SPINCTRL_UPDATED
, win
->GetId()); 
  55     event
.SetEventObject( win 
); 
  57     // note that we don't use wxSpinCtrl::GetValue() here because it would 
  58     // adjust the value to fit into the control range and this means that we 
  59     // would never be able to enter an "invalid" value in the control, even 
  60     // temporarily - and trying to enter 10 into the control which accepts the 
  61     // values in range 5..50 is then, ummm, quite challenging (hint: you can't 
  63     event
.SetInt( (int)ceil(win
->m_adjust
->value
) ); 
  64     win
->GetEventHandler()->ProcessEvent( event 
); 
  67 //----------------------------------------------------------------------------- 
  69 //----------------------------------------------------------------------------- 
  72 gtk_spinctrl_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxSpinCtrl 
*win 
) 
  74     if (!win
->m_hasVMT
) return; 
  77         wxapp_install_idle_handler(); 
  79     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
  80     event
.SetEventObject( win 
); 
  81     event
.SetInt( win
->GetValue() ); 
  82     win
->GetEventHandler()->ProcessEvent( event 
); 
  85 //----------------------------------------------------------------------------- 
  87 //----------------------------------------------------------------------------- 
  89 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
,wxControl
) 
  91 BEGIN_EVENT_TABLE(wxSpinCtrl
, wxControl
) 
  92     EVT_CHAR(wxSpinCtrl::OnChar
) 
  95 bool wxSpinCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
  96                         const wxString
& value
, 
  97                         const wxPoint
& pos
,  const wxSize
& size
, 
  99                         int min
, int max
, int initial
, 
 100                         const wxString
& name
) 
 103     m_acceptsFocus 
= TRUE
; 
 105     if (!PreCreation( parent
, pos
, size 
) || 
 106         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 108         wxFAIL_MSG( wxT("wxSpinCtrl creation failed") ); 
 114     m_adjust 
= (GtkAdjustment
*) gtk_adjustment_new( initial
, min
, max
, 1.0, 5.0, 0.0); 
 116     m_widget 
= gtk_spin_button_new( m_adjust
, 1, 0 ); 
 118     gtk_spin_button_set_wrap( GTK_SPIN_BUTTON(m_widget
), 
 119                               (int)(m_windowStyle 
& wxSP_WRAP
) ); 
 123     m_parent
->DoAddChild( this ); 
 127     SetFont( parent
->GetFont() ); 
 129     wxSize 
size_best( DoGetBestSize() ); 
 130     wxSize 
new_size( size 
); 
 131     if (new_size
.x 
== -1) 
 132         new_size
.x 
= size_best
.x
; 
 133     if (new_size
.y 
== -1) 
 134         new_size
.y 
= size_best
.y
; 
 135     if (new_size
.y 
> size_best
.y
) 
 136         new_size
.y 
= size_best
.y
; 
 137     if ((new_size
.x 
!= size
.x
) || (new_size
.y 
!= size
.y
)) 
 138         SetSize( new_size
.x
, new_size
.y 
); 
 140     SetBackgroundColour( parent
->GetBackgroundColour() ); 
 149 void wxSpinCtrl::GtkDisableEvents() 
 151     gtk_signal_disconnect_by_func( GTK_OBJECT(m_adjust
), 
 152                         GTK_SIGNAL_FUNC(gtk_spinctrl_callback
), 
 155     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 156                         GTK_SIGNAL_FUNC(gtk_spinctrl_text_changed_callback
), 
 160 void wxSpinCtrl::GtkEnableEvents() 
 162     gtk_signal_connect( GTK_OBJECT (m_adjust
), 
 164                         GTK_SIGNAL_FUNC(gtk_spinctrl_callback
), 
 167     gtk_signal_connect( GTK_OBJECT(m_widget
), 
 169                         GTK_SIGNAL_FUNC(gtk_spinctrl_text_changed_callback
), 
 173 int wxSpinCtrl::GetMin() const 
 175     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 177     return (int)ceil(m_adjust
->lower
); 
 180 int wxSpinCtrl::GetMax() const 
 182     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 184     return (int)ceil(m_adjust
->upper
); 
 187 int wxSpinCtrl::GetValue() const 
 189     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 191     gtk_spin_button_update( GTK_SPIN_BUTTON(m_widget
) ); 
 193     return (int)ceil(m_adjust
->value
); 
 196 void wxSpinCtrl::SetValue( const wxString
& value 
) 
 198     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 201     if ( (wxSscanf(value
, wxT("%d"), &n
) == 1) ) 
 208         // invalid number - set text as is (wxMSW compatible) 
 210         gtk_entry_set_text( GTK_ENTRY(m_widget
), value
.mbc_str() ); 
 215 void wxSpinCtrl::SetValue( int value 
) 
 217     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 219     float fpos 
= (float)value
; 
 221     if (fabs(fpos
-m_adjust
->value
) < sensitivity
) return; 
 223     m_adjust
->value 
= fpos
; 
 226     gtk_signal_emit_by_name( GTK_OBJECT(m_adjust
), "value_changed" ); 
 230 void wxSpinCtrl::SetRange(int minVal
, int maxVal
) 
 232     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 234     float fmin 
= (float)minVal
; 
 235     float fmax 
= (float)maxVal
; 
 237     if ((fabs(fmin
-m_adjust
->lower
) < sensitivity
) && 
 238         (fabs(fmax
-m_adjust
->upper
) < sensitivity
)) 
 243     m_adjust
->lower 
= fmin
; 
 244     m_adjust
->upper 
= fmax
; 
 246     gtk_signal_emit_by_name( GTK_OBJECT(m_adjust
), "changed" ); 
 248     // these two calls are required due to some bug in GTK 
 253 void wxSpinCtrl::OnChar( wxKeyEvent 
&event 
) 
 255     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid spin ctrl") ); 
 257     if (event
.KeyCode() == WXK_RETURN
) 
 259         wxWindow 
*top_frame 
= m_parent
; 
 260         while (top_frame
->GetParent() && !(top_frame
->GetParent()->IsTopLevel())) 
 261             top_frame 
= top_frame
->GetParent(); 
 262         GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 264         if (window
->default_widget
) 
 266             gtk_widget_activate (window
->default_widget
); 
 274 bool wxSpinCtrl::IsOwnGtkWindow( GdkWindow 
*window 
) 
 276     return GTK_SPIN_BUTTON(m_widget
)->panel 
== window
; 
 279 void wxSpinCtrl::ApplyWidgetStyle() 
 282     gtk_widget_set_style( m_widget
, m_widgetStyle 
); 
 285 wxSize 
wxSpinCtrl::DoGetBestSize() const 
 287     wxSize 
ret( wxControl::DoGetBestSize() ); 
 288     return wxSize(95, ret
.y
);