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
); 
 117     gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget
), initial
); 
 118     m_value 
= gtk_spin_button_get_value( GTK_SPIN_BUTTON(m_widget
)); 
 120     gtk_spin_button_set_wrap( GTK_SPIN_BUTTON(m_widget
), 
 121                               (int)(m_windowStyle 
& wxSP_WRAP
) ); 
 123     g_signal_connect_after(m_widget
, "value_changed", G_CALLBACK(gtk_value_changed
), this); 
 124     g_signal_connect_after(m_widget
, "changed", G_CALLBACK(gtk_changed
), this); 
 126     m_parent
->DoAddChild( this ); 
 138 double wxSpinCtrlGTKBase::DoGetValue() const 
 140     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 143     gtk_spin_button_update( GTK_SPIN_BUTTON(m_widget
) ); 
 144     wx_const_cast(wxSpinCtrlGTKBase
*, this)->m_value 
= 
 145         gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget
)); 
 151 double wxSpinCtrlGTKBase::DoGetMin() const 
 153     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 156     gtk_spin_button_get_range( GTK_SPIN_BUTTON(m_widget
), &min
, NULL
); 
 160 double wxSpinCtrlGTKBase::DoGetMax() const 
 162     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 165     gtk_spin_button_get_range( GTK_SPIN_BUTTON(m_widget
), NULL
, &max
); 
 169 double wxSpinCtrlGTKBase::DoGetIncrement() const 
 171     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 174     gtk_spin_button_get_increments( GTK_SPIN_BUTTON(m_widget
), NULL
, &inc
); 
 178 bool wxSpinCtrlGTKBase::GetSnapToTicks() const 
 180     wxCHECK_MSG( m_widget
, 0, "invalid spin button" ); 
 182     return gtk_spin_button_get_snap_to_ticks( GTK_SPIN_BUTTON(m_widget
) ); 
 185 void wxSpinCtrlGTKBase::SetValue( const wxString
& value 
) 
 187     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 190     if ( wxSscanf(value
, "%lg", &n
) == 1 ) 
 192         // a number - set it, let DoSetValue round for int value 
 197     // invalid number - set text as is (wxMSW compatible) 
 199     gtk_entry_set_text( GTK_ENTRY(m_widget
), wxGTK_CONV( value 
) ); 
 203 void wxSpinCtrlGTKBase::DoSetValue( double value 
) 
 205     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 207     if (wxIsKindOf(this, wxSpinCtrl
)) 
 208         value 
= int(value 
+ 0.5); 
 211     gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget
), value
); 
 212     m_value 
= gtk_spin_button_get_value( GTK_SPIN_BUTTON(m_widget
)); 
 216 void wxSpinCtrlGTKBase::SetSnapToTicks(bool snap_to_ticks
) 
 218     wxCHECK_RET( (m_widget 
!= NULL
), "invalid spin button" ); 
 220     gtk_spin_button_set_snap_to_ticks( GTK_SPIN_BUTTON(m_widget
), snap_to_ticks
); 
 223 void wxSpinCtrlGTKBase::SetSelection(long from
, long to
) 
 225     // translate from wxWidgets conventions to GTK+ ones: (-1, -1) means the 
 227     if ( from 
== -1 && to 
== -1 ) 
 233     gtk_editable_select_region( GTK_EDITABLE(m_widget
), (gint
)from
, (gint
)to 
); 
 236 void wxSpinCtrlGTKBase::DoSetRange(double minVal
, double maxVal
) 
 238     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 241     gtk_spin_button_set_range( GTK_SPIN_BUTTON(m_widget
), minVal
, maxVal
); 
 242     m_value 
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget
)); 
 246 void wxSpinCtrlGTKBase::DoSetIncrement(double inc
) 
 248     wxCHECK_RET( m_widget
, "invalid spin button" ); 
 251     gtk_spin_button_set_increments( GTK_SPIN_BUTTON(m_widget
), inc
, 10*inc
); 
 252     m_value 
= gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget
)); 
 256 void wxSpinCtrlGTKBase::GtkDisableEvents() const 
 258     g_signal_handlers_block_by_func( m_widget
, 
 259         (gpointer
)gtk_value_changed
, (void*) this); 
 261     g_signal_handlers_block_by_func(m_widget
, 
 262         (gpointer
)gtk_changed
, (void*) this); 
 265 void wxSpinCtrlGTKBase::GtkEnableEvents() const 
 267     g_signal_handlers_unblock_by_func(m_widget
, 
 268         (gpointer
)gtk_value_changed
, (void*) this); 
 270     g_signal_handlers_unblock_by_func(m_widget
, 
 271         (gpointer
)gtk_changed
, (void*) this); 
 274 void wxSpinCtrlGTKBase::OnChar( wxKeyEvent 
&event 
) 
 276     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid spin ctrl") ); 
 278     if (event
.GetKeyCode() == WXK_RETURN
) 
 280         wxWindow 
*top_frame 
= wxGetTopLevelParent(m_parent
); 
 282         if ( GTK_IS_WINDOW(top_frame
->m_widget
) ) 
 284             GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 287                 GtkWidget 
*widgetDef 
= window
->default_widget
; 
 291                     gtk_widget_activate(widgetDef
); 
 298     if ((event
.GetKeyCode() == WXK_RETURN
) && (m_windowStyle 
& wxTE_PROCESS_ENTER
)) 
 300         wxCommandEvent 
evt( wxEVT_COMMAND_TEXT_ENTER
, m_windowId 
); 
 301         evt
.SetEventObject(this); 
 302         GtkSpinButton 
*gsb 
= GTK_SPIN_BUTTON(m_widget
); 
 303         wxString val 
= wxGTK_CONV_BACK( gtk_entry_get_text( &gsb
->entry 
) ); 
 304         evt
.SetString( val 
); 
 305         if (HandleWindowEvent(evt
)) return; 
 311 GdkWindow 
*wxSpinCtrlGTKBase::GTKGetWindow(wxArrayGdkWindows
& windows
) const 
 313     GtkSpinButton
* spinbutton 
= GTK_SPIN_BUTTON(m_widget
); 
 315     windows
.push_back(spinbutton
->entry
.text_area
); 
 316     windows
.push_back(spinbutton
->panel
); 
 321 wxSize 
wxSpinCtrlGTKBase::DoGetBestSize() const 
 323     wxSize 
ret( wxControl::DoGetBestSize() ); 
 324     wxSize 
best(95, ret
.y
); // FIXME: 95? 
 331 wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 333     // TODO: overload to accept functions like gtk_spin_button_new? 
 334     // Until then use a similar type 
 335     return GetDefaultAttributesFromGTKWidget(gtk_entry_new
, true); 
 338 //----------------------------------------------------------------------------- 
 340 //----------------------------------------------------------------------------- 
 342 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
, wxSpinCtrlGTKBase
) 
 344 //----------------------------------------------------------------------------- 
 346 //----------------------------------------------------------------------------- 
 348 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrlDouble
, wxSpinCtrlGTKBase
) 
 350 unsigned wxSpinCtrlDouble::GetDigits() const 
 352     wxCHECK_MSG( m_widget
, 0, "invalid spin button" ); 
 354     return gtk_spin_button_get_digits( GTK_SPIN_BUTTON(m_widget
) ); 
 357 void wxSpinCtrlDouble::SetDigits(unsigned digits
) 
 359     wxCHECK_RET( m_widget
, "invalid spin button" ); 
 361     gtk_spin_button_set_digits( GTK_SPIN_BUTTON(m_widget
), digits
); 
 364 #endif // wxUSE_SPINCTRL