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
);