]> git.saurik.com Git - wxWidgets.git/blob - src/univ/slider.cpp
starting blend modes for Core Graphics
[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 nothing at all, the current value only
26 or the value and the limits - the current approach is just that of the
27 lowest 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 #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)
68 static const wxCoord SLIDER_LABEL_MARGIN = 2;
69
70 // ============================================================================
71 // implementation of wxSlider
72 // ============================================================================
73
74 IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
75
76 BEGIN_EVENT_TABLE(wxSlider, wxControl)
77 EVT_SIZE(wxSlider::OnSize)
78 END_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
89 wxSlider::wxSlider()
90 : m_thumb(this)
91 {
92 Init();
93 }
94
95 wxSlider::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
116 void 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
131 bool 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) )
142 return false;
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
153 return true;
154 }
155
156 // ----------------------------------------------------------------------------
157 // wxSlider range and value
158 // ----------------------------------------------------------------------------
159
160 int wxSlider::GetValue() const
161 {
162 return m_value;
163 }
164
165 int 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
175 bool wxSlider::ChangeValueBy(int inc)
176 {
177 return ChangeValueTo(NormalizeValue(m_value + inc));
178 }
179
180 bool wxSlider::ChangeValueTo(int value)
181 {
182 // check if the value is going to change at all
183 if (value == m_value) return false;
184
185 // this method is protected and we should only call it with normalized
186 // value!
187 wxCHECK_MSG( IsInRange(value), false, _T("invalid slider value") );
188
189 m_value = value;
190
191 Refresh();
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
200 return true;
201 }
202
203 void 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
215 void 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
244 int wxSlider::GetMin() const
245 {
246 return m_min;
247 }
248
249 int wxSlider::GetMax() const
250 {
251 return m_max;
252 }
253
254 // ----------------------------------------------------------------------------
255 // wxSlider line/page/thumb size
256 // ----------------------------------------------------------------------------
257
258 void wxSlider::SetLineSize(int lineSize)
259 {
260 wxCHECK_RET( lineSize >= 0, _T("invalid slider line size") );
261
262 m_lineSize = lineSize;
263 }
264
265 void wxSlider::SetPageSize(int pageSize)
266 {
267 wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );
268
269 m_pageSize = pageSize;
270 }
271
272 int 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
283 int wxSlider::GetPageSize() const
284 {
285 if ( !m_pageSize )
286 {
287 // the default page increment is m_tickFreq
288 wxConstCast(this, wxSlider)->m_pageSize = m_tickFreq;
289 }
290
291 return m_pageSize;
292 }
293
294 void wxSlider::SetThumbLength(int lenPixels)
295 {
296 wxCHECK_RET( lenPixels >= 0, _T("invalid slider thumb size") );
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
308 int wxSlider::GetThumbLength() const
309 {
310 wxSize sz = GetDefaultThumbSize();
311 int len = (IsVert() ? sz.x : sz.y);
312 if (m_thumbSize > len)
313 {
314 return m_thumbSize;
315 }
316 else
317 {
318 return len;
319 }
320
321 }
322
323 // ----------------------------------------------------------------------------
324 // wxSlider ticks
325 // ----------------------------------------------------------------------------
326
327 void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
328 {
329 wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));
330
331 if ( n != m_tickFreq )
332 {
333 m_tickFreq = n;
334
335 Refresh();
336 }
337 }
338
339 // ----------------------------------------------------------------------------
340 // wxSlider geometry
341 // ----------------------------------------------------------------------------
342
343 wxSize 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
361 wxSize wxSlider::DoGetBestClientSize() const
362 {
363 // this dimension is completely arbitrary
364 static const wxCoord SLIDER_WIDTH = 40;
365
366 long style = GetWindowStyle();
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();
388 if (style & wxSL_BOTH)
389 {
390 lenTick = 2 * lenTick;
391 }
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
404 if (style & (wxSL_LEFT|wxSL_RIGHT))
405 {
406 size.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
407 }
408 else if (style & (wxSL_TOP|wxSL_BOTTOM))
409 {
410 size.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
411 }
412 }
413
414 return size;
415 }
416
417 void wxSlider::OnSize(wxSizeEvent& event)
418 {
419 CalcGeometry();
420
421 event.Skip();
422 }
423
424 const 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
434 void 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 */
467 long style = GetWindowStyle();
468
469 // initialize to the full client rect
470 wxRect rectTotal = GetClientRect();
471 m_rectSlider = rectTotal;
472 wxSize sizeThumb = GetThumbSize();
473
474 // Labels reduce the size of the slider rect
475 if ( HasLabels() )
476 {
477 wxSize sizeLabels = CalcLabelSize();
478
479 m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);
480
481 if (style & wxSL_TOP)
482 {
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;
486 }
487 else if (style & wxSL_BOTTOM)
488 {
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 }
493 else if (style & wxSL_LEFT)
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 }
499 else if (style & wxSL_RIGHT)
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;
504 }
505 }
506
507 // calculate ticks too
508 if ( HasTicks() )
509 {
510 wxCoord lenTick = GetRenderer()->GetSliderTickLen();
511
512 // it
513 m_rectTicks = GetShaftRect();
514
515 if ( IsVert() )
516 {
517 if (style & (wxSL_LEFT|wxSL_BOTH))
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 }
525 m_rectTicks.width = lenTick;
526 }
527 else // horizontal
528 {
529 if (style & (wxSL_TOP|wxSL_BOTH))
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 }
537 m_rectTicks.height = lenTick;
538 }
539 }
540
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 );
551 }
552 }
553
554 wxSize wxSlider::GetDefaultThumbSize() const
555 {
556 // Default size has no styles (arrows)
557 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), 0, GetOrientation());
558 }
559
560 wxSize wxSlider::GetThumbSize() const
561 {
562 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), m_thumbSize, GetOrientation());
563 }
564
565 // ----------------------------------------------------------------------------
566 // wxSlider thumb geometry
567 // ----------------------------------------------------------------------------
568
569 wxRect wxSlider::GetShaftRect() const
570 {
571 return GetRenderer()->GetSliderShaftRect(m_rectSlider, m_thumbSize, GetOrientation(), GetWindowStyle());
572 }
573
574 void 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,
598 lenThumb;
599 wxCoord *p;
600
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 {
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 }
631 }
632
633 // calc the label rect
634 if ( HasLabels() && rectLabelOut )
635 {
636 long style = GetWindowStyle();
637 wxRect rectLabel = m_rectLabel;
638
639 // centre the label relatively to the thumb position
640 if (style & (wxSL_TOP|wxSL_BOTTOM))
641 {
642 rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
643 }
644 else if (style & (wxSL_LEFT|wxSL_RIGHT))
645 {
646 rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
647 }
648
649 *rectLabelOut = rectLabel;
650 }
651
652 if ( rectThumbOut )
653
654 *rectThumbOut = rectThumb;
655 }
656
657 // ----------------------------------------------------------------------------
658 // wxSlider drawing
659 // ----------------------------------------------------------------------------
660
661 wxString wxSlider::FormatValue(int value) const
662 {
663 return wxString::Format(_T("%d"), value);
664 }
665
666 void wxSlider::DoDraw(wxControlRenderer *renderer)
667 {
668 wxRenderer *rend = GetRenderer();
669 wxDC& dc = renderer->GetDC();
670 wxRect rectUpdate = GetUpdateClientRect();
671
672 wxOrientation orient = GetOrientation();
673 int flags = GetStateFlags();
674 long style = GetWindowStyle();
675
676 wxSize sz = GetThumbSize();
677 int len = IsVert() ? sz.x : sz.y;
678
679 // first draw the shaft
680 wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
681 if ( rectUpdate.Intersects(rectShaft) )
682 {
683 rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
684 }
685
686 // calculate the thumb position in pixels and draw it
687 wxRect rectThumb, rectLabel;
688 CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
689
690 // then draw the ticks
691 if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
692 {
693 rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
694 m_min, m_max, m_tickFreq, flags, style);
695 }
696
697 // then draw the thumb
698 if ( rectUpdate.Intersects(rectThumb) )
699 {
700 rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
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
707 int align = 0;
708 if (style & wxSL_TOP)
709 {
710 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
711 }
712 else if (style & wxSL_BOTTOM)
713 {
714 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
715 }
716 else if (style & wxSL_LEFT)
717 {
718 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
719 }
720 else if (style & wxSL_RIGHT)
721 {
722 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
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
734 // ----------------------------------------------------------------------------
735 // wxSlider input processing
736 // ----------------------------------------------------------------------------
737
738 bool wxSlider::PerformAction(const wxControlAction& action,
739 long numArg,
740 const wxString& strArg)
741 {
742 if ( action == wxACTION_SLIDER_START )
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 {
756 ChangeValueBy(+GetLineSize());
757 }
758 else if ( action == wxACTION_SLIDER_LINE_DOWN )
759 {
760 ChangeValueBy(-GetLineSize());
761 }
762 else if ( action == wxACTION_SLIDER_PAGE_UP )
763 {
764 ChangeValueBy(+GetPageSize());
765 }
766 else if ( action == wxACTION_SLIDER_PAGE_DOWN )
767 {
768 ChangeValueBy(-GetPageSize());
769 }
770 else if ( action == wxACTION_SLIDER_THUMB_DRAG )
771 {
772 // no special processing for it
773 return true;
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
785 return true;
786 }
787
788 // ----------------------------------------------------------------------------
789 // wxSlider implementation of wxControlWithThumb interface
790 // ----------------------------------------------------------------------------
791
792 wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
793 {
794 wxRect rectShaft = GetShaftRect();
795 wxRect rectThumb;
796 CalcThumbRect(&rectShaft, &rectThumb, NULL);
797
798 // check for possible shaft or thumb hit
799 if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
800 {
801 return wxScrollThumb::Shaft_None;
802 }
803
804 // the position to test and the start and end of the thumb
805 wxCoord x, x1, x2, x3, x4;
806 if (IsVert())
807 {
808 x = pt.y;
809 x1 = rectThumb.GetBottom();
810 x2 = rectShaft.GetBottom();
811 x3 = rectShaft.GetTop();
812 x4 = rectThumb.GetTop();
813 }
814 else
815 { // horz
816 x = pt.x;
817 x1 = rectShaft.GetLeft();
818 x2 = rectThumb.GetLeft();
819 x3 = rectThumb.GetRight();
820 x4 = rectShaft.GetRight();
821 }
822 if ((x1 <= x) && (x < x2))
823 {
824 // or to the left
825 return wxScrollThumb::Shaft_Above;
826 }
827
828 if ((x3 < x) && (x <= x4)) {
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
837 wxCoord wxSlider::ThumbPosToPixel() const
838 {
839 wxRect rectThumb;
840 CalcThumbRect(NULL, &rectThumb, NULL);
841
842 return IsVert() ? rectThumb.y : rectThumb.x;
843 }
844
845 int 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
877 void 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
890 Refresh();
891 }
892 }
893
894 void wxSlider::OnThumbDragStart(int pos)
895 {
896 if (IsVert())
897 {
898 PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
899 }
900 else
901 {
902 PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
903 }
904 }
905
906 void wxSlider::OnThumbDrag(int pos)
907 {
908 if (IsVert())
909 {
910 PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
911 }
912 else
913 {
914 PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
915 }
916 }
917
918 void wxSlider::OnThumbDragEnd(int pos)
919 {
920 if (IsVert())
921 {
922 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
923 }
924 else
925 {
926 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
927 }
928 }
929
930 void wxSlider::OnPageScrollStart()
931 {
932 // we do nothing here
933 }
934
935 bool 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
947 bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
948 const wxKeyEvent& event,
949 bool pressed)
950 {
951 if ( pressed )
952 {
953 int keycode = event.GetKeyCode();
954
955 wxControlAction action;
956 switch ( keycode )
957 {
958 case WXK_HOME:
959 action = wxACTION_SLIDER_END;
960 break;
961
962 case WXK_END:
963 action = wxACTION_SLIDER_START;
964 break;
965
966 case WXK_RIGHT:
967 case WXK_UP:
968 action = wxACTION_SLIDER_LINE_UP;
969 break;
970
971 case WXK_LEFT:
972 case WXK_DOWN:
973 action = wxACTION_SLIDER_LINE_DOWN;
974 break;
975
976 case WXK_PRIOR:
977 case WXK_PAGEUP:
978 action = wxACTION_SLIDER_PAGE_UP;
979 break;
980
981 case WXK_NEXT:
982 case WXK_PAGEDOWN:
983 action = wxACTION_SLIDER_PAGE_DOWN;
984 break;
985 }
986
987 if ( !action.IsEmpty() )
988 {
989 consumer->PerformAction(action);
990
991 return true;
992 }
993 }
994
995 return wxStdInputHandler::HandleKey(consumer, event, pressed);
996 }
997
998 bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
999 const wxMouseEvent& event)
1000 {
1001 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1002
1003 if ( slider->GetThumb().HandleMouse(event) )
1004 {
1005 // processed by the thumb
1006 return false;
1007 }
1008
1009 return wxStdInputHandler::HandleMouse(consumer, event);
1010 }
1011
1012 bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1013 const wxMouseEvent& event)
1014 {
1015 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1016
1017 if ( slider->GetThumb().HandleMouseMove(event) )
1018 {
1019 // processed by the thumb
1020 return false;
1021 }
1022
1023 return wxStdInputHandler::HandleMouseMove(consumer, event);
1024 }
1025
1026 bool
1027 wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
1028 const wxFocusEvent& WXUNUSED(event))
1029 {
1030 // slider's appearance changes when it gets/loses focus
1031 return true;
1032 }
1033
1034 #endif // wxUSE_SLIDER