1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        gtk/slider.cpp 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  13 #include "wx/slider.h" 
  19 #include "wx/gtk/private.h" 
  21 //----------------------------------------------------------------------------- 
  23 //----------------------------------------------------------------------------- 
  25 extern bool g_blockEventsOnDrag
; 
  27 // ---------------------------------------------------------------------------- 
  29 // ---------------------------------------------------------------------------- 
  31 // compare 2 adjustment values up to some (hardcoded) precision 
  32 static inline bool AreSameAdjustValues(double x
, double y
) 
  34     return fabs(x 
- y
) < 0.02; 
  37 static inline int AdjustValueToInt(double x
) 
  39     // we want to round to the nearest integer, i.e. 0.9 is rounded to 1 and 
  40     // -0.9 is rounded to -1 
  41     return (int)(x 
< 0 ? x 
- 0.5 : x 
+ 0.5); 
  44 // process a scroll event 
  46 ProcessScrollEvent(wxSlider 
*win
, wxEventType evtType
, double dvalue
) 
  48     const int orient 
= win
->HasFlag(wxSL_VERTICAL
) ? wxVERTICAL
 
  51     const int value 
= (int)(dvalue 
< 0 ? dvalue 
- 0.5 : dvalue 
+ 0.5); 
  53     // if we have any "special" event (i.e. the value changed by a line or a 
  54     // page), send this specific event first 
  55     if ( evtType 
!= wxEVT_NULL 
) 
  57         wxScrollEvent 
event( evtType
, win
->GetId(), value
, orient 
); 
  58         event
.SetEventObject( win 
); 
  59         win
->GetEventHandler()->ProcessEvent( event 
); 
  62     // but, in any case, except if we're dragging the slider (and so the change 
  63     // is not definitive), send a generic "changed" event 
  64     if ( evtType 
!= wxEVT_SCROLL_THUMBTRACK 
) 
  66         wxScrollEvent 
event(wxEVT_SCROLL_CHANGED
, win
->GetId(), value
, orient
); 
  67         event
.SetEventObject( win 
); 
  68         win
->GetEventHandler()->ProcessEvent( event 
); 
  71     // and also generate a command event for compatibility 
  72     wxCommandEvent 
event( wxEVT_COMMAND_SLIDER_UPDATED
, win
->GetId() ); 
  73     event
.SetEventObject( win 
); 
  74     event
.SetInt( value 
); 
  75     win
