]> git.saurik.com Git - wxWidgets.git/blob - src/univ/slider.cpp
submenus have to work in these as well
[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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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 wxCoord *p;
604
605 wxRect rectThumb(rectShaft.GetPosition(), GetThumbSize());
606 if ( isVertical )
607 {
608 rectThumb.x += (rectShaft.width - rectThumb.width) / 2;
609
610 lenThumb = rectThumb.height;
611 lenShaft = rectShaft.height;
612 p = &rectThumb.y;
613 }
614 else // horz
615 {
616 rectThumb.y += (rectShaft.height - rectThumb.height) / 2;
617
618 lenThumb = rectThumb.width;
619 lenShaft = rectShaft.width;
620 p = &rectThumb.x;
621 }
622
623 // the thumb must always be entirely inside the shaft limits, so the max
624 // position is not at lenShaft but at lenShaft - thumbSize
625 if ( m_max != m_min )
626 {
627 if ( isVertical )
628 {
629 *p += ((lenShaft - lenThumb)*(m_max - value))/(m_max - m_min);
630 }
631 else
632 { // horz
633 *p += ((lenShaft - lenThumb)*(value - m_min))/(m_max - m_min);
634 }
635 }
636
637 // calc the label rect
638 if ( HasLabels() && rectLabelOut )
639 {
640 long style = GetWindowStyle();
641 wxRect rectLabel = m_rectLabel;
642
643 // centre the label relatively to the thumb position
644 if (style & (wxSL_TOP|wxSL_BOTTOM))
645 {
646 rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
647 }
648 else if (style & (wxSL_LEFT|wxSL_RIGHT))
649 {
650 rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
651 }
652
653 *rectLabelOut = rectLabel;
654 }
655
656 if ( rectThumbOut )
657
658 *rectThumbOut = rectThumb;
659 }
660
661 // ----------------------------------------------------------------------------
662 // wxSlider drawing
663 // ----------------------------------------------------------------------------
664
665 wxString wxSlider::FormatValue(int value) const
666 {
667 return wxString::Format(_T("%d"), value);
668 }
669
670 void wxSlider::DoDraw(wxControlRenderer *renderer)
671 {
672 wxRenderer *rend = GetRenderer();
673 wxDC& dc = renderer->GetDC();
674 wxRect rectUpdate = GetUpdateClientRect();
675
676 wxOrientation orient = GetOrientation();
677 int flags = GetStateFlags();
678 long style = GetWindowStyle();
679
680 wxSize sz = GetThumbSize();
681 int len = IsVert() ? sz.x : sz.y;
682
683 // first draw the shaft
684 wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
685 if ( rectUpdate.Intersects(rectShaft) )
686 {
687 rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
688 }
689
690 // calculate the thumb position in pixels and draw it
691 wxRect rectThumb, rectLabel;
692 CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
693
694 // then draw the ticks
695 if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
696 {
697 rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
698 m_min, m_max, m_tickFreq, flags, style);
699 }
700
701 // then draw the thumb
702 if ( rectUpdate.Intersects(rectThumb) )
703 {
704 rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
705 }
706
707 // finally, draw the label near the thumb
708 if ( HasLabels() && rectUpdate.Intersects(rectLabel) )
709 {
710 // align it to be close to the shaft
711 int align = 0;
712 if (style & wxSL_TOP)
713 {
714 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
715 }
716 else if (style & wxSL_BOTTOM)
717 {
718 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
719 }
720 else if (style & wxSL_LEFT)
721 {
722 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
723 }
724 else if (style & wxSL_RIGHT)
725 {
726 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
727 }
728
729 dc.SetFont(GetFont());
730 dc.SetTextForeground(GetForegroundColour());
731
732 // the slider label is never drawn focused
733 rend->DrawLabel(dc, FormatValue(m_value), rectLabel,
734 flags & ~wxCONTROL_FOCUSED, align);
735 }
736 }
737
738 // ----------------------------------------------------------------------------
739 // wxSlider input processing
740 // ----------------------------------------------------------------------------
741
742 bool wxSlider::PerformAction(const wxControlAction& action,
743 long numArg,
744 const wxString& strArg)
745 {
746 if ( action == wxACTION_SLIDER_START )
747 {
748 ChangeValueTo(m_min);
749 }
750 else if ( action == wxACTION_SLIDER_END )
751 {
752 ChangeValueTo(m_max);
753 }
754 else if ( action == wxACTION_SLIDER_PAGE_CHANGE )
755 {
756 ChangeValueBy(numArg * GetPageSize());
757 }
758 else if ( action == wxACTION_SLIDER_LINE_UP )
759 {
760 ChangeValueBy(+GetLineSize());
761 }
762 else if ( action == wxACTION_SLIDER_LINE_DOWN )
763 {
764 ChangeValueBy(-GetLineSize());
765 }
766 else if ( action == wxACTION_SLIDER_PAGE_UP )
767 {
768 ChangeValueBy(+GetPageSize());
769 }
770 else if ( action == wxACTION_SLIDER_PAGE_DOWN )
771 {
772 ChangeValueBy(-GetPageSize());
773 }
774 else if ( action == wxACTION_SLIDER_THUMB_DRAG )
775 {
776 // no special processing for it
777 return true;
778 }
779 else if ( action == wxACTION_SLIDER_THUMB_MOVE ||
780 action == wxACTION_SLIDER_THUMB_RELEASE )
781 {
782 ChangeValueTo((int)numArg);
783 }
784 else
785 {
786 return wxControl::PerformAction(action, numArg, strArg);
787 }
788
789 return true;
790 }
791
792 // ----------------------------------------------------------------------------
793 // wxSlider implementation of wxControlWithThumb interface
794 // ----------------------------------------------------------------------------
795
796 wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
797 {
798 wxRect rectShaft = GetShaftRect();
799 wxRect rectThumb;
800 CalcThumbRect(&rectShaft, &rectThumb, NULL);
801
802 // check for possible shaft or thumb hit
803 if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
804 {
805 return wxScrollThumb::Shaft_None;
806 }
807
808 // the position to test and the start and end of the thumb
809 wxCoord x, x1, x2, x3, x4;
810 if (IsVert())
811 {
812 x = pt.y;
813 x1 = rectThumb.GetBottom();
814 x2 = rectShaft.GetBottom();
815 x3 = rectShaft.GetTop();
816 x4 = rectThumb.GetTop();
817 }
818 else
819 { // horz
820 x = pt.x;
821 x1 = rectShaft.GetLeft();
822 x2 = rectThumb.GetLeft();
823 x3 = rectThumb.GetRight();
824 x4 = rectShaft.GetRight();
825 }
826 if ((x1 <= x) & (x < x2))
827 {
828 // or to the left
829 return wxScrollThumb::Shaft_Above;
830 }
831
832 if ((x3 < x) & (x <= x4)) {
833 // or to the right
834 return wxScrollThumb::Shaft_Below;
835 }
836
837 // where else can it be?
838 return wxScrollThumb::Shaft_Thumb;
839 }
840
841 wxCoord wxSlider::ThumbPosToPixel() const
842 {
843 wxRect rectThumb;
844 CalcThumbRect(NULL, &rectThumb, NULL);
845
846 return IsVert() ? rectThumb.y : rectThumb.x;
847 }
848
849 int wxSlider::PixelToThumbPos(wxCoord x) const
850 {
851 wxRect rectShaft = GetShaftRect();
852 wxSize sizeThumb = GetThumbSize();
853
854 wxCoord x0, len;
855 if ( IsVert() )
856 {
857 x0 = rectShaft.y;
858 len = rectShaft.height - sizeThumb.y;
859 }
860 else // horz
861 {
862 x0 = rectShaft.x;
863 len = rectShaft.width - sizeThumb.x;
864 }
865
866 int pos = m_min;
867 if ( len > 0 )
868 {
869 if ( x > x0 )
870 {
871 pos += ((x - x0) * (m_max - m_min)) / len;
872 if ( pos > m_max )
873 pos = m_max;
874 }
875 //else: x <= x0, leave pos = min
876 }
877
878 return pos;
879 }
880
881 void wxSlider::SetShaftPartState(wxScrollThumb::Shaft shaftPart,
882 int flag,
883 bool set)
884 {
885 // for now we ignore the flags for the shaft as no renderer uses them
886 // anyhow
887 if ( shaftPart == wxScrollThumb::Shaft_Thumb )
888 {
889 if ( set )
890 m_thumbFlags |= flag;
891 else
892 m_thumbFlags &= ~flag;
893
894 Refresh();
895 }
896 }
897
898 void wxSlider::OnThumbDragStart(int pos)
899 {
900 if (IsVert())
901 {
902 PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
903 }
904 else
905 {
906 PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
907 }
908 }
909
910 void wxSlider::OnThumbDrag(int pos)
911 {
912 if (IsVert())
913 {
914 PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
915 }
916 else
917 {
918 PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
919 }
920 }
921
922 void wxSlider::OnThumbDragEnd(int pos)
923 {
924 if (IsVert())
925 {
926 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
927 }
928 else
929 {
930 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
931 }
932 }
933
934 void wxSlider::OnPageScrollStart()
935 {
936 // we do nothing here
937 }
938
939 bool wxSlider::OnPageScroll(int pageInc)
940 {
941 int value = GetValue();
942 PerformAction(wxACTION_SLIDER_PAGE_CHANGE, pageInc);
943
944 return GetValue() != value;
945 }
946
947 // ----------------------------------------------------------------------------
948 // wxStdSliderButtonInputHandler
949 // ----------------------------------------------------------------------------
950
951 bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
952 const wxKeyEvent& event,
953 bool pressed)
954 {
955 if ( pressed )
956 {
957 int keycode = event.GetKeyCode();
958
959 wxControlAction action;
960 switch ( keycode )
961 {
962 case WXK_HOME:
963 action = wxACTION_SLIDER_END;
964 break;
965
966 case WXK_END:
967 action = wxACTION_SLIDER_START;
968 break;
969
970 case WXK_RIGHT:
971 case WXK_UP:
972 action = wxACTION_SLIDER_LINE_UP;
973 break;
974
975 case WXK_LEFT:
976 case WXK_DOWN:
977 action = wxACTION_SLIDER_LINE_DOWN;
978 break;
979
980 case WXK_PRIOR:
981 case WXK_PAGEUP:
982 action = wxACTION_SLIDER_PAGE_UP;
983 break;
984
985 case WXK_NEXT:
986 case WXK_PAGEDOWN:
987 action = wxACTION_SLIDER_PAGE_DOWN;
988 break;
989 }
990
991 if ( !action.IsEmpty() )
992 {
993 consumer->PerformAction(action);
994
995 return true;
996 }
997 }
998
999 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1000 }
1001
1002 bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
1003 const wxMouseEvent& event)
1004 {
1005 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1006
1007 if ( slider->GetThumb().HandleMouse(event) )
1008 {
1009 // processed by the thumb
1010 return false;
1011 }
1012
1013 return wxStdInputHandler::HandleMouse(consumer, event);
1014 }
1015
1016 bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1017 const wxMouseEvent& event)
1018 {
1019 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1020
1021 if ( slider->GetThumb().HandleMouseMove(event) )
1022 {
1023 // processed by the thumb
1024 return false;
1025 }
1026
1027 return wxStdInputHandler::HandleMouseMove(consumer, event);
1028 }
1029
1030 bool
1031 wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
1032 const wxFocusEvent& WXUNUSED(event))
1033 {
1034 // slider's appearance changes when it gets/loses focus
1035 return true;
1036 }
1037
1038 #endif // wxUSE_SLIDER