1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/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" 
  19     #include "wx/textctrl.h"    // for wxEVT_COMMAND_TEXT_UPDATED 
  21     #include "wx/wxcrtvararg.h" 
  24 #include "wx/gtk/private.h" 
  26 //----------------------------------------------------------------------------- 
  28 //----------------------------------------------------------------------------- 
  30 extern bool   g_blockEventsOnDrag
; 
  32 //----------------------------------------------------------------------------- 
  34 //----------------------------------------------------------------------------- 
  38 gtk_value_changed(GtkSpinButton
* spinbutton
, wxSpinCtrlGTKBase
* win
) 
  40     win
->m_value 
= gtk_spin_button_get_value(spinbutton
); 
  41     if (!win
->m_hasVMT 
|| g_blockEventsOnDrag
) 
  44     // note that we don't use wxSpinCtrl::GetValue() here because it would 
  45     // adjust the value to fit into the control range and this means that we 
  46     // would never be able to enter an "invalid" value in the control, even 
  47     // temporarily - and trying to enter 10 into the control which accepts the 
  48     // values in range 5..50 is then, ummm, quite challenging (hint: you can't 
  51     if (wxIsKindOf(win
, wxSpinCtrl
)) 
  53         wxSpinEvent 
event(wxEVT_COMMAND_SPINCTRL_UPDATED
, win
->GetId()); 
  54         event
.SetEventObject( win 
); 
  55         event
.SetPosition((int)(win
->m_value 
+ 0.5)); // FIXME should be SetValue 
  56         event
.SetString(GTK_ENTRY(spinbutton
)->text
); 
  57         win
->HandleWindowEvent( event 
); 
  59     else // wxIsKindOf(win, wxSpinCtrlDouble) 
  61         wxSpinDoubleEvent 
event( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED
, win
->GetId()); 
  62         event
.SetEventObject( win 
); 
  63         event
.SetValue(win
->m_value
); 
  64         event
.SetString(GTK_ENTRY(spinbutton
)->text
); 
  65         win
->HandleWindowEvent( event 
); 
  70 //----------------------------------------------------------------------------- 
  72 //----------------------------------------------------------------------------- 
  76 gtk_changed(GtkSpinButton
* spinbutton
, wxSpinCtrl
* win
) 
  81     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
  82     event
.SetEventObject( win 
); 
  83     event
.SetString( GTK_ENTRY(spinbutton
)->text 
); 
  86     event
.SetInt((int)win
->m_value
); 
  87     win
->HandleWindowEvent( event 
); 
  91 //----------------------------------------------------------------------------- 
  93 //----------------------------------------------------------------------------- 
  95 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrlGTKBase
, wxSpinCtrlBase
) 
  97 BEGIN_EVENT_TABLE(wxSpinCtrlGTKBase
, wxSpinCtrlBase
) 
  98     EVT_CHAR(wxSpinCtrlGTKBase::OnChar
) 
 101 bool wxSpinCtrlGTKBase::Create(wxWindow 
*parent
, wxWindowID id
, 
 102                         const wxString
& value
, 
 103                         const wxPoint
& pos
,  const wxSize
& size
, 
 105                         double min
, double max
, double initial
, double inc
, 
 106                         const wxString
& name
) 
 108     if (!PreCreation( parent
, pos
, size 
) || 
 109         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 111         wxFAIL_MSG( wxT("wxSpinCtrlGTKBase creation failed") ); 
 115     m_widget 
= gtk_spin_button_new_with_range(min
, max
, inc
); 
 116     g_object_ref(m_widget
); 
 118     gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget
), initial
); 
 119     m_value 
= gtk_spin_button_get_value( GTK_SPIN_BUTTON(m_widget
)); 
 121     gtk_spin_button_set_wrap( GTK_SPIN_BUTTON(m_widget
), 
 122                               (int)(m_windowStyle 
& wxSP_WRAP
) ); 
 124     g_signal_connect_after(m_widget
, "value_changed", G_CALLBACK(gtk_value_changed
), this); 
 125     g_signal_connect_after(m_widget
, "changed", G_CALLBACK(gtk_changed
), this); 
 127     m_parent
->DoAddChild( this ); 
 139 double wxSpinCtrlGTKBase::DoGetValue() const 
 141     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 144     gtk_spin_button_update( GTK_SPIN_BUTTON(m_widget
) ); 
 145     const_cast<wxSpinCtrlGTKBase
*>(this)->m_value 
= 
 146         gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget
)); 
 152 double wxSpinCtrlGTKBase::DoGetMin() const 
 154     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 157     gtk_spin_button_get_range( GTK_SPIN_BUTTON(m_widget
), &min
, NULL
); 
 161 double wxSpinCtrlGTKBase::DoGetMax() const 
 163     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 166     gtk_spin_button_get_range( GTK_SPIN_BUTTON(m_widget
), NULL
, &max
); 
 170 double wxSpinCtrlGTKBase::DoGetIncrement() const 
 172     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 175     gtk_spin_button_get_increments( GTK_SPIN_BUTTON(m_widget
), NULL
, &inc
); 
 179 bool wxSpinCtrlGTKBase::GetSnapToTicks() const 
 181     wxCHECK_MSG( m_widget
, 0, "invalid spin button" ); 
 183     return gtk_spin_button_get_snap_to_ticks( GTK_SPIN_BUTTON(m_widget
) ); 
 186 void wxSpinCtrlGTKBase::SetValue( const wxString
& value 
) 
 188     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 191     if ( wxSscanf(value
, "%lg", &n
) == 1 ) 
 193         // a number - set it, let DoSetValue round for int value 
 198     // invalid number - set text as is (wxMSW compatible) 
 200     gtk_entry_set_text( GTK_ENTRY(m_widget
), wxGTK_CONV( value 
) ); 
 204 void wxSpinCtrlGTKBase::DoSetValue( double value 
) 
 206     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 208     if (wxIsKindOf(this, wxSpinCtrl
)) 
 209         value 
