1 ///////////////////////////////////////////////////////////////////////////// 
   7 // Copyright:   (c) Robert Roebling 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  12 #pragma implementation "spinctrl.h" 
  15 // For compilers that support precompilation, includes "wx.h". 
  16 #include "wx/wxprec.h" 
  18 #include "wx/spinctrl.h" 
  24 #include "wx/textctrl.h"    // for wxEVT_COMMAND_TEXT_UPDATED 
  28 #include "wx/gtk/private.h" 
  30 //----------------------------------------------------------------------------- 
  32 //----------------------------------------------------------------------------- 
  34 extern void wxapp_install_idle_handler(); 
  37 static const float sensitivity 
= 0.02; 
  39 //----------------------------------------------------------------------------- 
  41 //----------------------------------------------------------------------------- 
  43 extern bool   g_blockEventsOnDrag
; 
  45 //----------------------------------------------------------------------------- 
  47 //----------------------------------------------------------------------------- 
  49 static void gtk_spinctrl_callback( GtkWidget 
*WXUNUSED(widget
), wxSpinCtrl 
*win 
) 
  51     if (g_isIdle
) wxapp_install_idle_handler(); 
  53     if (!win
->m_hasVMT
) return; 
  54     if (g_blockEventsOnDrag
) return; 
  56     wxCommandEvent 
event( wxEVT_COMMAND_SPINCTRL_UPDATED
, win
->GetId()); 
  57     event
.SetEventObject( win 
); 
  59     // note that we don't use wxSpinCtrl::GetValue() here because it would 
  60     // adjust the value to fit into the control range and this means that we 
  61     // would never be able to enter an "invalid" value in the control, even 
  62     // temporarily - and trying to enter 10 into the control which accepts the 
  63     // values in range 5..50 is then, ummm, quite challenging (hint: you can't 
  65     event
.SetInt( (int)ceil(win
->m_adjust
->value
) ); 
  66     win
->GetEventHandler()->ProcessEvent( event 
); 
  69 //----------------------------------------------------------------------------- 
  71 //----------------------------------------------------------------------------- 
  74 gtk_spinctrl_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxSpinCtrl 
*win 
) 
  76     if (!win
->m_hasVMT
) return; 
  79         wxapp_install_idle_handler(); 
  81     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
  82     event
.SetEventObject( win 
); 
  85     event
.SetInt( (int)ceil(win
->m_adjust
->value
) ); 
  86     win
->GetEventHandler()->ProcessEvent( event 
); 
  89 //----------------------------------------------------------------------------- 
  91 //----------------------------------------------------------------------------- 
  93 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
,wxControl
) 
  95 BEGIN_EVENT_TABLE(wxSpinCtrl
, wxControl
) 
  96     EVT_CHAR(wxSpinCtrl::OnChar
) 
  99 bool wxSpinCtrl::Create(wxWindow 
*parent
, wxWindowID id
, 
 100                         const wxString
& value
, 
 101                         const wxPoint
& pos
,  const wxSize
& size
, 
 103                         int min
, int max
, int initial
, 
 104                         const wxString
& name
) 
 107     m_acceptsFocus 
