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     if (!win
->m_hasVMT 
|| g_blockEventsOnDrag
) 
  43     if (wxIsKindOf(win
, wxSpinCtrl
)) 
  45         wxSpinEvent 
event(wxEVT_COMMAND_SPINCTRL_UPDATED
, win
->GetId()); 
  46         event
.SetEventObject( win 
); 
  47         event
.SetPosition(static_cast<wxSpinCtrl
*>(win
)->GetValue()); 
  48         event
.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton
))); 
  49         win
->HandleWindowEvent( event 
); 
  51     else // wxIsKindOf(win, wxSpinCtrlDouble) 
  53         wxSpinDoubleEvent 
event( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED
, win
->GetId()); 
  54         event
.SetEventObject( win 
); 
  55         event
.SetValue(static_cast<wxSpinCtrlDouble
*>(win
)->GetValue()); 
  56         event
.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton
))); 
  57         win
->HandleWindowEvent( event 
); 
  62 //----------------------------------------------------------------------------- 
  64 //----------------------------------------------------------------------------- 
  68 gtk_changed(GtkSpinButton
* spinbutton
, wxSpinCtrl
* win
) 
  73     wxCommandEvent 
event( wxEVT_COMMAND_TEXT_UPDATED
, win
->GetId() ); 
  74     event
.SetEventObject( win 
); 
  75     event
.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton
))); 
  76     event
.SetInt(win
->GetValue()); 
  77     win
->HandleWindowEvent( event 
); 
  81 //----------------------------------------------------------------------------- 
  83 //----------------------------------------------------------------------------- 
  85 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrlGTKBase
, wxSpinCtrlBase
) 
  87 BEGIN_EVENT_TABLE(wxSpinCtrlGTKBase
, wxSpinCtrlBase
) 
  88     EVT_CHAR(wxSpinCtrlGTKBase::OnChar
) 
  91 bool wxSpinCtrlGTKBase::Create(wxWindow 
*parent
, wxWindowID id
, 
  92                         const wxString
& value
, 
  93                         const wxPoint
& pos
,  const wxSize
& size
, 
  95                         double min
, double max
, double initial
, double inc
, 
  98     if (!PreCreation( parent
, pos
, size 
) || 
  99         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 101         wxFAIL_MSG( wxT("wxSpinCtrlGTKBase creation failed") ); 
 105     m_widget 
= gtk_spin_button_new_with_range(min
, max
, inc
); 
 106     g_object_ref(m_widget
); 
 108     gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget
), initial
); 
 111     if ( HasFlag(wxALIGN_RIGHT
) ) 
 113     else if ( HasFlag(wxALIGN_CENTRE
) ) 
 118     gtk_entry_set_alignment(GTK_ENTRY(m_widget
), align
); 
 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") ); 
 142     // Get value directly from current control text, just as 
 143     // gtk_spin_button_update() would do. Calling gtk_spin_button_update() causes 
 144     // a redraw, which causes an idle event, so if GetValue() is called from 
 145     // a UI update handler, you get a never ending sequence of idle events. It 
 146     // also forces the text into valid range, which wxMSW GetValue() does not do. 
 147     static unsigned sig_id
; 
 149         sig_id 
= g_signal_lookup("input", GTK_TYPE_SPIN_BUTTON
); 
 152     g_signal_emit(m_widget
, sig_id
, 0, &value
, &handled
); 
 154         value 
= g_strtod(gtk_entry_get_text(GTK_ENTRY(m_widget
)), NULL
); 
 155     const GtkAdjustment
* adj 
= 
 156         gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(m_widget
)); 
 157     if (value 
< adj
->lower
) 
 159     else if (value 
> adj
->upper
) 
 165 double wxSpinCtrlGTKBase::DoGetMin() const 
 167     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 170     gtk_spin_button_get_range( GTK_SPIN_BUTTON(m_widget
), &min
, NULL
); 
 174 double wxSpinCtrlGTKBase::DoGetMax() const 
 176     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 179     gtk_spin_button_get_range( GTK_SPIN_BUTTON(m_widget
), NULL
, &max
); 
 183 double wxSpinCtrlGTKBase::DoGetIncrement() const 
 185     wxCHECK_MSG( (m_widget 
!= NULL
), 0, wxT("invalid spin button") ); 
 188     gtk_spin_button_get_increments( GTK_SPIN_BUTTON(m_widget
), &inc
, NULL
); 
 192 bool wxSpinCtrlGTKBase::GetSnapToTicks() const 
 194     wxCHECK_MSG(m_widget
, false, "invalid spin button"); 
 196     return gtk_spin_button_get_snap_to_ticks( GTK_SPIN_BUTTON(m_widget
) ); 
 199 void wxSpinCtrlGTKBase::SetValue( const wxString
& value 
) 
 201     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 204     if ( wxSscanf(value
, "%lg", &n
) == 1 ) 
 206         // a number - set it, let DoSetValue round for int value 
 211     // invalid number - set text as is (wxMSW compatible) 
 213     gtk_entry_set_text( GTK_ENTRY(m_widget
), wxGTK_CONV( value 
) ); 
 217 void wxSpinCtrlGTKBase::DoSetValue( double value 
) 
 219     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 222     gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget
), value
); 
 226 void wxSpinCtrlGTKBase::SetSnapToTicks(bool snap_to_ticks
) 
 228     wxCHECK_RET( (m_widget 
!= NULL
), "invalid spin button" ); 
 230     gtk_spin_button_set_snap_to_ticks( GTK_SPIN_BUTTON(m_widget
), snap_to_ticks
); 
 233 void wxSpinCtrlGTKBase::SetSelection(long from
, long to
) 
 235     // translate from wxWidgets conventions to GTK+ ones: (-1, -1) means the 
 237     if ( from 
== -1 && to 
== -1 ) 
 243     gtk_editable_select_region( GTK_EDITABLE(m_widget
), (gint
)from
, (gint
)to 
); 
 246 void wxSpinCtrlGTKBase::DoSetRange(double minVal
, double maxVal
) 
 248     wxCHECK_RET( (m_widget 
!= NULL
), wxT("invalid spin button") ); 
 251     gtk_spin_button_set_range( GTK_SPIN_BUTTON(m_widget
), minVal
, maxVal
); 
 255 void wxSpinCtrlGTKBase::DoSetIncrement(double inc
) 
 257     wxCHECK_RET( m_widget
, "invalid spin button" ); 
 261     // Preserve the old page value when changing just the increment. 
 262     double page 
