]> git.saurik.com Git - wxWidgets.git/blame - src/univ/slider.cpp
using backward compatible calls for HitTest hack
[wxWidgets.git] / src / univ / slider.cpp
CommitLineData
1e6feb95
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: univ/slider.cpp
3// Purpose: implementation of the universal version of wxSlider
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 09.02.01
7// RCS-ID: $Id$
442b35b5 8// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
65571936 9// Licence: wxWindows licence
1e6feb95
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12/*
13 There is some discrepancy in wxSL_LABELS style handling between wxMSW and
14 wxGTK: the latter handles it natively and shows only the current value of
15 the slider on the side corresponding to wxSL_TOP/BOTTOM/LEFT/RIGHT style
16 given (which can be combined with wxSL_HORIZONTAL/VERTICAL) while wxMSW
17 emulates this somehow and shows the min and max values near the ends of the
18 slider and the current value in a separate static box nearby.
19
20 We currently follow wxGTK except that wxSL_HORIZONTAL slider can only have
21 the label displayed on top or bottom of it and wxSL_VERTICAL - to the left
22 or right.
23
24 What we really need is probably a more fine grain control on labels, i.e. we
d6922577 25 should be able to select if we show nothing at all, the current value only
1e6feb95 26 or the value and the limits - the current approach is just that of the
d6922577 27 lowest common denominator.
1e6feb95
VZ
28
29 TODO:
30
31 +0. add ticks support
32 1. support for all orientations
33 2. draw the slider thumb highlighted when it is dragged
34 ?3. manual ticks support?
35 */
36
37// ============================================================================
38// declarations
39// ============================================================================
40
41// ----------------------------------------------------------------------------
42// headers
43// ----------------------------------------------------------------------------
44
1e6feb95
VZ
45#include "wx/wxprec.h"
46
47#ifdef __BORLANDC__
48 #pragma hdrstop
49#endif
50
51#ifndef WX_PRECOMP
52 #include "wx/dc.h"
53#endif
54
55#include "wx/slider.h"
56
57#if wxUSE_SLIDER
58
59#include "wx/univ/renderer.h"
60#include "wx/univ/inphand.h"
61#include "wx/univ/theme.h"
62
63// ----------------------------------------------------------------------------
64// constants
65// ----------------------------------------------------------------------------
66
67// the margin between the slider and the label (FIXME: hardcoded)
68static const wxCoord SLIDER_LABEL_MARGIN = 2;
69
70// ============================================================================
71// implementation of wxSlider
72// ============================================================================
73
74IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
75
76BEGIN_EVENT_TABLE(wxSlider, wxControl)
77 EVT_SIZE(wxSlider::OnSize)
78END_EVENT_TABLE()
79
80// ----------------------------------------------------------------------------
81// wxSlider creation
82// ----------------------------------------------------------------------------
83
84#ifdef __VISUALC__
85 // warning C4355: 'this' : used in base member initializer list
86 #pragma warning(disable:4355)
87#endif
88
89wxSlider::wxSlider()
90 : m_thumb(this)
91{
92 Init();
93}
94
95wxSlider::wxSlider(wxWindow *parent,
96 wxWindowID id,
97 int value, int minValue, int maxValue,
98 const wxPoint& pos,
99 const wxSize& size,
100 long style,
101 const wxValidator& validator,
102 const wxString& name)
103 : m_thumb(this)
104{
105 Init();
106
107 (void)Create(parent, id, value, minValue, maxValue,
108 pos, size, style, validator, name);
109}
110
111#ifdef __VISUALC__
112 // warning C4355: 'this' : used in base member initializer list
113 #pragma warning(default:4355)
114#endif
115
116void wxSlider::Init()
117{
118 m_min =
119 m_max =
120 m_value = 0;
121
122 m_tickFreq = 1;
123
124 m_lineSize =
125 m_pageSize = 0;
126
127 m_thumbSize = 0;
128 m_thumbFlags = 0;
129}
130
131bool wxSlider::Create(wxWindow *parent,
132 wxWindowID id,
133 int value, int minValue, int maxValue,
134 const wxPoint& pos,
135 const wxSize& size,
136 long style,
137 const wxValidator& validator,
138 const wxString& name)
139{
140 if ( !wxSliderBase::Create(parent, id, pos, size, style,
141 validator, name) )
a290fa5a 142 return false;
1e6feb95
VZ
143
144 SetRange(minValue, maxValue);
145 SetValue(value);
146
147 // call this after setting the range as the best size depends (at least if
148 // we have wxSL_LABELS style) on the range
149 SetBestSize(size);
150
151 CreateInputHandler(wxINP_HANDLER_SLIDER);
152
a290fa5a 153 return true;
1e6feb95
VZ
154}
155
156// ----------------------------------------------------------------------------
157// wxSlider range and value
158// ----------------------------------------------------------------------------
159
160int wxSlider::GetValue() const
161{
162 return m_value;
163}
164
165int wxSlider::NormalizeValue(int value) const
166{
167 if ( value < m_min )
168 return m_min;
169 else if ( value > m_max )
170 return m_max;
171 else
172 return value;
173}
174
175bool wxSlider::ChangeValueBy(int inc)
176{
177 return ChangeValueTo(NormalizeValue(m_value + inc));
178}
179
180bool wxSlider::ChangeValueTo(int value)
181{
6766e5d1 182 // check if the value is going to change at all
a290fa5a 183 if (value == m_value) return false;
6766e5d1 184
1e6feb95
VZ
185 // this method is protected and we should only call it with normalized
186 // value!
a290fa5a 187 wxCHECK_MSG( IsInRange(value), false, _T("invalid slider value") );
1e6feb95 188
1e6feb95
VZ
189 m_value = value;
190
6766e5d1 191 Refresh();
1e6feb95
VZ
192
193 // generate the event
194 wxCommandEvent event(wxEVT_COMMAND_SLIDER_UPDATED, GetId());
195 event.SetInt(m_value);
196 event.SetEventObject(this);
197
198 (void)GetEventHandler()->ProcessEvent(event);
199
a290fa5a 200 return true;
1e6feb95
VZ
201}
202
203void wxSlider::SetValue(int value)
204{
205 value = NormalizeValue(value);
206
207 if ( m_value != value )
208 {
209 m_value = value;
210
211 Refresh();
212 }
213}
214
215void wxSlider::SetRange(int minValue, int maxValue)
216{
217 if ( minValue > maxValue )
218 {
219 // swap them, we always want min to be less than max
220 int tmp = minValue;
221 minValue = maxValue;
222 maxValue = tmp;
223 }
224
225 if ( m_min != minValue || m_max != maxValue )
226 {
227 m_min = minValue;
228 m_max = maxValue;
229
230 // reset the value to make sure it is in the new range
231 SetValue(m_value);
232
233 // the size of the label rect might have changed
234 if ( HasLabels() )
235 {
236 CalcGeometry();
237 }
238
239 Refresh();
240 }
241 //else: nothing changed
242}
243
244int wxSlider::GetMin() const
245{
246 return m_min;
247}
248
249int wxSlider::GetMax() const
250{
251 return m_max;
252}
253
254// ----------------------------------------------------------------------------
255// wxSlider line/page/thumb size
256// ----------------------------------------------------------------------------
257
258void wxSlider::SetLineSize(int lineSize)
259{
6766e5d1 260 wxCHECK_RET( lineSize >= 0, _T("invalid slider line size") );
1e6feb95
VZ
261
262 m_lineSize = lineSize;
263}
264
265void wxSlider::SetPageSize(int pageSize)
266{
6766e5d1 267 wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );
1e6feb95
VZ
268
269 m_pageSize = pageSize;
270}
271
272int wxSlider::GetLineSize() const
273{
274 if ( !m_lineSize )
275 {
276 // the default line increment is 1
277 wxConstCast(this, wxSlider)->m_lineSize = 1;
278 }
279
280 return m_lineSize;
281}
282
283int wxSlider::GetPageSize() const
284{
285 if ( !m_pageSize )
286 {
6766e5d1
JS
287 // the default page increment is m_tickFreq
288 wxConstCast(this, wxSlider)->m_pageSize = m_tickFreq;
1e6feb95
VZ
289 }
290
291 return m_pageSize;
292}
293
294void wxSlider::SetThumbLength(int lenPixels)
295{
6766e5d1 296 wxCHECK_RET( lenPixels >= 0, _T("invalid slider thumb size") );
1e6feb95
VZ
297
298 // use m_thumbSize here directly and not GetThumbLength() to avoid setting
299 // it to the default value as we don't need it
300 if ( lenPixels != m_thumbSize )
301 {
302 m_thumbSize = lenPixels;
303
304 Refresh();
305 }
306}
307
308int wxSlider::GetThumbLength() const
309{
6766e5d1
JS
310 wxSize sz = GetDefaultThumbSize();
311 int len = (IsVert() ? sz.x : sz.y);
32b13913 312 if (m_thumbSize > len)
6766e5d1
JS
313 {
314 return m_thumbSize;
315 }
316 else
1e6feb95 317 {
6766e5d1 318 return len;
1e6feb95
VZ
319 }
320
1e6feb95
VZ
321}
322
323// ----------------------------------------------------------------------------
324// wxSlider ticks
325// ----------------------------------------------------------------------------
326
327void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
328{
6766e5d1
JS
329 wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));
330
1e6feb95
VZ
331 if ( n != m_tickFreq )
332 {
333 m_tickFreq = n;
334
335 Refresh();
336 }
337}
338
339// ----------------------------------------------------------------------------
340// wxSlider geometry
341// ----------------------------------------------------------------------------
342
343wxSize wxSlider::CalcLabelSize() const
344{
345 wxSize size;
346
347 // there is no sense in trying to calc the labels size if we haven't got
348 // any, the caller must check for it
349 wxCHECK_MSG( HasLabels(), size, _T("shouldn't be called") );
350
351 wxCoord w1, h1, w2, h2;
352 GetTextExtent(FormatValue(m_min), &w1, &h1);
353 GetTextExtent(FormatValue(m_max), &w2, &h2);
354
355 size.x = wxMax(w1, w2);
356 size.y = wxMax(h1, h2);
357
358 return size;
359}
360
361wxSize wxSlider::DoGetBestClientSize() const
362{
363 // this dimension is completely arbitrary
6766e5d1
JS
364 static const wxCoord SLIDER_WIDTH = 40;
365
366 long style = GetWindowStyle();
1e6feb95
VZ
367
368 // first calculate the size of the slider itself: i.e. the shaft and the
369 // thumb
370 wxCoord height = GetRenderer()->GetSliderDim();
371
372 wxSize size;
373 if ( IsVert() )
374 {
375 size.x = height;
376 size.y = SLIDER_WIDTH;
377 }
378 else // horizontal
379 {
380 size.x = SLIDER_WIDTH;
381 size.y = height;
382 }
383
384 // add space for ticks
385 if ( HasTicks() )
386 {
387 wxCoord lenTick = GetRenderer()->GetSliderTickLen();
32b13913 388 if (style & wxSL_BOTH)
6766e5d1
JS
389 {
390 lenTick = 2 * lenTick;
391 }
1e6feb95
VZ
392
393 if ( IsVert() )
394 size.x += lenTick;
395 else
396 size.y += lenTick;
397 }
398
399 // if we have the label, reserve enough space for it
400 if ( HasLabels() )
401 {
402 wxSize sizeLabels = CalcLabelSize();
403
6766e5d1
JS
404 if (style & (wxSL_LEFT|wxSL_RIGHT))
405 {
1e6feb95 406 size.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
6766e5d1
JS
407 }
408 else if (style & (wxSL_TOP|wxSL_BOTTOM))
409 {
1e6feb95 410 size.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
6766e5d1 411 }
1e6feb95
VZ
412 }
413
414 return size;
415}
416
417void wxSlider::OnSize(wxSizeEvent& event)
418{
419 CalcGeometry();
420
421 event.Skip();
422}
423
424const wxRect& wxSlider::GetSliderRect() const
425{
426 if ( m_rectSlider.width < 0 )
427 {
428 wxConstCast(this, wxSlider)->CalcGeometry();
429 }
430
431 return m_rectSlider;
432}
433
434void wxSlider::CalcGeometry()
435{
436 /*
437 recalc the label and slider positions, this looks like this for
438 wxSL_HORIZONTAL | wxSL_TOP slider:
439
440 LLL lll
441 -------------------------
442 | T | <-- this is the slider rect
443 | HHHHHHHHHHHHHHHTHHHHH |
444 | T |
445 | * * * * * * * *|
446 -------------------------
447
448 LLL is m_rectLabel as calculated here and lll is the real rect used for
449 label drawing in OnDraw() (TTT indicated the thumb position and *s are
450 the ticks)
451
452 in the wxSL_VERTICAL | wxSL_RIGHT case the picture is like this:
453
454 ------ LLL
455 | H |
456 | H *|
457 | H |
458 | H *|
459 | H |
460 | H *|
461 | H |
462 |TTT*| lll
463 | H |
464 | H *|
465 ------
466 */
6766e5d1 467 long style = GetWindowStyle();
1e6feb95 468
6766e5d1 469 // initialize to the full client rect
1e6feb95 470 wxRect rectTotal = GetClientRect();
6766e5d1
JS
471 m_rectSlider = rectTotal;
472 wxSize sizeThumb = GetThumbSize();
473
474 // Labels reduce the size of the slider rect
1e6feb95
VZ
475 if ( HasLabels() )
476 {
6766e5d1 477 wxSize sizeLabels = CalcLabelSize();
1e6feb95 478
1e6feb95
VZ
479 m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);
480
32b13913 481 if (style & wxSL_TOP)
1e6feb95 482 {
6766e5d1
JS
483 // shrink and offset the slider to the bottom
484 m_rectSlider.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
485 m_rectSlider.height -= sizeLabels.y + SLIDER_LABEL_MARGIN;
1e6feb95 486 }
32b13913 487 else if (style & wxSL_BOTTOM)
1e6feb95 488 {
6766e5d1
JS
489 // shrink the slider and move the label to the bottom
490 m_rectSlider.height -= sizeLabels.y + SLIDER_LABEL_MARGIN;
491 m_rectLabel.y += m_rectSlider.height + SLIDER_LABEL_MARGIN;
492 }
32b13913 493 else if (style & wxSL_LEFT)
6766e5d1
JS
494 {
495 // shrink and offset the slider to the right
496 m_rectSlider.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
497 m_rectSlider.width -= sizeLabels.x + SLIDER_LABEL_MARGIN;
498 }
32b13913 499 else if (style & wxSL_RIGHT)
6766e5d1
JS
500 {
501 // shrink the slider and move the label to the right
502 m_rectSlider.width -= sizeLabels.x + SLIDER_LABEL_MARGIN;
503 m_rectLabel.x += m_rectSlider.width + SLIDER_LABEL_MARGIN;
1e6feb95 504 }
1e6feb95
VZ
505 }
506
6766e5d1 507 // calculate ticks too
1e6feb95
VZ
508 if ( HasTicks() )
509 {
510 wxCoord lenTick = GetRenderer()->GetSliderTickLen();
511
1e6feb95
VZ
512 // it
513 m_rectTicks = GetShaftRect();
514
515 if ( IsVert() )
516 {
32b13913 517 if (style & (wxSL_LEFT|wxSL_BOTH))
6766e5d1
JS
518 {
519 m_rectTicks.x = m_rectSlider.x;
520 }
521 else
522 { // wxSL_RIGHT
523 m_rectTicks.x = m_rectSlider.x + m_rectSlider.width - lenTick;
524 }
1e6feb95
VZ
525 m_rectTicks.width = lenTick;
526 }
527 else // horizontal
528 {
32b13913 529 if (style & (wxSL_TOP|wxSL_BOTH))
6766e5d1
JS
530 {
531 m_rectTicks.y = m_rectSlider.y;
532 }
533 else
534 { // wxSL_BOTTOM
535 m_rectTicks.y = m_rectSlider.y + m_rectSlider.height - lenTick;
536 }
1e6feb95
VZ
537 m_rectTicks.height = lenTick;
538 }
6766e5d1 539 }
1e6feb95 540
6766e5d1
JS
541 // slider is never smaller than thumb size unless rectTotal
542 if ( IsVert() )
543 {
544 wxCoord width = wxMin ( rectTotal.width, sizeThumb.x );
545 m_rectSlider.width = wxMax ( m_rectSlider.width, width );
546 }
547 else
548 {
549 wxCoord height = wxMin ( rectTotal.height, sizeThumb.y );
550 m_rectSlider.height = wxMax ( m_rectSlider.height, height );
1e6feb95
VZ
551 }
552}
553
554wxSize wxSlider::GetDefaultThumbSize() const
555{
6766e5d1
JS
556 // Default size has no styles (arrows)
557 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), 0, GetOrientation());
1e6feb95
VZ
558}
559
560wxSize wxSlider::GetThumbSize() const
561{
6766e5d1 562 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), m_thumbSize, GetOrientation());
1e6feb95
VZ
563}
564
565// ----------------------------------------------------------------------------
566// wxSlider thumb geometry
567// ----------------------------------------------------------------------------
568
569wxRect wxSlider::GetShaftRect() const
570{
6766e5d1 571 return GetRenderer()->GetSliderShaftRect(m_rectSlider, m_thumbSize, GetOrientation(), GetWindowStyle());
1e6feb95
VZ
572}
573
574void wxSlider::CalcThumbRect(const wxRect *rectShaftIn,
575 wxRect *rectThumbOut,
576 wxRect *rectLabelOut,
577 int value) const
578{
579 if ( value == INVALID_THUMB_VALUE )
580 {
581 // use the current if not specified
582 value = m_value;
583 }
584
585 bool isVertical = IsVert();
586
587 wxRect rectShaft;
588 if ( rectShaftIn )
589 {
590 rectShaft = *rectShaftIn;
591 }
592 else // no shaft rect provided, calc it
593 {
594 rectShaft = GetShaftRect();
595 }
596
597 wxCoord lenShaft,
32b13913
WS
598 lenThumb;
599 wxCoord *p;
600
1e6feb95
VZ
601 wxRect rectThumb(rectShaft.GetPosition(), GetThumbSize());
602 if ( isVertical )
603 {
604 rectThumb.x += (rectShaft.width - rectThumb.width) / 2;
605
606 lenThumb = rectThumb.height;
607 lenShaft = rectShaft.height;
608 p = &rectThumb.y;
609 }
610 else // horz
611 {
612 rectThumb.y += (rectShaft.height - rectThumb.height) / 2;
613
614 lenThumb = rectThumb.width;
615 lenShaft = rectShaft.width;
616 p = &rectThumb.x;
617 }
618
619 // the thumb must always be entirely inside the shaft limits, so the max
620 // position is not at lenShaft but at lenShaft - thumbSize
621 if ( m_max != m_min )
622 {
6766e5d1
JS
623 if ( isVertical )
624 {
625 *p += ((lenShaft - lenThumb)*(m_max - value))/(m_max - m_min);
626 }
627 else
628 { // horz
629 *p += ((lenShaft - lenThumb)*(value - m_min))/(m_max - m_min);
630 }
1e6feb95
VZ
631 }
632
633 // calc the label rect
634 if ( HasLabels() && rectLabelOut )
635 {
6766e5d1 636 long style = GetWindowStyle();
1e6feb95
VZ
637 wxRect rectLabel = m_rectLabel;
638
639 // centre the label relatively to the thumb position
6766e5d1 640 if (style & (wxSL_TOP|wxSL_BOTTOM))
1e6feb95 641 {
6766e5d1 642 rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
1e6feb95 643 }
6766e5d1 644 else if (style & (wxSL_LEFT|wxSL_RIGHT))
1e6feb95 645 {
6766e5d1 646 rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
1e6feb95
VZ
647 }
648
649 *rectLabelOut = rectLabel;
650 }
651
652 if ( rectThumbOut )
6766e5d1 653
1e6feb95
VZ
654 *rectThumbOut = rectThumb;
655}
656
657// ----------------------------------------------------------------------------
658// wxSlider drawing
659// ----------------------------------------------------------------------------
660
661wxString wxSlider::FormatValue(int value) const
662{
663 return wxString::Format(_T("%d"), value);
664}
665
666void wxSlider::DoDraw(wxControlRenderer *renderer)
667{
668 wxRenderer *rend = GetRenderer();
669 wxDC& dc = renderer->GetDC();
670 wxRect rectUpdate = GetUpdateClientRect();
671
1e6feb95
VZ
672 wxOrientation orient = GetOrientation();
673 int flags = GetStateFlags();
6766e5d1
JS
674 long style = GetWindowStyle();
675
676 wxSize sz = GetThumbSize();
677 int len = IsVert() ? sz.x : sz.y;
1e6feb95
VZ
678
679 // first draw the shaft
6766e5d1 680 wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
1e6feb95
VZ
681 if ( rectUpdate.Intersects(rectShaft) )
682 {
6766e5d1 683 rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
1e6feb95
VZ
684 }
685
686 // calculate the thumb position in pixels and draw it
687 wxRect rectThumb, rectLabel;
688 CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
689
6766e5d1
JS
690 // then draw the ticks
691 if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
1e6feb95 692 {
6766e5d1
JS
693 rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
694 m_min, m_max, m_tickFreq, flags, style);
1e6feb95
VZ
695 }
696
6766e5d1
JS
697 // then draw the thumb
698 if ( rectUpdate.Intersects(rectThumb) )
1e6feb95 699 {
6766e5d1 700 rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
1e6feb95
VZ
701 }
702
703 // finally, draw the label near the thumb
704 if ( HasLabels() && rectUpdate.Intersects(rectLabel) )
705 {
706 // align it to be close to the shaft
6766e5d1 707 int align = 0;
32b13913 708 if (style & wxSL_TOP)
1e6feb95 709 {
6766e5d1 710 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
1e6feb95 711 }
32b13913 712 else if (style & wxSL_BOTTOM)
1e6feb95 713 {
6766e5d1
JS
714 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
715 }
32b13913 716 else if (style & wxSL_LEFT)
6766e5d1
JS
717 {
718 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
719 }
32b13913 720 else if (style & wxSL_RIGHT)
6766e5d1
JS
721 {
722 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
1e6feb95
VZ
723 }
724
725 dc.SetFont(GetFont());
726 dc.SetTextForeground(GetForegroundColour());
727
728 // the slider label is never drawn focused
729 rend->DrawLabel(dc, FormatValue(m_value), rectLabel,
730 flags & ~wxCONTROL_FOCUSED, align);
731 }
732}
733
1e6feb95
VZ
734// ----------------------------------------------------------------------------
735// wxSlider input processing
736// ----------------------------------------------------------------------------
737
738bool wxSlider::PerformAction(const wxControlAction& action,
739 long numArg,
740 const wxString& strArg)
741{
88d2e567 742 if ( action == wxACTION_SLIDER_START )
1e6feb95
VZ
743 {
744 ChangeValueTo(m_min);
745 }
746 else if ( action == wxACTION_SLIDER_END )
747 {
748 ChangeValueTo(m_max);
749 }
750 else if ( action == wxACTION_SLIDER_PAGE_CHANGE )
751 {
752 ChangeValueBy(numArg * GetPageSize());
753 }
754 else if ( action == wxACTION_SLIDER_LINE_UP )
755 {
6766e5d1 756 ChangeValueBy(+GetLineSize());
1e6feb95 757 }
6766e5d1 758 else if ( action == wxACTION_SLIDER_LINE_DOWN )
1e6feb95 759 {
6766e5d1 760 ChangeValueBy(-GetLineSize());
1e6feb95 761 }
6766e5d1 762 else if ( action == wxACTION_SLIDER_PAGE_UP )
1e6feb95 763 {
6766e5d1 764 ChangeValueBy(+GetPageSize());
1e6feb95
VZ
765 }
766 else if ( action == wxACTION_SLIDER_PAGE_DOWN )
767 {
6766e5d1 768 ChangeValueBy(-GetPageSize());
1e6feb95
VZ
769 }
770 else if ( action == wxACTION_SLIDER_THUMB_DRAG )
771 {
772 // no special processing for it
a290fa5a 773 return true;
1e6feb95
VZ
774 }
775 else if ( action == wxACTION_SLIDER_THUMB_MOVE ||
776 action == wxACTION_SLIDER_THUMB_RELEASE )
777 {
778 ChangeValueTo((int)numArg);
779 }
780 else
781 {
782 return wxControl::PerformAction(action, numArg, strArg);
783 }
784
a290fa5a 785 return true;
1e6feb95
VZ
786}
787
788// ----------------------------------------------------------------------------
789// wxSlider implementation of wxControlWithThumb interface
790// ----------------------------------------------------------------------------
791
792wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
793{
794 wxRect rectShaft = GetShaftRect();
2b5f62a0
VZ
795 wxRect rectThumb;
796 CalcThumbRect(&rectShaft, &rectThumb, NULL);
797
6766e5d1 798 // check for possible shaft or thumb hit
32b13913 799 if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
1e6feb95
VZ
800 {
801 return wxScrollThumb::Shaft_None;
802 }
803
1e6feb95 804 // the position to test and the start and end of the thumb
6766e5d1 805 wxCoord x, x1, x2, x3, x4;
32b13913 806 if (IsVert())
1e6feb95
VZ
807 {
808 x = pt.y;
6766e5d1
JS
809 x1 = rectThumb.GetBottom();
810 x2 = rectShaft.GetBottom();
811 x3 = rectShaft.GetTop();
812 x4 = rectThumb.GetTop();
1e6feb95 813 }
6766e5d1
JS
814 else
815 { // horz
1e6feb95 816 x = pt.x;
6766e5d1
JS
817 x1 = rectShaft.GetLeft();
818 x2 = rectThumb.GetLeft();
819 x3 = rectThumb.GetRight();
820 x4 = rectShaft.GetRight();
1e6feb95 821 }
88d2e567 822 if ((x1 <= x) && (x < x2))
1e6feb95
VZ
823 {
824 // or to the left
825 return wxScrollThumb::Shaft_Above;
826 }
827
88d2e567 828 if ((x3 < x) && (x <= x4)) {
1e6feb95
VZ
829 // or to the right
830 return wxScrollThumb::Shaft_Below;
831 }
832
833 // where else can it be?
834 return wxScrollThumb::Shaft_Thumb;
835}
836
837wxCoord wxSlider::ThumbPosToPixel() const
838{
839 wxRect rectThumb;
840 CalcThumbRect(NULL, &rectThumb, NULL);
841
842 return IsVert() ? rectThumb.y : rectThumb.x;
843}
844
845int wxSlider::PixelToThumbPos(wxCoord x) const
846{
847 wxRect rectShaft = GetShaftRect();
848 wxSize sizeThumb = GetThumbSize();
849
850 wxCoord x0, len;
851 if ( IsVert() )
852 {
853 x0 = rectShaft.y;
854 len = rectShaft.height - sizeThumb.y;
855 }
856 else // horz
857 {
858 x0 = rectShaft.x;
859 len = rectShaft.width - sizeThumb.x;
860 }
861
862 int pos = m_min;
863 if ( len > 0 )
864 {
865 if ( x > x0 )
866 {
867 pos += ((x - x0) * (m_max - m_min)) / len;
868 if ( pos > m_max )
869 pos = m_max;
870 }
871 //else: x <= x0, leave pos = min
872 }
873
874 return pos;
875}
876
877void wxSlider::SetShaftPartState(wxScrollThumb::Shaft shaftPart,
878 int flag,
879 bool set)
880{
881 // for now we ignore the flags for the shaft as no renderer uses them
882 // anyhow
883 if ( shaftPart == wxScrollThumb::Shaft_Thumb )
884 {
885 if ( set )
886 m_thumbFlags |= flag;
887 else
888 m_thumbFlags &= ~flag;
889
6766e5d1 890 Refresh();
1e6feb95
VZ
891 }
892}
893
894void wxSlider::OnThumbDragStart(int pos)
895{
32b13913 896 if (IsVert())
6766e5d1
JS
897 {
898 PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
899 }
900 else
901 {
902 PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
903 }
1e6feb95
VZ
904}
905
906void wxSlider::OnThumbDrag(int pos)
907{
32b13913 908 if (IsVert())
6766e5d1
JS
909 {
910 PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
911 }
912 else
913 {
914 PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
915 }
1e6feb95
VZ
916}
917
918void wxSlider::OnThumbDragEnd(int pos)
919{
32b13913 920 if (IsVert())
6766e5d1
JS
921 {
922 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
923 }
924 else
925 {
926 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
927 }
1e6feb95
VZ
928}
929
930void wxSlider::OnPageScrollStart()
931{
932 // we do nothing here
933}
934
935bool wxSlider::OnPageScroll(int pageInc)
936{
937 int value = GetValue();
938 PerformAction(wxACTION_SLIDER_PAGE_CHANGE, pageInc);
939
940 return GetValue() != value;
941}
942
943// ----------------------------------------------------------------------------
944// wxStdSliderButtonInputHandler
945// ----------------------------------------------------------------------------
946
23645bfa 947bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
948 const wxKeyEvent& event,
949 bool pressed)
950{
88d2e567 951 if ( pressed )
1e6feb95
VZ
952 {
953 int keycode = event.GetKeyCode();
954
955 wxControlAction action;
956 switch ( keycode )
957 {
958 case WXK_HOME:
6766e5d1 959 action = wxACTION_SLIDER_END;
1e6feb95
VZ
960 break;
961
962 case WXK_END:
6766e5d1 963 action = wxACTION_SLIDER_START;
1e6feb95
VZ
964 break;
965
6766e5d1 966 case WXK_RIGHT:
1e6feb95
VZ
967 case WXK_UP:
968 action = wxACTION_SLIDER_LINE_UP;
969 break;
970
6766e5d1 971 case WXK_LEFT:
1e6feb95
VZ
972 case WXK_DOWN:
973 action = wxACTION_SLIDER_LINE_DOWN;
974 break;
975
976 case WXK_PRIOR:
187c183c 977 case WXK_PAGEUP:
1e6feb95
VZ
978 action = wxACTION_SLIDER_PAGE_UP;
979 break;
980
981 case WXK_NEXT:
187c183c 982 case WXK_PAGEDOWN:
1e6feb95
VZ
983 action = wxACTION_SLIDER_PAGE_DOWN;
984 break;
985 }
986
a290fa5a 987 if ( !action.IsEmpty() )
1e6feb95 988 {
23645bfa 989 consumer->PerformAction(action);
1e6feb95 990
a290fa5a 991 return true;
1e6feb95
VZ
992 }
993 }
994
23645bfa 995 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
996}
997
23645bfa 998bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
999 const wxMouseEvent& event)
1000{
23645bfa 1001 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1002
1003 if ( slider->GetThumb().HandleMouse(event) )
1004 {
1005 // processed by the thumb
a290fa5a 1006 return false;
1e6feb95
VZ
1007 }
1008
23645bfa 1009 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
1010}
1011
23645bfa 1012bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
1013 const wxMouseEvent& event)
1014{
23645bfa 1015 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1016
1017 if ( slider->GetThumb().HandleMouseMove(event) )
1018 {
1019 // processed by the thumb
a290fa5a 1020 return false;
1e6feb95
VZ
1021 }
1022
23645bfa 1023 return wxStdInputHandler::HandleMouseMove(consumer, event);
1e6feb95
VZ
1024}
1025
61fef19b
VZ
1026bool
1027wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
1028 const wxFocusEvent& WXUNUSED(event))
1e6feb95
VZ
1029{
1030 // slider's appearance changes when it gets/loses focus
a290fa5a 1031 return true;
1e6feb95
VZ
1032}
1033
1034#endif // wxUSE_SLIDER