]> git.saurik.com Git - wxWidgets.git/blame - src/univ/slider.cpp
renamed wxRect::Inside() to wxRect::Contains(), wxRect::Inside(wxRect) is too confusing
[wxWidgets.git] / src / univ / slider.cpp
CommitLineData
1e6feb95 1///////////////////////////////////////////////////////////////////////////////
faa94f3e 2// Name: src/univ/slider.cpp
1e6feb95
VZ
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
1e6feb95
VZ
45#include "wx/wxprec.h"
46
47#ifdef __BORLANDC__
48 #pragma hdrstop
49#endif
50
f4da9a94 51#if wxUSE_SLIDER
1e6feb95
VZ
52
53#include "wx/slider.h"
54
f4da9a94
WS
55#ifndef WX_PRECOMP
56 #include "wx/dc.h"
57#endif
1e6feb95
VZ
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)
68static const wxCoord SLIDER_LABEL_MARGIN = 2;
69
70// ============================================================================
71// implementation of wxSlider
72// ============================================================================
73
74IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
75
76BEGIN_EVENT_TABLE(wxSlider, wxControl)
77 EVT_SIZE(wxSlider::OnSize)
78END_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
89wxSlider::wxSlider()
90 : m_thumb(this)
91{
92 Init();
93}
94
95wxSlider::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
116void 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
131bool 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) )
a290fa5a 142 return false;
1e6feb95
VZ
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
a290fa5a 153 return true;
1e6feb95
VZ
154}
155
156// ----------------------------------------------------------------------------
157// wxSlider range and value
158// ----------------------------------------------------------------------------
159
160int wxSlider::GetValue() const
161{
162 return m_value;
163}
164
165int 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
175bool wxSlider::ChangeValueBy(int inc)
176{
177 return ChangeValueTo(NormalizeValue(m_value + inc));
178}
179
180bool wxSlider::ChangeValueTo(int value)
181{
6766e5d1 182 // check if the value is going to change at all
c4edb7ac
VZ
183 if (value == m_value)
184 return false;
6766e5d1 185
1e6feb95
VZ
186 // this method is protected and we should only call it with normalized
187 // value!
a290fa5a 188 wxCHECK_MSG( IsInRange(value), false, _T("invalid slider value") );
1e6feb95 189
1e6feb95
VZ
190 m_value = value;
191
6766e5d1 192 Refresh();
1e6feb95 193
c4edb7ac
VZ
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
1e6feb95
VZ
200 wxCommandEvent event(wxEVT_COMMAND_SLIDER_UPDATED, GetId());
201 event.SetInt(m_value);
202 event.SetEventObject(this);
1e6feb95
VZ
203 (void)GetEventHandler()->ProcessEvent(event);
204
a290fa5a 205 return true;
1e6feb95
VZ
206}
207
208void 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
220void 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
249int wxSlider::GetMin() const
250{
251 return m_min;
252}
253
254int wxSlider::GetMax() const
255{
256 return m_max;
257}
258
259// ----------------------------------------------------------------------------
260// wxSlider line/page/thumb size
261// ----------------------------------------------------------------------------
262
263void wxSlider::SetLineSize(int lineSize)
264{
6766e5d1 265 wxCHECK_RET( lineSize >= 0, _T("invalid slider line size") );
1e6feb95
VZ
266
267 m_lineSize = lineSize;
268}
269
270void wxSlider::SetPageSize(int pageSize)
271{
6766e5d1 272 wxCHECK_RET( pageSize >= 0, _T("invalid slider page size") );
1e6feb95
VZ
273
274 m_pageSize = pageSize;
275}
276
277int 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
288int wxSlider::GetPageSize() const
289{
290 if ( !m_pageSize )
291 {
6766e5d1
JS
292 // the default page increment is m_tickFreq
293 wxConstCast(this, wxSlider)->m_pageSize = m_tickFreq;
1e6feb95
VZ
294 }
295
296 return m_pageSize;
297}
298
299void wxSlider::SetThumbLength(int lenPixels)
300{
6766e5d1 301 wxCHECK_RET( lenPixels >= 0, _T("invalid slider thumb size") );
1e6feb95
VZ
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
313int wxSlider::GetThumbLength() const
314{
6766e5d1
JS
315 wxSize sz = GetDefaultThumbSize();
316 int len = (IsVert() ? sz.x : sz.y);
32b13913 317 if (m_thumbSize > len)
6766e5d1
JS
318 {
319 return m_thumbSize;
320 }
321 else
1e6feb95 322 {
6766e5d1 323 return len;
1e6feb95
VZ
324 }
325
1e6feb95
VZ
326}
327
328// ----------------------------------------------------------------------------
329// wxSlider ticks
330// ----------------------------------------------------------------------------
331
332void wxSlider::SetTickFreq(int n, int WXUNUSED(dummy))
333{
6766e5d1
JS
334 wxCHECK_RET (n > 0, _T("invalid slider tick frequency"));
335
1e6feb95
VZ
336 if ( n != m_tickFreq )
337 {
338 m_tickFreq = n;
339
340 Refresh();
341 }
342}
343
344// ----------------------------------------------------------------------------
345// wxSlider geometry
346// ----------------------------------------------------------------------------
347
348wxSize 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
366wxSize wxSlider::DoGetBestClientSize() const
367{
368 // this dimension is completely arbitrary
6766e5d1
JS
369 static const wxCoord SLIDER_WIDTH = 40;
370
371 long style = GetWindowStyle();
1e6feb95
VZ
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();
32b13913 393 if (style & wxSL_BOTH)
6766e5d1
JS
394 {
395 lenTick = 2 * lenTick;
396 }
1e6feb95
VZ
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
6766e5d1
JS
409 if (style & (wxSL_LEFT|wxSL_RIGHT))
410 {
1e6feb95 411 size.x += sizeLabels.x + SLIDER_LABEL_MARGIN;
6766e5d1
JS
412 }
413 else if (style & (wxSL_TOP|wxSL_BOTTOM))
414 {
1e6feb95 415 size.y += sizeLabels.y + SLIDER_LABEL_MARGIN;
6766e5d1 416 }
1e6feb95
VZ
417 }
418
419 return size;
420}
421
422void wxSlider::OnSize(wxSizeEvent& event)
423{
424 CalcGeometry();
425
426 event.Skip();
427}
428
429const 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
439void 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 */
6766e5d1 472 long style = GetWindowStyle();
1e6feb95 473
6766e5d1 474 // initialize to the full client rect
1e6feb95 475 wxRect rectTotal = GetClientRect();
6766e5d1
JS
476 m_rectSlider = rectTotal;
477 wxSize sizeThumb = GetThumbSize();
478
479 // Labels reduce the size of the slider rect
1e6feb95
VZ
480 if ( HasLabels() )
481 {
6766e5d1 482 wxSize sizeLabels = CalcLabelSize();
1e6feb95 483
1e6feb95
VZ
484 m_rectLabel = wxRect(rectTotal.GetPosition(), sizeLabels);
485
32b13913 486 if (style & wxSL_TOP)
1e6feb95 487 {
6766e5d1
JS
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;
1e6feb95 491 }
32b13913 492 else if (style & wxSL_BOTTOM)
1e6feb95 493 {
6766e5d1
JS
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 }
32b13913 498 else if (style & wxSL_LEFT)
6766e5d1
JS
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 }
32b13913 504 else if (style & wxSL_RIGHT)
6766e5d1
JS
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;
1e6feb95 509 }
1e6feb95
VZ
510 }
511
6766e5d1 512 // calculate ticks too
1e6feb95
VZ
513 if ( HasTicks() )
514 {
515 wxCoord lenTick = GetRenderer()->GetSliderTickLen();
516
1e6feb95
VZ
517 // it
518 m_rectTicks = GetShaftRect();
519
520 if ( IsVert() )
521 {
32b13913 522 if (style & (wxSL_LEFT|wxSL_BOTH))
6766e5d1
JS
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 }
1e6feb95
VZ
530 m_rectTicks.width = lenTick;
531 }
532 else // horizontal
533 {
32b13913 534 if (style & (wxSL_TOP|wxSL_BOTH))
6766e5d1
JS
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 }
1e6feb95
VZ
542 m_rectTicks.height = lenTick;
543 }
6766e5d1 544 }
1e6feb95 545
6766e5d1
JS
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 );
1e6feb95
VZ
556 }
557}
558
559wxSize wxSlider::GetDefaultThumbSize() const
560{
6766e5d1
JS
561 // Default size has no styles (arrows)
562 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), 0, GetOrientation());
1e6feb95
VZ
563}
564
565wxSize wxSlider::GetThumbSize() const
566{
6766e5d1 567 return GetRenderer()->GetSliderThumbSize(GetSliderRect(), m_thumbSize, GetOrientation());
1e6feb95
VZ
568}
569
570// ----------------------------------------------------------------------------
571// wxSlider thumb geometry
572// ----------------------------------------------------------------------------
573
574wxRect wxSlider::GetShaftRect() const
575{
6766e5d1 576 return GetRenderer()->GetSliderShaftRect(m_rectSlider, m_thumbSize, GetOrientation(), GetWindowStyle());
1e6feb95
VZ
577}
578
579void 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,
32b13913
WS
603 lenThumb;
604 wxCoord *p;
605
1e6feb95
VZ
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 {
6766e5d1
JS
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 }
1e6feb95
VZ
636 }
637
638 // calc the label rect
639 if ( HasLabels() && rectLabelOut )
640 {
6766e5d1 641 long style = GetWindowStyle();
1e6feb95
VZ
642 wxRect rectLabel = m_rectLabel;
643
644 // centre the label relatively to the thumb position
6766e5d1 645 if (style & (wxSL_TOP|wxSL_BOTTOM))
1e6feb95 646 {
6766e5d1 647 rectLabel.x = rectThumb.x + (rectThumb.width - m_rectLabel.width)/2;
1e6feb95 648 }
6766e5d1 649 else if (style & (wxSL_LEFT|wxSL_RIGHT))
1e6feb95 650 {
6766e5d1 651 rectLabel.y = rectThumb.y + (rectThumb.height - m_rectLabel.height)/2;
1e6feb95
VZ
652 }
653
654 *rectLabelOut = rectLabel;
655 }
656
657 if ( rectThumbOut )
6766e5d1 658
1e6feb95
VZ
659 *rectThumbOut = rectThumb;
660}
661
662// ----------------------------------------------------------------------------
663// wxSlider drawing
664// ----------------------------------------------------------------------------
665
666wxString wxSlider::FormatValue(int value) const
667{
668 return wxString::Format(_T("%d"), value);
669}
670
671void wxSlider::DoDraw(wxControlRenderer *renderer)
672{
673 wxRenderer *rend = GetRenderer();
674 wxDC& dc = renderer->GetDC();
675 wxRect rectUpdate = GetUpdateClientRect();
676
1e6feb95
VZ
677 wxOrientation orient = GetOrientation();
678 int flags = GetStateFlags();
6766e5d1
JS
679 long style = GetWindowStyle();
680
681 wxSize sz = GetThumbSize();
682 int len = IsVert() ? sz.x : sz.y;
1e6feb95
VZ
683
684 // first draw the shaft
6766e5d1 685 wxRect rectShaft = rend->GetSliderShaftRect(m_rectSlider, len, orient, style);
1e6feb95
VZ
686 if ( rectUpdate.Intersects(rectShaft) )
687 {
6766e5d1 688 rend->DrawSliderShaft(dc, m_rectSlider, len, orient, flags, style);
1e6feb95
VZ
689 }
690
691 // calculate the thumb position in pixels and draw it
692 wxRect rectThumb, rectLabel;
693 CalcThumbRect(&rectShaft, &rectThumb, &rectLabel);
694
6766e5d1
JS
695 // then draw the ticks
696 if ( HasTicks() && rectUpdate.Intersects(m_rectTicks) )
1e6feb95 697 {
6766e5d1
JS
698 rend->DrawSliderTicks(dc, m_rectSlider, len, orient,
699 m_min, m_max, m_tickFreq, flags, style);
1e6feb95
VZ
700 }
701
6766e5d1
JS
702 // then draw the thumb
703 if ( rectUpdate.Intersects(rectThumb) )
1e6feb95 704 {
6766e5d1 705 rend->DrawSliderThumb(dc, rectThumb, orient, flags | m_thumbFlags, style);
1e6feb95
VZ
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
6766e5d1 712 int align = 0;
32b13913 713 if (style & wxSL_TOP)
1e6feb95 714 {
6766e5d1 715 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_TOP;
1e6feb95 716 }
32b13913 717 else if (style & wxSL_BOTTOM)
1e6feb95 718 {
6766e5d1
JS
719 align = wxALIGN_CENTRE_HORIZONTAL|wxALIGN_BOTTOM;
720 }
32b13913 721 else if (style & wxSL_LEFT)
6766e5d1
JS
722 {
723 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_LEFT;
724 }
32b13913 725 else if (style & wxSL_RIGHT)
6766e5d1
JS
726 {
727 align = wxALIGN_CENTRE_VERTICAL|wxALIGN_RIGHT;
1e6feb95
VZ
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
1e6feb95
VZ
739// ----------------------------------------------------------------------------
740// wxSlider input processing
741// ----------------------------------------------------------------------------
742
743bool wxSlider::PerformAction(const wxControlAction& action,
744 long numArg,
745 const wxString& strArg)
746{
c4edb7ac
VZ
747 wxEventType scrollEvent = wxEVT_NULL;
748 int value;
749 bool valueChanged = true;
750
88d2e567 751 if ( action == wxACTION_SLIDER_START )
1e6feb95 752 {
c4edb7ac
VZ
753 scrollEvent = wxEVT_SCROLL_TOP;
754 value = m_min;
1e6feb95
VZ
755 }
756 else if ( action == wxACTION_SLIDER_END )
757 {
c4edb7ac
VZ
758 scrollEvent = wxEVT_SCROLL_BOTTOM;
759 value = m_max;
1e6feb95
VZ
760 }
761 else if ( action == wxACTION_SLIDER_PAGE_CHANGE )
762 {
c4edb7ac 763 value = NormalizeValue(m_value + numArg * GetPageSize());
1e6feb95
VZ
764 }
765 else if ( action == wxACTION_SLIDER_LINE_UP )
766 {
c4edb7ac
VZ
767 scrollEvent = wxEVT_SCROLL_LINEUP;
768 value = NormalizeValue(m_value + +GetLineSize());
1e6feb95 769 }
6766e5d1 770 else if ( action == wxACTION_SLIDER_LINE_DOWN )
1e6feb95 771 {
c4edb7ac
VZ
772 scrollEvent = wxEVT_SCROLL_LINEDOWN;
773 value = NormalizeValue(m_value + -GetLineSize());
1e6feb95 774 }
6766e5d1 775 else if ( action == wxACTION_SLIDER_PAGE_UP )
1e6feb95 776 {
c4edb7ac
VZ
777 scrollEvent = wxEVT_SCROLL_PAGEUP;
778 value = NormalizeValue(m_value + +GetPageSize());
1e6feb95
VZ
779 }
780 else if ( action == wxACTION_SLIDER_PAGE_DOWN )
781 {
c4edb7ac
VZ
782 scrollEvent = wxEVT_SCROLL_PAGEDOWN;
783 value = NormalizeValue(m_value + -GetPageSize());
1e6feb95 784 }
c4edb7ac
VZ
785 else if ( action == wxACTION_SLIDER_THUMB_DRAG ||
786 action == wxACTION_SLIDER_THUMB_MOVE )
1e6feb95 787 {
c4edb7ac
VZ
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();
1e6feb95 796 }
c4edb7ac 797 else if ( action == wxACTION_SLIDER_THUMB_RELEASE )
1e6feb95 798 {
c4edb7ac
VZ
799 scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
800 value = (int)numArg;
1e6feb95
VZ
801 }
802 else
803 {
804 return wxControl::PerformAction(action, numArg, strArg);
805 }
806
c4edb7ac
VZ
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
a290fa5a 821 return true;
1e6feb95
VZ
822}
823
824// ----------------------------------------------------------------------------
825// wxSlider implementation of wxControlWithThumb interface
826// ----------------------------------------------------------------------------
827
828wxScrollThumb::Shaft wxSlider::HitTest(const wxPoint& pt) const
829{
830 wxRect rectShaft = GetShaftRect();
2b5f62a0
VZ
831 wxRect rectThumb;
832 CalcThumbRect(&rectShaft, &rectThumb, NULL);
833
6766e5d1 834 // check for possible shaft or thumb hit
32b13913 835 if (!rectShaft.Inside(pt) && !rectThumb.Inside(pt))
1e6feb95
VZ
836 {
837 return wxScrollThumb::Shaft_None;
838 }
839
1e6feb95 840 // the position to test and the start and end of the thumb
6766e5d1 841 wxCoord x, x1, x2, x3, x4;
32b13913 842 if (IsVert())
1e6feb95
VZ
843 {
844 x = pt.y;
6766e5d1
JS
845 x1 = rectThumb.GetBottom();
846 x2 = rectShaft.GetBottom();
847 x3 = rectShaft.GetTop();
848 x4 = rectThumb.GetTop();
1e6feb95 849 }
6766e5d1
JS
850 else
851 { // horz
1e6feb95 852 x = pt.x;
6766e5d1
JS
853 x1 = rectShaft.GetLeft();
854 x2 = rectThumb.GetLeft();
855 x3 = rectThumb.GetRight();
856 x4 = rectShaft.GetRight();
1e6feb95 857 }
88d2e567 858 if ((x1 <= x) && (x < x2))
1e6feb95
VZ
859 {
860 // or to the left
861 return wxScrollThumb::Shaft_Above;
862 }
863
88d2e567 864 if ((x3 < x) && (x <= x4)) {
1e6feb95
VZ
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
873wxCoord wxSlider::ThumbPosToPixel() const
874{
875 wxRect rectThumb;
876 CalcThumbRect(NULL, &rectThumb, NULL);
877
878 return IsVert() ? rectThumb.y : rectThumb.x;
879}
880
881int 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
913void 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
6766e5d1 926 Refresh();
1e6feb95
VZ
927 }
928}
929
930void wxSlider::OnThumbDragStart(int pos)
931{
32b13913 932 if (IsVert())
6766e5d1
JS
933 {
934 PerformAction(wxACTION_SLIDER_THUMB_DRAG, m_max - pos);
935 }
936 else
937 {
938 PerformAction(wxACTION_SLIDER_THUMB_DRAG, pos);
939 }
1e6feb95
VZ
940}
941
942void wxSlider::OnThumbDrag(int pos)
943{
32b13913 944 if (IsVert())
6766e5d1
JS
945 {
946 PerformAction(wxACTION_SLIDER_THUMB_MOVE, m_max - pos);
947 }
948 else
949 {
950 PerformAction(wxACTION_SLIDER_THUMB_MOVE, pos);
951 }
1e6feb95
VZ
952}
953
954void wxSlider::OnThumbDragEnd(int pos)
955{
32b13913 956 if (IsVert())
6766e5d1
JS
957 {
958 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, m_max - pos);
959 }
960 else
961 {
962 PerformAction(wxACTION_SLIDER_THUMB_RELEASE, pos);
963 }
1e6feb95
VZ
964}
965
966void wxSlider::OnPageScrollStart()
967{
968 // we do nothing here
969}
970
971bool 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
23645bfa 983bool wxStdSliderButtonInputHandler::HandleKey(wxInputConsumer *consumer,
1e6feb95
VZ
984 const wxKeyEvent& event,
985 bool pressed)
986{
88d2e567 987 if ( pressed )
1e6feb95
VZ
988 {
989 int keycode = event.GetKeyCode();
990
991 wxControlAction action;
992 switch ( keycode )
993 {
994 case WXK_HOME:
6766e5d1 995 action = wxACTION_SLIDER_END;
1e6feb95
VZ
996 break;
997
998 case WXK_END:
6766e5d1 999 action = wxACTION_SLIDER_START;
1e6feb95
VZ
1000 break;
1001
6766e5d1 1002 case WXK_RIGHT:
1e6feb95
VZ
1003 case WXK_UP:
1004 action = wxACTION_SLIDER_LINE_UP;
1005 break;
1006
6766e5d1 1007 case WXK_LEFT:
1e6feb95
VZ
1008 case WXK_DOWN:
1009 action = wxACTION_SLIDER_LINE_DOWN;
1010 break;
1011
187c183c 1012 case WXK_PAGEUP:
1e6feb95
VZ
1013 action = wxACTION_SLIDER_PAGE_UP;
1014 break;
1015
187c183c 1016 case WXK_PAGEDOWN:
1e6feb95
VZ
1017 action = wxACTION_SLIDER_PAGE_DOWN;
1018 break;
1019 }
1020
a290fa5a 1021 if ( !action.IsEmpty() )
1e6feb95 1022 {
23645bfa 1023 consumer->PerformAction(action);
1e6feb95 1024
a290fa5a 1025 return true;
1e6feb95
VZ
1026 }
1027 }
1028
23645bfa 1029 return wxStdInputHandler::HandleKey(consumer, event, pressed);
1e6feb95
VZ
1030}
1031
23645bfa 1032bool wxStdSliderButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
1e6feb95
VZ
1033 const wxMouseEvent& event)
1034{
23645bfa 1035 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1036
1037 if ( slider->GetThumb().HandleMouse(event) )
1038 {
1039 // processed by the thumb
a290fa5a 1040 return false;
1e6feb95
VZ
1041 }
1042
23645bfa 1043 return wxStdInputHandler::HandleMouse(consumer, event);
1e6feb95
VZ
1044}
1045
23645bfa 1046bool wxStdSliderButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
1e6feb95
VZ
1047 const wxMouseEvent& event)
1048{
23645bfa 1049 wxSlider *slider = wxStaticCast(consumer->GetInputWindow(), wxSlider);
1e6feb95
VZ
1050
1051 if ( slider->GetThumb().HandleMouseMove(event) )
1052 {
1053 // processed by the thumb
a290fa5a 1054 return false;
1e6feb95
VZ
1055 }
1056
23645bfa 1057 return wxStdInputHandler::HandleMouseMove(consumer, event);
1e6feb95
VZ
1058}
1059
61fef19b
VZ
1060bool
1061wxStdSliderButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
1062 const wxFocusEvent& WXUNUSED(event))
1e6feb95
VZ
1063{
1064 // slider's appearance changes when it gets/loses focus
a290fa5a 1065 return true;
1e6feb95
VZ
1066}
1067
1068#endif // wxUSE_SLIDER