= int(value 
+ 0.5); 
 212     gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget
), value
); 
 213     m_value 
= gtk_spin_button_get_value( GTK_SPIN_BUTTON(m_widget
)); 
 217 void wxSpinCtrlGTKBase::SetSnapToTicks(bool snap_to_ticks
) 
 219     wxCHECK_RET( (m_widget 
!= NULL
), "invalid spin button" ); 
 221     gtk_spin_button_set_snap_to_ticks( GTK_SPIN_BUTTON(m_widget
), snap_to_ticks
); 
 224 void wxSpinCtrlGTKBase::SetSelection(long from
, long to
) 
 226     // translate from wxWidgets conventions to GTK+ ones: (-1, -1) means the 
 228     if ( from 
== -1 && to 
== -1 ) 
 234     gtk_editable_select_region( GTK_EDITABLE(m_widget
), (gint
)from
, (gint
)to 
); 
 237 void wxSpinCtrlGTKBase::DoSetRange(double minVal
, double maxVal
) 
 239     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 242     gtk_spin_button_set_range( GTK_SPIN_BUTTON(m_widget
), minVal
, maxVal
); 
 243     m_value 
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget
)); 
 247 void wxSpinCtrlGTKBase::DoSetIncrement(double inc
) 
 249     wxCHECK_RET( m_widget
, "invalid spin button" ); 
 252     gtk_spin_button_set_increments( GTK_SPIN_BUTTON(m_widget
), inc
, 10*inc
); 
 253     m_value 
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget
)); 
 257 void wxSpinCtrlGTKBase::GtkDisableEvents() const 
 259     g_signal_handlers_block_by_func( m_widget
, 
 260         (gpointer
)gtk_value_changed
, (void*) this); 
 262     g_signal_handlers_block_by_func(m_widget
, 
 263         (gpointer
)gtk_changed
, (void*) this); 
 266 void wxSpinCtrlGTKBase::GtkEnableEvents() const 
 268     g_signal_handlers_unblock_by_func(m_widget
, 
 269         (gpointer
)gtk_value_changed
, (void*) this); 
 271     g_signal_handlers_unblock_by_func(m_widget
, 
 272         (gpointer
)gtk_changed
, (void*) this); 
 275 void wxSpinCtrlGTKBase::OnChar( wxKeyEvent 
&event 
) 
 277     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid spin ctrl") ); 
 279     if (event
.GetKeyCode() == WXK_RETURN
) 
 281         wxWindow 
*top_frame 
= wxGetTopLevelParent(m_parent
); 
 283         if ( GTK_IS_WINDOW(top_frame
->m_widget
) ) 
 285             GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 288                 GtkWidget 
*widgetDef 
= window
->default_widget
; 
 292                     gtk_widget_activate(widgetDef
); 
 299     if ((event
.GetKeyCode() == WXK_RETURN
) && (m_windowStyle 
& wxTE_PROCESS_ENTER
)) 
 301         wxCommandEvent 
evt( wxEVT_COMMAND_TEXT_ENTER
, m_windowId 
); 
 302         evt
.SetEventObject(this); 
 303         GtkSpinButton 
*gsb 
= GTK_SPIN_BUTTON(m_widget
); 
 304         wxString val 
= wxGTK_CONV_BACK( gtk_entry_get_text( &gsb
->entry 
) ); 
 305         evt
.SetString( val 
); 
 306         if (HandleWindowEvent(evt
)) return; 
 312 GdkWindow 
*wxSpinCtrlGTKBase::GTKGetWindow(wxArrayGdkWindows
& windows
) const 
 314     GtkSpinButton
* spinbutton 
= GTK_SPIN_BUTTON(m_widget
); 
 316     windows
.push_back(spinbutton
->entry
.text_area
); 
 317     windows
.push_back(spinbutton
->panel
); 
 322 wxSize 
wxSpinCtrlGTKBase::DoGetBestSize() const 
 324     wxSize 
ret( wxControl::DoGetBestSize() ); 
 325     wxSize 
best(95, ret
.y
); // FIXME: 95? 
 332 wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 334     // TODO: overload to accept functions like gtk_spin_button_new? 
 335     // Until then use a similar type 
 336     return GetDefaultAttributesFromGTKWidget(gtk_entry_new
, true); 
 339 //----------------------------------------------------------------------------- 
 341 //----------------------------------------------------------------------------- 
 343 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
, wxSpinCtrlGTKBase
) 
 345 //----------------------------------------------------------------------------- 
 347 //----------------------------------------------------------------------------- 
 349 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrlDouble
, wxSpinCtrlGTKBase
) 
 351 unsigned wxSpinCtrlDouble::GetDigits() const 
 353     wxCHECK_MSG( m_widget
, 0, "invalid spin button" ); 
 355     return gtk_spin_button_get_digits( GTK_SPIN_BUTTON(m_widget
) ); 
 358 void wxSpinCtrlDouble::SetDigits(unsigned digits
) 
 360     wxCHECK_RET( m_widget
, "invalid spin button" ); 
 362     gtk_spin_button_set_digits( GTK_SPIN_BUTTON(m_widget
), digits
); 
 365 #endif // wxUSE_SPINCTRL