1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk1/spinbutt.cpp 
   7 // Copyright:   (c) Robert Roebling 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 // For compilers that support precompilation, includes "wx.h". 
  12 #include "wx/wxprec.h" 
  16 #include "wx/spinctrl.h" 
  20     #include "wx/textctrl.h"    // for wxEVT_COMMAND_TEXT_UPDATED 
  24 #include "wx/gtk1/private.h" 
  26 //----------------------------------------------------------------------------- 
  28 //----------------------------------------------------------------------------- 
  30 extern void wxapp_install_idle_handler(); 
  33 static const float sensitivity 
= 0.02; 
  35 //----------------------------------------------------------------------------- 
  37 //----------------------------------------------------------------------------- 
  39 extern bool   g_blockEventsOnDrag
; 
  41 //----------------------------------------------------------------------------- 
  43 //----------------------------------------------------------------------------- 
  46 static void gtk_spinctrl_callback( GtkWidget 
*WXUNUSED(widget
), wxSpinCtrl 
*win 
) 
  48     if (g_isIdle
) wxapp_install_idle_handler(); 
  50     if (!win
->m_hasVMT
) return; 
  51     if (g_blockEventsOnDrag
) return; 
  53     wxCommandEvent 
event( wxEVT_COMMAND_SPINCTRL_UPDATED
, win
->GetId()); 
  54     event
.SetEventObject( win 
); 
  56     // note that we don't use wxSpinCtrl::GetValue() here because it would 
  57     // adjust the value to fit into the control range and this means that we 
  58     // would never be able to enter an "invalid" value in the control, even 
  59     // temporarily - and trying to enter 10 into the control which accepts the 
  60     // values in range 5..50 is then, ummm, quite challenging (hint: you can't 
  62     event
.SetInt( (int)ceil(win
->m_adjust
->value
) ); 
  63     win
->GetEventHandler()->ProcessEvent( event 
); 
  67 //----------------------------------------------------------------------------- 
  69 //----------------------------------------------------------------------------- 
  73 gtk_spinctrl_text_changed_callback( GtkWidget 
*WXUNUSED(widget
), wxSpinCtrl 
*win 
) 
  75     if (!win
->m_hasVMT
) return; 
  78         wxapp_install_idle_handler(); 
  80     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
  81     event
.SetEventObject( win 
); 
  84     event
.SetInt( (int)ceil(win
->m_adjust
->value
) ); 
  85     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 ); 
 136 void wxSpinCtrl::GtkDisableEvents() 
 138     gtk_signal_disconnect_by_func( GTK_OBJECT(m_adjust
), 
 139                         GTK_SIGNAL_FUNC(gtk_spinctrl_callback
), 
 142     gtk_signal_disconnect_by_func( GTK_OBJECT(m_widget
), 
 143                         GTK_SIGNAL_FUNC(gtk_spinctrl_text_changed_callback
), 
 147 void wxSpinCtrl::GtkEnableEvents() 
 149     gtk_signal_connect( GTK_OBJECT (m_adjust
), 
 151                         GTK_SIGNAL_FUNC(gtk_spinctrl_callback
), 
 154     gtk_signal_connect( GTK_OBJECT(m_widget
), 
 156                         GTK_SIGNAL_FUNC(gtk_spinctrl_text_changed_callback
), 
 160 int wxSpinCtrl::GetMin() const 
 162     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 164     return (int)ceil(m_adjust
->lower
); 
 167 int wxSpinCtrl::GetMax() const 
 169     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 171     return (int)ceil(m_adjust
->upper
); 
 174 int wxSpinCtrl::GetValue() const 
 176     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 178     gtk_spin_button_update( GTK_SPIN_BUTTON(m_widget
) ); 
 180     return (int)ceil(m_adjust
->value
); 
 183 void wxSpinCtrl::SetValue( const wxString
& value 
) 
 185     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 188     if ( (wxSscanf(value
, wxT("%d"), &n
) == 1) ) 
 195         // invalid number - set text as is (wxMSW compatible) 
 197         gtk_entry_set_text( GTK_ENTRY(m_widget
), wxGTK_CONV( value 
) ); 
 202 void wxSpinCtrl::SetValue( int value 
) 
 204     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 206     float fpos 
= (float)value
; 
 208     if (fabs(fpos
-m_adjust
->value
) < sensitivity
) return; 
 210     m_adjust
->value 
= fpos
; 
 213     gtk_signal_emit_by_name( GTK_OBJECT(m_adjust
), "value_changed" ); 
 217 void wxSpinCtrl::SetSelection(long from
, long to
) 
 219     // translate from wxWidgets conventions to GTK+ ones: (-1, -1) means the 
 221     if ( from 
== -1 && to 
== -1 ) 
 227     gtk_editable_select_region( GTK_EDITABLE(m_widget
), (gint
)from
, (gint
)to 
); 
 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
.GetKeyCode() == WXK_RETURN
) 
 259         wxWindow 
*top_frame 
= m_parent
; 
 260         while (top_frame
->GetParent() && !(top_frame
->IsTopLevel())) 
 261             top_frame 
= top_frame
->GetParent(); 
 263         if ( GTK_IS_WINDOW(top_frame
->m_widget
) ) 
 265             GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 268                 GtkWidget 
*widgetDef 
= window
->default_widget
; 
 272                     gtk_widget_activate(widgetDef
); 
 279     if ((event
.GetKeyCode() == WXK_RETURN
) && (m_windowStyle 
& wxTE_PROCESS_ENTER
)) 
 281         wxCommandEvent 
evt( wxEVT_COMMAND_TEXT_ENTER
, m_windowId 
); 
 282         evt
.SetEventObject(this); 
 283         GtkSpinButton 
*gsb 
= GTK_SPIN_BUTTON(m_widget
); 
 284         wxString val 
= wxGTK_CONV_BACK( gtk_entry_get_text( &gsb
->entry 
) ); 
 285         evt
.SetString( val 
); 
 286         if (GetEventHandler()->ProcessEvent(evt
)) return; 
 292 bool wxSpinCtrl::IsOwnGtkWindow( GdkWindow 
*window 
) 
 294     if (GTK_SPIN_BUTTON(m_widget
)->entry
.text_area 
== window
) return true; 
 296     if (GTK_SPIN_BUTTON(m_widget
)->panel 
== window
) return true; 
 301 wxSize 
wxSpinCtrl::DoGetBestSize() const 
 303     wxSize 
ret( wxControl::DoGetBestSize() ); 
 304     wxSize 
best(95, ret
.y
); 
 311 wxSpinCtrl::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 313     // TODO: overload to accept functions like gtk_spin_button_new? 
 314     // Until then use a similar type 
 315     return GetDefaultAttributesFromGTKWidget(gtk_entry_new
, true);