]> git.saurik.com Git - wxWidgets.git/blame - src/univ/slider.cpp
We need one float argument to perform floating point division.
[wxWidgets.git] / src / univ / slider.cpp
CommitLineData
1e6feb95
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: univ/slider.cpp
3// Purpose: implementation of the universal version of wxSlider
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 09.02.01
7// RCS-ID: $Id$
442b35b5 8// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
65571936 9// Licence: wxWindows licence
1e6feb95
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12/*
13 There is some discrepancy in wxSL_LABELS style handling between wxMSW and
14 wxGTK: the latter handles it natively and shows only the current value of
15 the slider on the side corresponding to wxSL_TOP/BOTTOM/LEFT/RIGHT style
16 given (which can be combined with wxSL_HORIZONTAL/VERTICAL) while wxMSW
17 emulates this somehow and shows the min and max values near the ends of the
18 slider and the current value in a separate static box nearby.
19
20 We currently follow wxGTK except that wxSL_HORIZONTAL slider can only have
21 the label displayed on top or bottom of it and wxSL_VERTICAL - to the left
22 or right.
23
24 What we really need is probably a more fine grain control on labels, i.e. we
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
14f355c2 45#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
a3870b2f 46 #pragma implementation "univslider.h"
1e6feb95
VZ
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)
72static const wxCoord SLIDER_LABEL_MARGIN = 2;
73
74// ============================================================================
75// implementation of wxSlider
76// ============================================================================
77
78IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
79
80BEGIN_EVENT_TABLE(wxSlider, wxControl)
81 EVT_SIZE(wxSlider::OnSize)
82END_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
93wxSlider::wxSlider()
94 : m_thumb(this)
95{
96 Init();
97}
98
99wxSlider::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
120void 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
135bool 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
164int wxSlider::GetValue() const
165{
166 return m_value;
167}
168
169int 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
179bool wxSlider::ChangeValueBy(int inc)
180{
181 return ChangeValueTo(NormalizeValue(m_value + inc));
182}
183
184bool wxSlider::ChangeValueTo(int value)
185{
6766e5d1
JS
186 // check if the value is going to change at all
187 if (value == m_value) return FALSE;
188
1e6feb95
VZ
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
1e6feb95
VZ
193 m_value = value;
194
6766e5d1 195 Refresh();
1e6feb95
VZ
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
207void 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
219void 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
248int wxSlider::GetMin() const
249{
250 return m_min;
251}
252
253int wxSlider::GetMax() const
254{
255 return m_max;
256}
257
258// ----------------------------------------------------------------------------
259// wxSlider line/page/thumb size
260// ----------------------------------------------------------------------------
261
262void wxSlider::SetLineSize(int lineSize)
263{
6766e5d1 264 wxCHECK_RET( lineSize >= 0, _T("invalid slider line size") );
1e6feb95
VZ
265
266 m_lineSize = lineSize;
267}
268
269void wxSlider::SetPageSize(int pageSize)
270{
6766e5d1 271 wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );
1e6feb95
VZ
272
273 m_pageSize = pageSize;
274}
275
276int 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
287int wxSlider::GetPageSize() const
288{
289 if ( !m_pageSize )
290 {
6766e5d1
JS
291 // the default page increment is m_tickFreq
292 wxConstCast(this, wxSlider)->m_pageSize = m_tickFreq;
1e6feb95
VZ
293 }
294
295 return m_pageSize;
296}
297
298void wxSlider::SetThumbLength(int lenPixels)
299{
6766e5d1 300 wxCHECK_RET( lenPixels >= 0, _T("invalid slider thumb size") );
1e6feb95
VZ
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
312int wxSlider::GetThumbLength() const
313{
6766e5d1
JS
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
1e6feb95 321 {
6766e5d1 322 return len;
1e6feb95
VZ
323 }
324
1e6feb95
VZ
325}
326
327// ----------------------------------------------------------------------------
328// wxSlider ticks
329// ----------------------------------------------------------------------------
330
331void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
332{
6766e5d1
JS
333 wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));
334
1e6feb95
VZ
335 if ( n != m_tickFreq )
336 {
337 m_tickFreq = n;
338
339 Refresh();
340 }
341}
342
343// ----------------------------------------------------------------------------
344// wxSlider geometry
345// ----------------------------------------------------------------------------
346
347wxSize 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
365wxSize wxSlider::DoGetBestClientSize() const
366{
367 // this dimension is completely arbitrary
6766e5d1
JS
368 static const wxCoord SLIDER_WIDTH = 40;
369
370 long style = GetWindowStyle();
1e6feb95
VZ
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();
6766e5d1
JS
392 if (style & wxSL_BOTH)
393 {
394 lenTick = 2 * lenTick;
395 }
1e6feb95
VZ
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
6766e5d1
JS
408 if (style & (wxSL_LEFT|wxSL_RIGHT))
409 {
1e6feb95 410 size.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
6766e5d1
JS
411 }
412 else if (style & (wxSL_TOP|wxSL_BOTTOM))
413 {
1e6feb95 414 size.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
6766e5d1 415 }
1e6feb95
VZ
416 }
417
418 return size;
419}
420
421void wxSlider::OnSize(wxSizeEvent& event)
422{
423 CalcGeometry();
424
425 event.Skip();
426}
427
428const 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
438void 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 */
6766e5d1 471 long style = GetWindowStyle();
1e6feb95 472
6766e5d1 473 // initialize to the full client rect
1e6feb95 474 wxRect rectTotal = GetClientRect();
6766e5d1
JS
475 m_rectSlider = rectTotal;
476 wxSize sizeThumb = GetThumbSize();
477
478 // Labels reduce the size of the slider rect
1e6feb95
VZ
479 if ( HasLabels() )
480 {
6766e5d1 481 wxSize sizeLabels = CalcLabelSize();
1e6feb95 482
1e6feb95
VZ
483 m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);
484
6766e5d1 485 if (style & wxSL_TOP)
1e6feb95 486 {
6766e5d1
JS
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;
1e6feb95 490 }
6766e5d1 491 else if (style & wxSL_BOTTOM)
1e6feb95 492 {
6766e5d1
JS
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;
1e6feb95 508 }
1e6feb95
VZ
509 }
510
6766e5d1 511 // calculate ticks too
1e6feb95
VZ
512 if ( HasTicks() )
513 {
514 wxCoord lenTick = GetRenderer()->GetSliderTickLen();
515
1e6feb95
VZ
516 // it
517 m_rectTicks = GetShaftRect();
518
519 if ( IsVert() )
520 {
6766e5d1
JS
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 }
1e6feb95
VZ
529 m_rectTicks.width = lenTick;
530 }
531 else // horizontal
532 {
6766e5d1
JS
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 }
1e6feb95
VZ
541 m_rectTicks.height = lenTick;
542 }
6766e5d1 543 }
1e6feb95 544
6766e5d1
JS
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 );
1e6feb95
VZ
555 }
556}
557
558wxSize wxSlider::GetDefaultThumbSize() const
559{
6766e5d1
JS
560 // Default size has no styles (arrows)
561 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), 0, GetOrientation());
1e6feb95
VZ
562}
563
564wxSize wxSlider::GetThumbSize() const
565{
6766e5d1 566 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), m_thumbSize, GetOrientation());
1e6feb95
VZ
567}
568
569// ----------------------------------------------------------------------------
570// wxSlider thumb geometry
571// ----------------------------------------------------------------------------
572
573wxRect wxSlider::GetShaftRect() const
574{
6766e5d1 575 return GetRenderer()->GetSliderShaftRect(m_rectSlider, m_thumbSize, GetOrientation(), GetWindowStyle());
1e6feb95
VZ
576}
577
578void 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 {
6766e5d1
JS
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 }
1e6feb95
VZ
634 }
635
636 // calc the label rect
637 if ( HasLabels() && rectLabelOut )
638 {
6766e5d1 639 long style = GetWindowStyle();
1e6feb95
VZ
640 wxRect rectLabel = m_rectLabel;
641
642 // centre the label relatively to the thumb position
6766e5d1 643 if (style & (wxSL_TOP|wxSL_BOTTOM))
1e6feb95 644 {
6766e5d1 645 rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
1e6feb95 646 }
6766e5d1 647 else if (style & (wxSL_LEFT|wxSL_RIGHT))
1e6feb95 648 {
6766e5d1 649 rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
1e6feb95
VZ
650 }
651
652 *rectLabelOut = rectLabel;
653 }
654
655 if ( rectThumbOut )
6766e5d1 656
1e6feb95
VZ
657 *rectThumbOut = rectThumb;
658}
659
660// ----------------------------------------------------------------------------
661// wxSlider drawing
662// ----------------------------------------------------------------------------
663
664wxString wxSlider::FormatValue(int value) const
665{
666 return wxString::Format(_T("%d"), value);
667}
668
669void wxSlider::DoDraw(wxControlRenderer *renderer)
670{
671 wxRenderer *rend = GetRenderer();
672 wxDC& dc = renderer->GetDC();
673 wxRect rectUpdate = GetUpdateClientRect();
674
1e6feb95
VZ
675 wxOrientation orient = GetOrientation();
676 int flags = GetStateFlags();
6766e5d1
JS
677 long style = GetWindowStyle();
678
679 wxSize sz = GetThumbSize();
680 int len = IsVert() ? sz.x : sz.y;
1e6feb95
VZ
681
682 // first draw the shaft
6766e5d1 683 wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
1e6feb95
VZ
684 if ( rectUpdate.Intersects(rectShaft) )
685 {
6766e5d1 686 rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
1e6feb95
VZ
687 }
688
689 // calculate the thumb position in pixels and draw it
690 wxRect rectThumb, rectLabel;
691 CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
692
6766e5d1
JS
693 // then draw the ticks
694 if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
1e6feb95 695 {
6766e5d1
JS
696 rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
697 m_min, m_max, m_tickFreq, flags, style);
1e6feb95
VZ
698 }
699
6766e5d1
JS
700 // then draw the thumb
701 if ( rectUpdate.Intersects(rectThumb) )
1e6feb95 702 {
6766e5d1 703 rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
1e6feb95
VZ
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
6766e5d1
JS
710 int align = 0;
711 if (style & wxSL_TOP)
1e6feb95 712 {
6766e5d1 713 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
1e6feb95 714 }
6766e5d1 715 else if (style & wxSL_BOTTOM)
1e6feb95 716 {
6766e5d1
JS
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;
1e6feb95
VZ
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
1e6feb95
VZ
737// ----------------------------------------------------------------------------
738// wxSlider input processing
739// ----------------------------------------------------------------------------
740
741bool wxSlider::PerformAction(const wxControlAction& action,
742 long numArg,
743 const wxString& strArg)
744{
6766e5d1 745 if ( action == wxACTION_SLIDER_START )
1e6feb95
VZ
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 {
6766e5d1 759 ChangeValueBy(+GetLineSize());
1e6feb95 760 }
6766e5d1 761 else if ( action == wxACTION_SLIDER_LINE_DOWN )
1e6feb95 762 {
6766e5d1 763 ChangeValueBy(-GetLineSize());
1e6feb95 764 }
6766e5d1 765 else if ( action == wxACTION_SLIDER_PAGE_UP )
1e6feb95 766 {
6766e5d1 767 ChangeValueBy(+GetPageSize());
1e6feb95
VZ
768 }
769 else if ( action == wxACTION_SLIDER_PAGE_DOWN )
770 {
6766e5d1 771 ChangeValueBy(-GetPageSize());
1e6feb95
VZ
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
795wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
796{
797 wxRect rectShaft = GetShaftRect();
2b5f62a0
VZ
798 wxRect rectThumb;
799 CalcThumbRect(&rectShaft, &rectThumb, NULL);
800
6766e5d1
JS
801 // check for possible shaft or thumb hit
802 if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
1e6feb95
VZ
803 {
804 return wxScrollThumb::Shaft_None;
805 }
806
1e6feb95 807 // the position to test and the start and end of the thumb
6766e5d1
JS
808 wxCoord x, x1, x2, x3, x4;
809 if (IsVert())
1e6feb95
VZ
810 {
811 x = pt.y;
6766e5d1
JS
812 x1 = rectThumb.GetBottom();
813 x2 = rectShaft.GetBottom();
814 x3 = rectShaft.GetTop();
815 x4 = rectThumb.GetTop();
1e6feb95 816 }
6766e5d1
JS
817 else
818 { // horz
1e6feb95 819 x = pt.x;
6766e5d1
JS
820 x1 = rectShaft.GetLeft();
821 x2 = rectThumb.GetLeft();
822 x3 = rectThumb.GetRight();
823 x4 = rectShaft.GetRight();
1e6feb95 824 }
6766e5d1 825 if ((x1 <= x) & (x < x2))
1e6feb95
VZ
826 {
827 // or to the left
828 return wxScrollThumb::Shaft_Above;
829 }
830
6766e5d1 831 if ((x3 < x) & (x <= x4)) {
1e6feb95
VZ
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
840wxCoord wxSlider::ThumbPosToPixel() const
841{
842 wxRect rectThumb;
843 CalcThumbRect(NULL, &rectThumb, NULL);
844
845 return IsVert() ? rectThumb.y : rectThumb.x;
846}
847
848int 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
880void 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
6766e5d1 893 Refresh();
1e6feb95
VZ
894 }
895}
896
897void wxSlider::OnThumbDragStart(int pos)
898{
6766e5d1
JS
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 }
1e6feb95
VZ
907}
908
909void wxSlider::OnThumbDrag(int pos)
910{
6766e5d1
JS
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 }
1e6feb95
VZ
919}
920
921void wxSlider::OnThumbDragEnd(int pos)
922{
6766e5d1
JS
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 }
1e6feb95
VZ
931}
932
933void wxSlider::OnPageScrollStart()
934{
935 // we do nothing here
936}
937
938bool 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
23645bfa 950bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
951 const wxKeyEvent& event,
952 bool pressed)
953{
6766e5d1 954 if ( pressed )
1e6feb95
VZ
955 {
956 int keycode = event.GetKeyCode();
957
958 wxControlAction action;
959 switch ( keycode )
960 {
961 case WXK_HOME:
6766e5d1 962 action = wxACTION_SLIDER_END;
1e6feb95
VZ
963 break;
964
965 case WXK_END:
6766e5d1 966 action = wxACTION_SLIDER_START;
1e6feb95
VZ
967 break;
968
6766e5d1 969 case WXK_RIGHT:
1e6feb95
VZ
970 case WXK_UP:
971 action = wxACTION_SLIDER_LINE_UP;
972 break;
973
6766e5d1 974 case WXK_LEFT:
1e6feb95
VZ
975 case WXK_DOWN:
976 action = wxACTION_SLIDER_LINE_DOWN;
977 break;
978
979 case WXK_PRIOR:
187c183c 980 case WXK_PAGEUP:
1e6feb95
VZ
981 action = wxACTION_SLIDER_PAGE_UP;
982 break;
983
984 case WXK_NEXT:
187c183c 985 case WXK_PAGEDOWN:
1e6feb95
VZ
986 action = wxACTION_SLIDER_PAGE_DOWN;
987 break;
988 }
989
990 if ( !!action )
991 {
23645bfa 992 consumer->PerformAction(action);
1e6feb95
VZ
993
994 return TRUE;
995 }
996 }
997
23645bfa 998 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
999}
1000
23645bfa 1001bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
1002 const wxMouseEvent& event)
1003{
23645bfa 1004 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1005
1006 if ( slider->GetThumb().HandleMouse(event) )
1007 {
1008 // processed by the thumb
1009 return FALSE;
1010 }
1011
23645bfa 1012 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
1013}
1014
23645bfa 1015bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
1016 const wxMouseEvent& event)
1017{
23645bfa 1018 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1019
1020 if ( slider->GetThumb().HandleMouseMove(event) )
1021 {
1022 // processed by the thumb
1023 return FALSE;
1024 }
1025
23645bfa 1026 return wxStdInputHandler::HandleMouseMove(consumer, event);
1e6feb95
VZ
1027}
1028
61fef19b
VZ
1029bool
1030wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
1031 const wxFocusEvent& WXUNUSED(event))
1e6feb95
VZ
1032{
1033 // slider's appearance changes when it gets/loses focus
1034 return TRUE;
1035}
1036
1037#endif // wxUSE_SLIDER