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