]> git.saurik.com Git - wxWidgets.git/blame - src/univ/slider.cpp
Applied [ 1223122 ] [wxMSW] Proper repainting when resizing - take 2
[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
d6922577 25 should be able to select if we show nothing at all, the current value only
1e6feb95 26 or the value and the limits - the current approach is just that of the
d6922577 27 lowest common denominator.
1e6feb95
VZ
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) )
a290fa5a 146 return false;
1e6feb95
VZ
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
a290fa5a 157 return true;
1e6feb95
VZ
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 186 // check if the value is going to change at all
a290fa5a 187 if (value == m_value) return false;
6766e5d1 188
1e6feb95
VZ
189 // this method is protected and we should only call it with normalized
190 // value!
a290fa5a 191 wxCHECK_MSG( IsInRange(value), false, _T("invalid slider value") );
1e6feb95 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
a290fa5a 204 return true;
1e6feb95
VZ
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);
32b13913 316 if (m_thumbSize > len)
6766e5d1
JS
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();
32b13913 392 if (style & wxSL_BOTH)
6766e5d1
JS
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
32b13913 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 }
32b13913 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 }
32b13913 497 else if (style & wxSL_LEFT)
6766e5d1
JS
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 }
32b13913 503 else if (style & wxSL_RIGHT)
6766e5d1
JS
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 {
32b13913 521 if (style & (wxSL_LEFT|wxSL_BOTH))
6766e5d1
JS
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 {
32b13913 533 if (style & (wxSL_TOP|wxSL_BOTH))
6766e5d1
JS
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,
32b13913
WS
602 lenThumb;
603 wxCoord *p;
604
1e6feb95
VZ
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 {
6766e5d1
JS
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 }
1e6feb95
VZ
635 }
636
637 // calc the label rect
638 if ( HasLabels() && rectLabelOut )
639 {
6766e5d1 640 long style = GetWindowStyle();
1e6feb95
VZ
641 wxRect rectLabel = m_rectLabel;
642
643 // centre the label relatively to the thumb position
6766e5d1 644 if (style & (wxSL_TOP|wxSL_BOTTOM))
1e6feb95 645 {
6766e5d1 646 rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
1e6feb95 647 }
6766e5d1 648 else if (style & (wxSL_LEFT|wxSL_RIGHT))
1e6feb95 649 {
6766e5d1 650 rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
1e6feb95
VZ
651 }
652
653 *rectLabelOut = rectLabel;
654 }
655
656 if ( rectThumbOut )
6766e5d1 657
1e6feb95
VZ
658 *rectThumbOut = rectThumb;
659}
660
661// ----------------------------------------------------------------------------
662// wxSlider drawing
663// ----------------------------------------------------------------------------
664
665wxString wxSlider::FormatValue(int value) const
666{
667 return wxString::Format(_T("%d"), value);
668}
669
670void wxSlider::DoDraw(wxControlRenderer *renderer)
671{
672 wxRenderer *rend = GetRenderer();
673 wxDC& dc = renderer->GetDC();
674 wxRect rectUpdate = GetUpdateClientRect();
675
1e6feb95
VZ
676 wxOrientation orient = GetOrientation();
677 int flags = GetStateFlags();
6766e5d1
JS
678 long style = GetWindowStyle();
679
680 wxSize sz = GetThumbSize();
681 int len = IsVert() ? sz.x : sz.y;
1e6feb95
VZ
682
683 // first draw the shaft
6766e5d1 684 wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
1e6feb95
VZ
685 if ( rectUpdate.Intersects(rectShaft) )
686 {
6766e5d1 687 rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
1e6feb95
VZ
688 }
689
690 // calculate the thumb position in pixels and draw it
691 wxRect rectThumb, rectLabel;
692 CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
693
6766e5d1
JS
694 // then draw the ticks
695 if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
1e6feb95 696 {
6766e5d1
JS
697 rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
698 m_min, m_max, m_tickFreq, flags, style);
1e6feb95
VZ
699 }
700
6766e5d1
JS
701 // then draw the thumb
702 if ( rectUpdate.Intersects(rectThumb) )
1e6feb95 703 {
6766e5d1 704 rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
1e6feb95
VZ
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
6766e5d1 711 int align = 0;
32b13913 712 if (style & wxSL_TOP)
1e6feb95 713 {
6766e5d1 714 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
1e6feb95 715 }
32b13913 716 else if (style & wxSL_BOTTOM)
1e6feb95 717 {
6766e5d1
JS
718 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
719 }
32b13913 720 else if (style & wxSL_LEFT)
6766e5d1
JS
721 {
722 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
723 }
32b13913 724 else if (style & wxSL_RIGHT)
6766e5d1
JS
725 {
726 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
1e6feb95
VZ
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
1e6feb95
VZ
738// ----------------------------------------------------------------------------
739// wxSlider input processing
740// ----------------------------------------------------------------------------
741
742bool wxSlider::PerformAction(const wxControlAction& action,
743 long numArg,
744 const wxString& strArg)
745{
6766e5d1 746 if ( action == wxACTION_SLIDER_START )
1e6feb95
VZ
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 {
6766e5d1 760 ChangeValueBy(+GetLineSize());
1e6feb95 761 }
6766e5d1 762 else if ( action == wxACTION_SLIDER_LINE_DOWN )
1e6feb95 763 {
6766e5d1 764 ChangeValueBy(-GetLineSize());
1e6feb95 765 }
6766e5d1 766 else if ( action == wxACTION_SLIDER_PAGE_UP )
1e6feb95 767 {
6766e5d1 768 ChangeValueBy(+GetPageSize());
1e6feb95
VZ
769 }
770 else if ( action == wxACTION_SLIDER_PAGE_DOWN )
771 {
6766e5d1 772 ChangeValueBy(-GetPageSize());
1e6feb95
VZ
773 }
774 else if ( action == wxACTION_SLIDER_THUMB_DRAG )
775 {
776 // no special processing for it
a290fa5a 777 return true;
1e6feb95
VZ
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
a290fa5a 789 return true;
1e6feb95
VZ
790}
791
792// ----------------------------------------------------------------------------
793// wxSlider implementation of wxControlWithThumb interface
794// ----------------------------------------------------------------------------
795
796wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
797{
798 wxRect rectShaft = GetShaftRect();
2b5f62a0
VZ
799 wxRect rectThumb;
800 CalcThumbRect(&rectShaft, &rectThumb, NULL);
801
6766e5d1 802 // check for possible shaft or thumb hit
32b13913 803 if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
1e6feb95
VZ
804 {
805 return wxScrollThumb::Shaft_None;
806 }
807
1e6feb95 808 // the position to test and the start and end of the thumb
6766e5d1 809 wxCoord x, x1, x2, x3, x4;
32b13913 810 if (IsVert())
1e6feb95
VZ
811 {
812 x = pt.y;
6766e5d1
JS
813 x1 = rectThumb.GetBottom();
814 x2 = rectShaft.GetBottom();
815 x3 = rectShaft.GetTop();
816 x4 = rectThumb.GetTop();
1e6feb95 817 }
6766e5d1
JS
818 else
819 { // horz
1e6feb95 820 x = pt.x;
6766e5d1
JS
821 x1 = rectShaft.GetLeft();
822 x2 = rectThumb.GetLeft();
823 x3 = rectThumb.GetRight();
824 x4 = rectShaft.GetRight();
1e6feb95 825 }
32b13913 826 if ((x1 <= x) & (x < x2))
1e6feb95
VZ
827 {
828 // or to the left
829 return wxScrollThumb::Shaft_Above;
830 }
831
6766e5d1 832 if ((x3 < x) & (x <= x4)) {
1e6feb95
VZ
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
841wxCoord wxSlider::ThumbPosToPixel() const
842{
843 wxRect rectThumb;
844 CalcThumbRect(NULL, &rectThumb, NULL);
845
846 return IsVert() ? rectThumb.y : rectThumb.x;
847}
848
849int 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
881void 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
6766e5d1 894 Refresh();
1e6feb95
VZ
895 }
896}
897
898void wxSlider::OnThumbDragStart(int pos)
899{
32b13913 900 if (IsVert())
6766e5d1
JS
901 {
902 PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
903 }
904 else
905 {
906 PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
907 }
1e6feb95
VZ
908}
909
910void wxSlider::OnThumbDrag(int pos)
911{
32b13913 912 if (IsVert())
6766e5d1
JS
913 {
914 PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
915 }
916 else
917 {
918 PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
919 }
1e6feb95
VZ
920}
921
922void wxSlider::OnThumbDragEnd(int pos)
923{
32b13913 924 if (IsVert())
6766e5d1
JS
925 {
926 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
927 }
928 else
929 {
930 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
931 }
1e6feb95
VZ
932}
933
934void wxSlider::OnPageScrollStart()
935{
936 // we do nothing here
937}
938
939bool 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
23645bfa 951bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
952 const wxKeyEvent& event,
953 bool pressed)
954{
6766e5d1 955 if ( pressed )
1e6feb95
VZ
956 {
957 int keycode = event.GetKeyCode();
958
959 wxControlAction action;
960 switch ( keycode )
961 {
962 case WXK_HOME:
6766e5d1 963 action = wxACTION_SLIDER_END;
1e6feb95
VZ
964 break;
965
966 case WXK_END:
6766e5d1 967 action = wxACTION_SLIDER_START;
1e6feb95
VZ
968 break;
969
6766e5d1 970 case WXK_RIGHT:
1e6feb95
VZ
971 case WXK_UP:
972 action = wxACTION_SLIDER_LINE_UP;
973 break;
974
6766e5d1 975 case WXK_LEFT:
1e6feb95
VZ
976 case WXK_DOWN:
977 action = wxACTION_SLIDER_LINE_DOWN;
978 break;
979
980 case WXK_PRIOR:
187c183c 981 case WXK_PAGEUP:
1e6feb95
VZ
982 action = wxACTION_SLIDER_PAGE_UP;
983 break;
984
985 case WXK_NEXT:
187c183c 986 case WXK_PAGEDOWN:
1e6feb95
VZ
987 action = wxACTION_SLIDER_PAGE_DOWN;
988 break;
989 }
990
a290fa5a 991 if ( !action.IsEmpty() )
1e6feb95 992 {
23645bfa 993 consumer->PerformAction(action);
1e6feb95 994
a290fa5a 995 return true;
1e6feb95
VZ
996 }
997 }
998
23645bfa 999 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
1000}
1001
23645bfa 1002bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
1003 const wxMouseEvent& event)
1004{
23645bfa 1005 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1006
1007 if ( slider->GetThumb().HandleMouse(event) )
1008 {
1009 // processed by the thumb
a290fa5a 1010 return false;
1e6feb95
VZ
1011 }
1012
23645bfa 1013 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
1014}
1015
23645bfa 1016bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
1017 const wxMouseEvent& event)
1018{
23645bfa 1019 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1020
1021 if ( slider->GetThumb().HandleMouseMove(event) )
1022 {
1023 // processed by the thumb
a290fa5a 1024 return false;
1e6feb95
VZ
1025 }
1026
23645bfa 1027 return wxStdInputHandler::HandleMouseMove(consumer, event);
1e6feb95
VZ
1028}
1029
61fef19b
VZ
1030bool
1031wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
1032 const wxFocusEvent& WXUNUSED(event))
1e6feb95
VZ
1033{
1034 // slider's appearance changes when it gets/loses focus
a290fa5a 1035 return true;
1e6feb95
VZ
1036}
1037
1038#endif // wxUSE_SLIDER