= TRUE
; 
 109     if (!PreCreation( parent
, pos
, size 
) || 
 110         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 112         wxFAIL_MSG( wxT("wxSpinCtrl creation failed") ); 
 118     m_adjust 
= (GtkAdjustment
*) gtk_adjustment_new( initial
, min
, max
, 1.0, 5.0, 0.0); 
 120     m_widget 
= gtk_spin_button_new( m_adjust
, 1, 0 ); 
 122     gtk_spin_button_set_wrap( GTK_SPIN_BUTTON(m_widget
), 
 123                               (int)(m_windowStyle 
& wxSP_WRAP
) ); 
 127     m_parent
->DoAddChild( this ); 
 131     SetFont( parent
->GetFont() ); 
 133     wxSize 
size_best( DoGetBestSize() ); 
 134     wxSize 
new_size( size 
); 
 135     if (new_size
.x 
== -1) 
 136         new_size
.x 
= size_best
.x
; 
 137     if (new_size
.y 
== -1) 
 138         new_size
.y 
= size_best
.y
; 
 139     if (new_size
.y 
> size_best
.y
) 
 140         new_size
.y 
= size_best
.y
; 
 141     if ((new_size
.x 
!= size
.x
) || (new_size
.y 
!= size
.y
)) 
 142         SetSize( new_size
.x
, new_size
.y 
); 
 144     SetBackgroundColour( parent
->GetBackgroundColour() ); 
 153 void wxSpinCtrl::GtkDisableEvents() 
 155     gtk_signal_disconnect_by_func( GTK_OBJECT(m_adjust
), 
 156                         GTK_SIGNAL_FUNC(gtk_spinctrl_callback
), 
 159     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 160                         GTK_SIGNAL_FUNC(gtk_spinctrl_text_changed_callback
), 
 164 void wxSpinCtrl::GtkEnableEvents() 
 166     gtk_signal_connect( GTK_OBJECT (m_adjust
), 
 168                         GTK_SIGNAL_FUNC(gtk_spinctrl_callback
), 
 171     gtk_signal_connect( GTK_OBJECT(m_widget
), 
 173                         GTK_SIGNAL_FUNC(gtk_spinctrl_text_changed_callback
), 
 177 int wxSpinCtrl::GetMin() const 
 179     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 181     return (int)ceil(m_adjust
->lower
); 
 184 int wxSpinCtrl::GetMax() const 
 186     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 188     return (int)ceil(m_adjust
->upper
); 
 191 int wxSpinCtrl::GetValue() const 
 193     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 195     gtk_spin_button_update( GTK_SPIN_BUTTON(m_widget
) ); 
 197     return (int)ceil(m_adjust
->value
); 
 200 void wxSpinCtrl::SetValue( const wxString
& value 
) 
 202     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 205     if ( (wxSscanf(value
, wxT("%d"), &n
) == 1) ) 
 212         // invalid number - set text as is (wxMSW compatible) 
 214         gtk_entry_set_text( GTK_ENTRY(m_widget
), wxGTK_CONV( value 
) ); 
 219 void wxSpinCtrl::SetValue( int value 
) 
 221     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 223     float fpos 
= (float)value
; 
 225     if (fabs(fpos
-m_adjust
->value
) < sensitivity
) return; 
 227     m_adjust
->value 
= fpos
; 
 230     gtk_signal_emit_by_name( GTK_OBJECT(m_adjust
), "value_changed" ); 
 234 void wxSpinCtrl::SetRange(int minVal
, int maxVal
) 
 236     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 238     float fmin 
= (float)minVal
; 
 239     float fmax 
= (float)maxVal
; 
 241     if ((fabs(fmin
-m_adjust
->lower
) < sensitivity
) && 
 242         (fabs(fmax
-m_adjust
->upper
) < sensitivity
)) 
 247     m_adjust
->lower 
= fmin
; 
 248     m_adjust
->upper 
= fmax
; 
 250     gtk_signal_emit_by_name( GTK_OBJECT(m_adjust
), "changed" ); 
 252     // these two calls are required due to some bug in GTK 
 257 void wxSpinCtrl::OnChar( wxKeyEvent 
&event 
) 
 259     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid spin ctrl") ); 
 261     if (event
.GetKeyCode() == WXK_RETURN
) 
 263         wxWindow 
*top_frame 
= m_parent
; 
 264         while (top_frame
->GetParent() && !(top_frame
->GetParent()->IsTopLevel())) 
 265             top_frame 
= top_frame
->GetParent(); 
 267         if ( GTK_IS_WINDOW(top_frame
->m_widget
) ) 
 269             GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 272                 GtkWidget 
*widgetDef 
= window
->default_widget
; 
 274                 if ( widgetDef 
&& GTK_IS_WINDOW(widgetDef
) ) 
 276                     gtk_widget_activate(widgetDef
); 
 286 bool wxSpinCtrl::IsOwnGtkWindow( GdkWindow 
*window 
) 
 288     if (GTK_SPIN_BUTTON(m_widget
)->entry
.text_area 
== window
) return TRUE
; 
 290     if (GTK_SPIN_BUTTON(m_widget
)->panel 
== window
) return TRUE
; 
 295 void wxSpinCtrl::ApplyWidgetStyle() 
 298     gtk_widget_set_style( m_widget
, m_widgetStyle 
); 
 301 wxSize 
wxSpinCtrl::DoGetBestSize() const 
 303     wxSize 
ret( wxControl::DoGetBestSize() ); 
 304     return wxSize(95, ret
.y
);