Include wx/utils.h according to precompiled headers of wx/wx.h (with other minor...
[wxWidgets.git] / src / gtk1 / slider.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk1/slider.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_SLIDER
14
15 #include "wx/slider.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/utils.h"
19 #endif
20
21 #include "wx/math.h"
22 #include "wx/gtk1/private.h"
23
24 //-----------------------------------------------------------------------------
25 // idle system
26 //-----------------------------------------------------------------------------
27
28 extern void wxapp_install_idle_handler();
29 extern bool g_isIdle;
30
31 //-----------------------------------------------------------------------------
32 // data
33 //-----------------------------------------------------------------------------
34
35 extern bool g_blockEventsOnDrag;
36
37 // ----------------------------------------------------------------------------
38 // helper functions
39 // ----------------------------------------------------------------------------
40
41 // compare 2 adjustment values up to some (hardcoded) precision
42 static inline bool AreSameAdjustValues(double x, double y)
43 {
44 return fabs(x - y) < 0.02;
45 }
46
47 static inline int AdjustValueToInt(double x)
48 {
49 // we want to round to the nearest integer, i.e. 0.9 is rounded to 1 and
50 // -0.9 is rounded to -1
51 return (int)(x < 0 ? x - 0.5 : x + 0.5);
52 }
53
54 // process a scroll event
55 static void
56 ProcessScrollEvent(wxSlider *win, wxEventType evtType, double dvalue)
57 {
58 int orient = win->GetWindowStyleFlag() & wxSL_VERTICAL ? wxVERTICAL
59 : wxHORIZONTAL;
60
61 int value = (int)(dvalue < 0 ? dvalue - 0.5 : dvalue + 0.5);
62 wxScrollEvent event( evtType, win->GetId(), value, orient );
63 event.SetEventObject( win );
64 win->GetEventHandler()->ProcessEvent( event );
65
66 if ( evtType != wxEVT_SCROLL_THUMBTRACK )
67 {
68 wxScrollEvent event2(wxEVT_SCROLL_CHANGED, win->GetId(), value, orient);
69 event2.SetEventObject( win );
70 win->GetEventHandler()->ProcessEvent( event2 );
71 }
72
73 wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, win->GetId() );
74 cevent.SetEventObject( win );
75 cevent.SetInt( value );
76 win->GetEventHandler()->ProcessEvent( cevent );
77 }
78
79 //-----------------------------------------------------------------------------
80 // "value_changed"
81 //-----------------------------------------------------------------------------
82
83 extern "C" {
84 static void gtk_slider_callback( GtkAdjustment *adjust,
85 SCROLLBAR_CBACK_ARG
86 wxSlider *win )
87 {
88 if (g_isIdle) wxapp_install_idle_handler();
89
90 if (!win->m_hasVMT) return;
91 if (g_blockEventsOnDrag) return;
92
93 const double dvalue = adjust->value;
94 const double diff = dvalue - win->m_oldPos;
95 if ( AreSameAdjustValues(diff, 0) )
96 return;
97
98 wxEventType evtType;
99 evtType = GtkScrollTypeToWx(GET_SCROLL_TYPE(win->m_widget));
100
101 ProcessScrollEvent(win, evtType, dvalue);
102
103 win->m_oldPos = dvalue;
104 }
105
106 static gint gtk_slider_button_press_callback( GtkWidget * /* widget */,
107 GdkEventButton * /* gdk_event */,
108 wxWindowGTK *win)
109 {
110 // indicate that the thumb is being dragged with the mouse
111 win->m_isScrolling = true;
112
113 return FALSE;
114 }
115
116 static gint gtk_slider_button_release_callback( GtkWidget *scale,
117 GdkEventButton * /* gdk_event */,
118 wxSlider *win)
119 {
120 // not scrolling any longer
121 win->m_isScrolling = false;
122
123 ProcessScrollEvent(win, wxEVT_SCROLL_THUMBRELEASE,
124 GTK_RANGE(scale)->adjustment->value);
125
126 return FALSE;
127 }
128
129 }
130
131 //-----------------------------------------------------------------------------
132 // wxSlider
133 //-----------------------------------------------------------------------------
134
135 IMPLEMENT_DYNAMIC_CLASS(wxSlider,wxControl)
136
137 bool wxSlider::Create(wxWindow *parent, wxWindowID id,
138 int value, int minValue, int maxValue,
139 const wxPoint& pos, const wxSize& size,
140 long style, const wxValidator& validator, const wxString& name )
141 {
142 m_acceptsFocus = true;
143 m_needParent = true;
144
145 if (!PreCreation( parent, pos, size ) ||
146 !CreateBase( parent, id, pos, size, style, validator, name ))
147 {
148 wxFAIL_MSG( wxT("wxSlider creation failed") );
149 return false;
150 }
151
152 m_oldPos = 0.0;
153
154 if (style & wxSL_VERTICAL)
155 m_widget = gtk_vscale_new( (GtkAdjustment *) NULL );
156 else
157 m_widget = gtk_hscale_new( (GtkAdjustment *) NULL );
158
159 if (style & wxSL_LABELS)
160 {
161 gtk_scale_set_draw_value( GTK_SCALE( m_widget ), TRUE );
162 gtk_scale_set_digits( GTK_SCALE( m_widget ), 0 );
163
164 /* labels need more space and too small window will
165 cause junk to appear on the dialog */
166 if (style & wxSL_VERTICAL)
167 {
168 wxSize sz( size );
169 if (sz.x < 35)
170 {
171 sz.x = 35;
172 SetSize( sz );
173 }
174 }
175 else
176 {
177 wxSize sz( size );
178 if (sz.y < 35)
179 {
180 sz.y = 35;
181 SetSize( sz );
182 }
183 }
184 }
185 else
186 gtk_scale_set_draw_value( GTK_SCALE( m_widget ), FALSE );
187
188 m_adjust = gtk_range_get_adjustment( GTK_RANGE(m_widget) );
189
190 GtkEnableEvents();
191 gtk_signal_connect( GTK_OBJECT(m_widget),
192 "button_press_event",
193 (GtkSignalFunc)gtk_slider_button_press_callback,
194 (gpointer) this );
195 gtk_signal_connect( GTK_OBJECT(m_widget),
196 "button_release_event",
197 (GtkSignalFunc)gtk_slider_button_release_callback,
198 (gpointer) this );
199
200 SetRange( minValue, maxValue );
201 SetValue( value );
202
203 m_parent->DoAddChild( this );
204
205 PostCreation(size);
206
207 return true;
208 }
209
210 int wxSlider::GetValue() const
211 {
212 return AdjustValueToInt(m_adjust->value);
213 }
214
215 void wxSlider::SetValue( int value )
216 {
217 double fpos = (double)value;
218 m_oldPos = fpos;
219 if ( AreSameAdjustValues(fpos, m_adjust->value) )
220 return;
221
222 m_adjust->value = fpos;
223
224 GtkDisableEvents();
225
226 gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "value_changed" );
227
228 GtkEnableEvents();
229 }
230
231 void wxSlider::SetRange( int minValue, int maxValue )
232 {
233 double fmin = (double)minValue;
234 double fmax = (double)maxValue;
235
236 if ((fabs(fmin-m_adjust->lower) < 0.2) &&
237 (fabs(fmax-m_adjust->upper) < 0.2))
238 {
239 return;
240 }
241
242 m_adjust->lower = fmin;
243 m_adjust->upper = fmax;
244 m_adjust->step_increment = 1.0;
245 m_adjust->page_increment = ceil((fmax-fmin) / 10.0);
246
247 GtkDisableEvents();
248
249 gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
250
251 GtkEnableEvents();
252 }
253
254 int wxSlider::GetMin() const
255 {
256 return (int)ceil(m_adjust->lower);
257 }
258
259 int wxSlider::GetMax() const
260 {
261 return (int)ceil(m_adjust->upper);
262 }
263
264 void wxSlider::SetPageSize( int pageSize )
265 {
266 double fpage = (double)pageSize;
267
268 if (fabs(fpage-m_adjust->page_increment) < 0.2) return;
269
270 m_adjust->page_increment = fpage;
271
272 GtkDisableEvents();
273
274 gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
275
276 GtkEnableEvents();
277 }
278
279 int wxSlider::GetPageSize() const
280 {
281 return (int)ceil(m_adjust->page_increment);
282 }
283
284 void wxSlider::SetThumbLength( int len )
285 {
286 double flen = (double)len;
287
288 if (fabs(flen-m_adjust->page_size) < 0.2) return;
289
290 m_adjust->page_size = flen;
291
292 GtkDisableEvents();
293
294 gtk_signal_emit_by_name( GTK_OBJECT(m_adjust), "changed" );
295
296 GtkEnableEvents();
297 }
298
299 int wxSlider::GetThumbLength() const
300 {
301 return (int)ceil(m_adjust->page_size);
302 }
303
304 void wxSlider::SetLineSize( int WXUNUSED(lineSize) )
305 {
306 }
307
308 int wxSlider::GetLineSize() const
309 {
310 return 0;
311 }
312
313 bool wxSlider::IsOwnGtkWindow( GdkWindow *window )
314 {
315 GtkRange *range = GTK_RANGE(m_widget);
316 return ( (window == GTK_WIDGET(range)->window)
317 || (window == range->trough)
318 || (window == range->slider)
319 || (window == range->step_forw)
320 || (window == range->step_back) );
321 }
322
323 void wxSlider::GtkDisableEvents()
324 {
325 gtk_signal_disconnect_by_func( GTK_OBJECT(m_adjust),
326 GTK_SIGNAL_FUNC(gtk_slider_callback),
327 (gpointer) this );
328 }
329
330 void wxSlider::GtkEnableEvents()
331 {
332 gtk_signal_connect( GTK_OBJECT (m_adjust),
333 "value_changed",
334 GTK_SIGNAL_FUNC(gtk_slider_callback),
335 (gpointer) this );
336 }
337
338 // static
339 wxVisualAttributes
340 wxSlider::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
341 {
342 return GetDefaultAttributesFromGTKWidget(gtk_vscale_new);
343 }
344
345 #endif // wxUSE_SLIDER