->GetEventHandler()->ProcessEvent( event 
); 
  78 //----------------------------------------------------------------------------- 
  80 //----------------------------------------------------------------------------- 
  83 static void gtk_slider_callback( GtkAdjustment 
*adjust
, 
  86     if (g_isIdle
) wxapp_install_idle_handler(); 
  88     if (!win
->m_hasVMT
) return; 
  89     if (g_blockEventsOnDrag
) return; 
  91     const double dvalue 
= adjust
->value
; 
  92     const double diff 
= dvalue 
- win
->m_oldPos
; 
  93     if ( AreSameAdjustValues(diff
, 0) ) 
  97     if ( win
->m_isScrolling 
) 
  98         evtType 
= wxEVT_SCROLL_THUMBTRACK
; 
  99     // it could seem that UP/DOWN are inversed but this is what wxMSW does 
 100     else if ( AreSameAdjustValues(diff
, adjust
->step_increment
) ) 
 101         evtType 
= wxEVT_SCROLL_LINEDOWN
; 
 102     else if ( AreSameAdjustValues(diff
, -adjust
->step_increment
) ) 
 103         evtType 
= wxEVT_SCROLL_LINEUP
; 
 104     else if ( AreSameAdjustValues(diff
, adjust
->page_increment
) ) 
 105         evtType 
= wxEVT_SCROLL_PAGEDOWN
; 
 106     else if ( AreSameAdjustValues(diff
, -adjust
->page_increment
) ) 
 107         evtType 
= wxEVT_SCROLL_PAGEUP
; 
 108     else if ( AreSameAdjustValues(adjust
->value
, adjust
->lower
) ) 
 109         evtType 
= wxEVT_SCROLL_TOP
; 
 110     else if ( AreSameAdjustValues(adjust
->value
, adjust
->upper
) ) 
 111         evtType 
= wxEVT_SCROLL_BOTTOM
; 
 113         evtType 
= wxEVT_NULL
; // wxEVT_SCROLL_CHANGED will still be generated 
 115     ProcessScrollEvent(win
, evtType
, dvalue
); 
 117     win
->m_oldPos 
= dvalue
; 
 120 static gint 
gtk_slider_button_press_callback( GtkWidget 
* /* widget */, 
 121                                               GdkEventButton 
* /* gdk_event */, 
 124     // indicate that the thumb is being dragged with the mouse 
 125     win
->m_isScrolling 
= true; 
 130 static gint 
gtk_slider_button_release_callback( GtkWidget 
*scale
, 
 131                                                 GdkEventButton 
* /* gdk_event */, 
 134     // not scrolling any longer 
 135     win
->m_isScrolling 
= false; 
 137     ProcessScrollEvent(win
, wxEVT_SCROLL_THUMBRELEASE
, 
 138                        GTK_RANGE(scale
)->adjustment
->value
); 
 145 //----------------------------------------------------------------------------- 
 147 //----------------------------------------------------------------------------- 
 149 IMPLEMENT_DYNAMIC_CLASS(wxSlider
,wxControl
) 
 151 bool wxSlider::Create(wxWindow 
*parent
, wxWindowID id
, 
 152         int value
, int minValue
, int maxValue
, 
 153         const wxPoint
& pos
, const wxSize
& size
, 
 154         long style
, const wxValidator
& validator
, const wxString
& name 
) 
 156     m_acceptsFocus 
= TRUE
; 
 159     if (!PreCreation( parent
, pos
, size 
) || 
 160         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
 162         wxFAIL_MSG( wxT("wxSlider creation failed") ); 
 168     if (style 
& wxSL_VERTICAL
) 
 169         m_widget 
= gtk_vscale_new( (GtkAdjustment 
*) NULL 
); 
 171         m_widget 
= gtk_hscale_new( (GtkAdjustment 
*) NULL 
); 
 173     if (style 
& wxSL_LABELS
) 
 175         gtk_scale_set_draw_value( GTK_SCALE( m_widget 
), TRUE 
); 
 176         gtk_scale_set_digits( GTK_SCALE( m_widget 
), 0 ); 
 178         /* labels need more space and too small window will 
 179            cause junk to appear on the dialog */ 
 180         if (style 
& wxSL_VERTICAL
) 
 200         gtk_scale_set_draw_value( GTK_SCALE( m_widget 
), FALSE 
); 
 202     m_adjust 
= gtk_range_get_adjustment( GTK_RANGE(m_widget
) ); 
 204     if (style 
& wxSL_INVERSE
) 
 205         gtk_range_set_inverted( GTK_RANGE(m_widget
), TRUE 
); 
 208     g_signal_connect (m_widget
, "button_press_event", 
 209                       G_CALLBACK (gtk_slider_button_press_callback
), 
 211     g_signal_connect (m_widget
, "button_release_event", 
 212                       G_CALLBACK (gtk_slider_button_release_callback
), 
 215     SetRange( minValue
, maxValue 
); 
 218     m_parent
->DoAddChild( this ); 
 225 int wxSlider::GetValue() const 
 227     return AdjustValueToInt(m_adjust
->value
); 
 230 void wxSlider::SetValue( int value 
) 
 232     double fpos 
= (double)value
; 
 234     if ( AreSameAdjustValues(fpos
, m_adjust
->value
) ) 
 237     m_adjust
->value 
= fpos
; 
 241     g_signal_emit_by_name (m_adjust
, "value_changed"); 
 246 void wxSlider::SetRange( int minValue
, int maxValue 
) 
 248     double fmin 
= (double)minValue
; 
 249     double fmax 
= (double)maxValue
; 
 251     if ((fabs(fmin
-m_adjust
->lower
) < 0.2) && 
 252         (fabs(fmax
-m_adjust
->upper
) < 0.2)) 
 257     m_adjust
->lower 
= fmin
; 
 258     m_adjust
->upper 
= fmax
; 
 259     m_adjust
->step_increment 
= 1.0; 
 260     m_adjust
->page_increment 
= ceil((fmax
-fmin
) / 10.0); 
 264     g_signal_emit_by_name (m_adjust
, "changed"); 
 269 int wxSlider::GetMin() const 
 271     return (int)ceil(m_adjust
->lower
); 
 274 int wxSlider::GetMax() const 
 276     return (int)ceil(m_adjust
->upper
); 
 279 void wxSlider::SetPageSize( int pageSize 
) 
 281     double fpage 
= (double)pageSize
; 
 283     if (fabs(fpage
-m_adjust
->page_increment
) < 0.2) return; 
 285     m_adjust
->page_increment 
= fpage
; 
 289     g_signal_emit_by_name (m_adjust
, "changed"); 
 294 int wxSlider::GetPageSize() const 
 296     return (int)ceil(m_adjust
->page_increment
); 
 299 void wxSlider::SetThumbLength( int len 
) 
 301     double flen 
= (double)len
; 
 303     if (fabs(flen
-m_adjust
->page_size
) < 0.2) return; 
 305     m_adjust
->page_size 
= flen
; 
 309     g_signal_emit_by_name (m_adjust
, "changed"); 
 314 int wxSlider::GetThumbLength() const 
 316     return (int)ceil(m_adjust
->page_size
); 
 319 void wxSlider::SetLineSize( int WXUNUSED(lineSize
) ) 
 323 int wxSlider::GetLineSize() const 
 328 bool wxSlider::IsOwnGtkWindow( GdkWindow 
*window 
) 
 330     GtkRange 
*range 
= GTK_RANGE(m_widget
); 
 331     return (range
->event_window 
== window
); 
 334 void wxSlider::GtkDisableEvents() 
 336     g_signal_handlers_disconnect_by_func (m_adjust
, 
 337                                           (gpointer
) gtk_slider_callback
, 
 341 void wxSlider::GtkEnableEvents() 
 343     g_signal_connect (m_adjust
, "value_changed", 
 344                       G_CALLBACK (gtk_slider_callback
), this); 
 349 wxSlider::GetClassDefaultAttributes(wxWindowVariant 
WXUNUSED(variant
)) 
 351     return GetDefaultAttributesFromGTKWidget(gtk_vscale_new
);