= 10*inc
; 
 263     gtk_spin_button_get_increments( GTK_SPIN_BUTTON(m_widget
), NULL
, &page
); 
 265     gtk_spin_button_set_increments( GTK_SPIN_BUTTON(m_widget
), inc
, page
); 
 269 void wxSpinCtrlGTKBase::GtkDisableEvents() const 
 271     g_signal_handlers_block_by_func( m_widget
, 
 272         (gpointer
)gtk_value_changed
, (void*) this); 
 274     g_signal_handlers_block_by_func(m_widget
, 
 275         (gpointer
)gtk_changed
, (void*) this); 
 278 void wxSpinCtrlGTKBase::GtkEnableEvents() const 
 280     g_signal_handlers_unblock_by_func(m_widget
, 
 281         (gpointer
)gtk_value_changed
, (void*) this); 
 283     g_signal_handlers_unblock_by_func(m_widget
, 
 284         (gpointer
)gtk_changed
, (void*) this); 
 287 void wxSpinCtrlGTKBase::OnChar( wxKeyEvent 
&event 
) 
 289     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid spin ctrl") ); 
 291     if (event
.GetKeyCode() == WXK_RETURN
) 
 293         wxWindow 
*top_frame 
= wxGetTopLevelParent(m_parent
); 
 295         if ( GTK_IS_WINDOW(top_frame
->m_widget
) ) 
 297             GtkWindow 
*window 
= GTK_WINDOW(top_frame
->m_widget
); 
 300                 GtkWidget 
*widgetDef 
= window
->default_widget
; 
 304                     gtk_widget_activate(widgetDef
); 
 311     if ((event
.GetKeyCode() == WXK_RETURN
) && (m_windowStyle 
& wxTE_PROCESS_ENTER
)) 
 313         wxCommandEvent 
evt( wxEVT_COMMAND_TEXT_ENTER
, m_windowId 
); 
 314         evt
.SetEventObject(this); 
 315         GtkSpinButton 
*gsb 
= GTK_SPIN_BUTTON(m_widget
); 
 316         wxString val 
= wxGTK_CONV_BACK( gtk_entry_get_text( &gsb
->entry 
) ); 
 317         evt
.SetString( val 
); 
 318         if (HandleWindowEvent(evt
)) return; 
 324 GdkWindow 
*wxSpinCtrlGTKBase::GTKGetWindow(wxArrayGdkWindows
& windows
) const 
 326     GtkSpinButton
* spinbutton 
= GTK_SPIN_BUTTON(m_widget
); 
 328     windows
.push_back(spinbutton
->entry
.text_area
); 
 329     windows
.push_back(spinbutton
->panel
); 
 334 wxSize 
wxSpinCtrlGTKBase::DoGetBestSize() const 
 336     wxSize 
ret( wxControl::DoGetBestSize() ); 
 337     wxSize 
best(95, ret
.y
); // FIXME: 95? 
 344 wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 346     // TODO: overload to accept functions like gtk_spin_button_new? 
 347     // Until then use a similar type 
 348     return GetDefaultAttributesFromGTKWidget(gtk_entry_new
, true); 
 351 //----------------------------------------------------------------------------- 
 353 //----------------------------------------------------------------------------- 
 355 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
, wxSpinCtrlGTKBase
) 
 357 //----------------------------------------------------------------------------- 
 359 //----------------------------------------------------------------------------- 
 361 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrlDouble
, wxSpinCtrlGTKBase
) 
 363 unsigned wxSpinCtrlDouble::GetDigits() const 
 365     wxCHECK_MSG( m_widget
, 0, "invalid spin button" ); 
 367     return gtk_spin_button_get_digits( GTK_SPIN_BUTTON(m_widget
) ); 
 370 void wxSpinCtrlDouble::SetDigits(unsigned digits
) 
 372     wxCHECK_RET( m_widget
, "invalid spin button" ); 
 374     gtk_spin_button_set_digits( GTK_SPIN_BUTTON(m_widget
), digits
); 
 377 #endif // wxUSE_SPINCTRL