]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/slider.cpp
[ 1487463 ] XRC handler for wxOwnerDrawnComboBox.
[wxWidgets.git] / src / gtk / slider.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
de6185e2 2// Name: src/gtk/slider.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
f96aa4d9
RR
5// Id: $Id$
6// Copyright: (c) 1998 Robert Roebling
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
de6185e2
WS
13#if wxUSE_SLIDER
14
cc57f388
JJ
15#ifdef __VMS
16 //Missing definition in OpenVMS C++ header files.
17 double round(double __x);
18#endif
19
c801d85f 20#include "wx/slider.h"
dcf924a3 21
de6185e2
WS
22#ifndef WX_PRECOMP
23 #include "wx/utils.h"
24#endif
dcf924a3 25
9e691f46 26#include "wx/gtk/private.h"
83624f79 27
66bd6b93
RR
28//-----------------------------------------------------------------------------
29// data
30//-----------------------------------------------------------------------------
31
1e6feb95 32extern bool g_blockEventsOnDrag;
66bd6b93 33
2b024653
VZ
34// ----------------------------------------------------------------------------
35// helper functions
36// ----------------------------------------------------------------------------
37
2b024653
VZ
38// process a scroll event
39static void
12a480c1 40ProcessScrollEvent(wxSlider *win, wxEventType evtType)
2b024653 41{
46c48053
VZ
42 const int orient = win->HasFlag(wxSL_VERTICAL) ? wxVERTICAL
43 : wxHORIZONTAL;
2b024653 44
12a480c1 45 const int value = win->GetValue();
2b024653 46
46c48053
VZ
47 // if we have any "special" event (i.e. the value changed by a line or a
48 // page), send this specific event first
49 if ( evtType != wxEVT_NULL )
50 {
51 wxScrollEvent event( evtType, win->GetId(), value, orient );
52 event.SetEventObject( win );
53 win->GetEventHandler()->ProcessEvent( event );
54 }
55
56 // but, in any case, except if we're dragging the slider (and so the change
57 // is not definitive), send a generic "changed" event
8e3e14c4
VZ
58 if ( evtType != wxEVT_SCROLL_THUMBTRACK )
59 {
46c48053
VZ
60 wxScrollEvent event(wxEVT_SCROLL_CHANGED, win->GetId(), value, orient);
61 event.SetEventObject( win );
62 win->GetEventHandler()->ProcessEvent( event );
8e3e14c4
VZ
63 }
64
46c48053
VZ
65 // and also generate a command event for compatibility
66 wxCommandEvent event( wxEVT_COMMAND_SLIDER_UPDATED, win->GetId() );
67 event.SetEventObject( win );
68 event.SetInt( value );
69 win->GetEventHandler()->ProcessEvent( event );
2b024653 70}
57a1fd73 71
12a480c1
PC
72static inline wxEventType GtkScrollTypeToWx(int scrollType)
73{
74 wxEventType eventType;
75 switch (scrollType)
76 {
77 case GTK_SCROLL_STEP_BACKWARD:
78 case GTK_SCROLL_STEP_LEFT:
79 case GTK_SCROLL_STEP_UP:
80 eventType = wxEVT_SCROLL_LINEUP;
81 break;
82 case GTK_SCROLL_STEP_DOWN:
83 case GTK_SCROLL_STEP_FORWARD:
84 case GTK_SCROLL_STEP_RIGHT:
85 eventType = wxEVT_SCROLL_LINEDOWN;
86 break;
87 case GTK_SCROLL_PAGE_BACKWARD:
88 case GTK_SCROLL_PAGE_LEFT:
89 case GTK_SCROLL_PAGE_UP:
90 eventType = wxEVT_SCROLL_PAGEUP;
91 break;
92 case GTK_SCROLL_PAGE_DOWN:
93 case GTK_SCROLL_PAGE_FORWARD:
94 case GTK_SCROLL_PAGE_RIGHT:
95 eventType = wxEVT_SCROLL_PAGEDOWN;
96 break;
97 case GTK_SCROLL_START:
98 eventType = wxEVT_SCROLL_TOP;
99 break;
100 case GTK_SCROLL_END:
101 eventType = wxEVT_SCROLL_BOTTOM;
102 break;
103 case GTK_SCROLL_JUMP:
104 eventType = wxEVT_SCROLL_THUMBTRACK;
105 break;
106 default:
107 wxFAIL_MSG(_T("Unknown GtkScrollType"));
108 eventType = wxEVT_NULL;
109 break;
110 }
111 return eventType;
112}
113
114// Determine if increment is the same as +/-x, allowing for some small
115// difference due to possible inexactness in floating point arithmetic
116static inline bool IsScrollIncrement(double increment, double x)
117{
118 wxASSERT(increment > 0);
119 const double tolerance = 1.0 / 1024;
120 return fabs(increment - fabs(x)) < tolerance;
121}
122
c801d85f 123//-----------------------------------------------------------------------------
97b3455a 124// "value_changed"
c801d85f
KB
125//-----------------------------------------------------------------------------
126
865bb325 127extern "C" {
12a480c1
PC
128static void
129gtk_value_changed(GtkRange* range, wxSlider* win)
80810ca3 130{
acfd422a
RR
131 if (g_isIdle) wxapp_install_idle_handler();
132
a2053b27 133 if (!win->m_hasVMT) return;
2d17d68f 134 if (g_blockEventsOnDrag) return;
e1811a01 135
12a480c1
PC
136 GtkAdjustment* adj = range->adjustment;
137 const int pos = int(round(adj->value));
138 const double oldPos = win->m_pos;
139 win->m_pos = adj->value;
140 if (win->m_blockScrollEvent)
141 {
142 win->m_scrollEventType = GTK_SCROLL_NONE;
2b024653 143 return;
12a480c1 144 }
80810ca3 145
12a480c1
PC
146 wxEventType eventType = wxEVT_NULL;
147 if (win->m_isScrolling)
148 {
149 eventType = wxEVT_SCROLL_THUMBTRACK;
150 }
151 else if (win->m_scrollEventType != GTK_SCROLL_NONE)
152 {
153 // Scroll event from "move-slider" (keyboard)
154 eventType = GtkScrollTypeToWx(win->m_scrollEventType);
155 }
156 else if (win->m_mouseButtonDown)
157 {
158 // Difference from last change event
159 const double diff = adj->value - oldPos;
160 const bool isDown = diff > 0;
2d17d68f 161
12a480c1
PC
162 if (IsScrollIncrement(adj->page_increment, diff))
163 {
164 eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
165 }
166 else if (wxIsSameDouble(adj->value, 0))
167 {
168 eventType = wxEVT_SCROLL_PAGEUP;
169 }
170 else if (wxIsSameDouble(adj->value, adj->upper))
171 {
172 eventType = wxEVT_SCROLL_PAGEDOWN;
173 }
174 else
175 {
176 // Assume track event
177 eventType = wxEVT_SCROLL_THUMBTRACK;
178 // Remember that we're tracking
179 win->m_isScrolling = true;
180 }
181 }
182
183 win->m_scrollEventType = GTK_SCROLL_NONE;
184
185 // If integral position has changed
186 if (int(round(oldPos)) != pos)
187 {
188 wxCHECK_RET(eventType != wxEVT_NULL, _T("Unknown slider scroll event type"));
189 ProcessScrollEvent(win, eventType);
190 win->m_needThumbRelease = eventType == wxEVT_SCROLL_THUMBTRACK;
191 }
192}
193}
80810ca3 194
12a480c1
PC
195//-----------------------------------------------------------------------------
196// "move_slider" (keyboard event)
197//-----------------------------------------------------------------------------
198
199extern "C" {
200static void
201gtk_move_slider(GtkRange*, GtkScrollType scrollType, wxSlider* win)
202{
203 // Save keyboard scroll type for "value_changed" handler
204 win->m_scrollEventType = scrollType;
205}
2b024653 206}
80810ca3 207
12a480c1
PC
208//-----------------------------------------------------------------------------
209// "button_press_event"
210//-----------------------------------------------------------------------------
211
212extern "C" {
213static gboolean
214gtk_button_press_event(GtkWidget*, GdkEventButton*, wxSlider* win)
2b024653 215{
12a480c1 216 win->m_mouseButtonDown = true;
80810ca3 217
12a480c1
PC
218 return false;
219}
2b024653 220}
80810ca3 221
c918b2cd
PC
222//-----------------------------------------------------------------------------
223// "event_after"
224//-----------------------------------------------------------------------------
225
12a480c1 226extern "C" {
c918b2cd
PC
227static void
228gtk_event_after(GtkRange* range, GdkEvent* event, wxSlider* win)
2b024653 229{
c918b2cd 230 if (event->type == GDK_BUTTON_RELEASE)
12a480c1 231 {
c918b2cd
PC
232 g_signal_handlers_block_by_func(range, (void*)gtk_event_after, win);
233
234 if (win->m_needThumbRelease)
235 {
236 win->m_needThumbRelease = false;
237 ProcessScrollEvent(win, wxEVT_SCROLL_THUMBRELEASE);
238 }
239 // Keep slider at an integral position
240 win->BlockScrollEvent();
241 gtk_range_set_value((GtkRange*)win->m_widget, win->GetValue());
242 win->UnblockScrollEvent();
12a480c1 243 }
12a480c1
PC
244}
245}
2b024653 246
12a480c1
PC
247//-----------------------------------------------------------------------------
248// "button_release_event"
249//-----------------------------------------------------------------------------
2b024653 250
12a480c1
PC
251extern "C" {
252static gboolean
c918b2cd 253gtk_button_release_event(GtkRange* range, GdkEventButton*, wxSlider* win)
12a480c1
PC
254{
255 win->m_mouseButtonDown = false;
256 if (win->m_isScrolling)
257 {
c918b2cd
PC
258 win->m_isScrolling = false;
259 g_signal_handlers_unblock_by_func(range, (void*)gtk_event_after, win);
12a480c1
PC
260 }
261 return false;
262}
6de97a3b 263}
2b024653 264
12a480c1
PC
265//-----------------------------------------------------------------------------
266// "format_value"
267//-----------------------------------------------------------------------------
268
269extern "C" {
270static gchar* gtk_format_value(GtkScale*, double value, void*)
271{
272 // Format value as nearest integer
273 return g_strdup_printf("%d", int(round(value)));
274}
865bb325 275}
c801d85f 276
97b3455a
RR
277//-----------------------------------------------------------------------------
278// wxSlider
279//-----------------------------------------------------------------------------
280
c801d85f
KB
281IMPLEMENT_DYNAMIC_CLASS(wxSlider,wxControl)
282
12a480c1
PC
283wxSlider::wxSlider()
284{
285 m_pos = 0;
286 m_scrollEventType = 0;
287 m_needThumbRelease = false;
288}
289
debe6624
JS
290bool wxSlider::Create(wxWindow *parent, wxWindowID id,
291 int value, int minValue, int maxValue,
c801d85f 292 const wxPoint& pos, const wxSize& size,
6de97a3b 293 long style, const wxValidator& validator, const wxString& name )
c801d85f 294{
de6185e2
WS
295 m_acceptsFocus = true;
296 m_needParent = true;
80810ca3 297
4dcaf11a
RR
298 if (!PreCreation( parent, pos, size ) ||
299 !CreateBase( parent, id, pos, size, style, validator, name ))
300 {
223d09f6 301 wxFAIL_MSG( wxT("wxSlider creation failed") );
de6185e2 302 return false;
4dcaf11a 303 }
6de97a3b 304
12a480c1
PC
305 m_pos = 0;
306 m_scrollEventType = 0;
307 m_needThumbRelease = false;
c801d85f 308
2e563988 309 if (style & wxSL_VERTICAL)
2d17d68f 310 m_widget = gtk_vscale_new( (GtkAdjustment *) NULL );
19da4326
RR
311 else
312 m_widget = gtk_hscale_new( (GtkAdjustment *) NULL );
80810ca3 313
12a480c1
PC
314 gtk_scale_set_draw_value((GtkScale*)m_widget, (style & wxSL_LABELS) != 0);
315 // Keep full precision in position value
316 gtk_scale_set_digits((GtkScale*)m_widget, -1);
80810ca3 317
1e219378
KH
318 if (style & wxSL_INVERSE)
319 gtk_range_set_inverted( GTK_RANGE(m_widget), TRUE );
320
12a480c1
PC
321 g_signal_connect(m_widget, "button_press_event", G_CALLBACK(gtk_button_press_event), this);
322 g_signal_connect(m_widget, "button_release_event", G_CALLBACK(gtk_button_release_event), this);
323 g_signal_connect(m_widget, "move_slider", G_CALLBACK(gtk_move_slider), this);
324 g_signal_connect(m_widget, "format_value", G_CALLBACK(gtk_format_value), NULL);
325 g_signal_connect(m_widget, "value_changed", G_CALLBACK(gtk_value_changed), this);
c918b2cd
PC
326 gulong handler_id;
327 handler_id = g_signal_connect(
328 m_widget, "event_after", G_CALLBACK(gtk_event_after), this);
329 g_signal_handler_block(m_widget, handler_id);
91b167dd 330
2d17d68f
RR
331 SetRange( minValue, maxValue );
332 SetValue( value );
80810ca3 333
f03fc89f 334 m_parent->DoAddChild( this );
80810ca3 335
abdeb9e7 336 PostCreation(size);
80810ca3 337
de6185e2 338 return true;
6de97a3b 339}
c801d85f 340
1e1fafb9 341int wxSlider::GetValue() const
c801d85f 342{
12a480c1 343 return int(round(m_pos));
6de97a3b 344}
c801d85f 345
debe6624 346void wxSlider::SetValue( int value )
c801d85f 347{
12a480c1
PC
348 if (GetValue() != value)
349 {
350 BlockScrollEvent();
351 gtk_range_set_value((GtkRange*)m_widget, value);
352 UnblockScrollEvent();
353 }
6de97a3b 354}
c801d85f 355
debe6624 356void wxSlider::SetRange( int minValue, int maxValue )
c801d85f 357{
12a480c1
PC
358 BlockScrollEvent();
359 gtk_range_set_range((GtkRange*)m_widget, minValue, maxValue);
360 gtk_range_set_increments((GtkRange*)m_widget, 1, (maxValue - minValue + 9) / 10);
361 UnblockScrollEvent();
6de97a3b 362}
c801d85f 363
1e1fafb9 364int wxSlider::GetMin() const
c801d85f 365{
12a480c1 366 return int(((GtkRange*)m_widget)->adjustment->lower);
6de97a3b 367}
c801d85f 368
1e1fafb9 369int wxSlider::GetMax() const
c801d85f 370{
12a480c1 371 return int(((GtkRange*)m_widget)->adjustment->upper);
6de97a3b 372}
c801d85f 373
debe6624 374void wxSlider::SetPageSize( int pageSize )
c801d85f 375{
12a480c1
PC
376 BlockScrollEvent();
377 gtk_range_set_increments((GtkRange*)m_widget, 1, pageSize);
378 UnblockScrollEvent();
6de97a3b 379}
c801d85f 380
1e1fafb9 381int wxSlider::GetPageSize() const
c801d85f 382{
12a480c1 383 return int(((GtkRange*)m_widget)->adjustment->page_increment);
6de97a3b 384}
c801d85f 385
12a480c1
PC
386// GTK does not support changing the size of the slider
387void wxSlider::SetThumbLength(int)
c801d85f 388{
6de97a3b 389}
c801d85f 390
1e1fafb9 391int wxSlider::GetThumbLength() const
c801d85f 392{
12a480c1 393 return 0;
6de97a3b 394}
c801d85f 395
debe6624 396void wxSlider::SetLineSize( int WXUNUSED(lineSize) )
c801d85f 397{
6de97a3b 398}
c801d85f 399
1e1fafb9 400int wxSlider::GetLineSize() const
c801d85f 401{
2d17d68f 402 return 0;
6de97a3b 403}
c801d85f 404
b4071e91
RR
405bool wxSlider::IsOwnGtkWindow( GdkWindow *window )
406{
2d17d68f 407 GtkRange *range = GTK_RANGE(m_widget);
2b5f62a0 408 return (range->event_window == window);
b4071e91
RR
409}
410
9d522606
RD
411// static
412wxVisualAttributes
413wxSlider::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
414{
415 return GetDefaultAttributesFromGTKWidget(gtk_vscale_new);
416}
417
de6185e2 418#endif // wxUSE_SLIDER