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