1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/slider.cpp
3 // Purpose:     wxSlider, using the Win95 (and later) trackbar control
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     04/01/98
7 // RCS-ID:      $Id: slider95.cpp 41054 2006-09-07 19:01:45Z ABX $
8 // Copyright:   (c) Julian Smart 1998
9 //                  Vadim Zeitlin 2004
10 // Licence:     wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12 
13 // ============================================================================
14 // declarations
15 // ============================================================================
16 
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20 
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23 
24 #ifdef __BORLANDC__
25     #pragma hdrstop
26 #endif
27 
28 #if wxUSE_SLIDER
29 
30 #include "wx/slider.h"
31 
32 #ifndef WX_PRECOMP
33     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
34     #include "wx/brush.h"
35 #endif
36 
37 #include "wx/msw/subwin.h"
38 
39 // ----------------------------------------------------------------------------
40 // constants
41 // ----------------------------------------------------------------------------
42 
43 // indices of labels in wxSlider::m_labels
44 enum
45 {
46     SliderLabel_Min,
47     SliderLabel_Max,
48     SliderLabel_Value,
49     SliderLabel_Last
50 };
51 
52 // the gap between the slider and the labels, in pixels
53 static const int HGAP = 5;
54 
55 // ----------------------------------------------------------------------------
56 // XTI
57 // ----------------------------------------------------------------------------
58 
59 #if wxUSE_EXTENDED_RTTI
60 WX_DEFINE_FLAGS( wxSliderStyle )
61 
wxBEGIN_FLAGS(wxSliderStyle)62 wxBEGIN_FLAGS( wxSliderStyle )
63     // new style border flags, we put them first to
64     // use them for streaming out
65     wxFLAGS_MEMBER(wxBORDER_SIMPLE)
66     wxFLAGS_MEMBER(wxBORDER_SUNKEN)
67     wxFLAGS_MEMBER(wxBORDER_DOUBLE)
68     wxFLAGS_MEMBER(wxBORDER_RAISED)
69     wxFLAGS_MEMBER(wxBORDER_STATIC)
70     wxFLAGS_MEMBER(wxBORDER_NONE)
71 
72     // old style border flags
73     wxFLAGS_MEMBER(wxSIMPLE_BORDER)
74     wxFLAGS_MEMBER(wxSUNKEN_BORDER)
75     wxFLAGS_MEMBER(wxDOUBLE_BORDER)
76     wxFLAGS_MEMBER(wxRAISED_BORDER)
77     wxFLAGS_MEMBER(wxSTATIC_BORDER)
78     wxFLAGS_MEMBER(wxBORDER)
79 
80     // standard window styles
81     wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
82     wxFLAGS_MEMBER(wxCLIP_CHILDREN)
83     wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
84     wxFLAGS_MEMBER(wxWANTS_CHARS)
85     wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
86     wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
87     wxFLAGS_MEMBER(wxVSCROLL)
88     wxFLAGS_MEMBER(wxHSCROLL)
89 
90     wxFLAGS_MEMBER(wxSL_HORIZONTAL)
91     wxFLAGS_MEMBER(wxSL_VERTICAL)
92     wxFLAGS_MEMBER(wxSL_AUTOTICKS)
93     wxFLAGS_MEMBER(wxSL_LABELS)
94     wxFLAGS_MEMBER(wxSL_LEFT)
95     wxFLAGS_MEMBER(wxSL_TOP)
96     wxFLAGS_MEMBER(wxSL_RIGHT)
97     wxFLAGS_MEMBER(wxSL_BOTTOM)
98     wxFLAGS_MEMBER(wxSL_BOTH)
99     wxFLAGS_MEMBER(wxSL_SELRANGE)
100     wxFLAGS_MEMBER(wxSL_INVERSE)
101 
102 wxEND_FLAGS( wxSliderStyle )
103 
104 IMPLEMENT_DYNAMIC_CLASS_XTI(wxSlider, wxControl,"wx/slider.h")
105 
106 wxBEGIN_PROPERTIES_TABLE(wxSlider)
107     wxEVENT_RANGE_PROPERTY( Scroll , wxEVT_SCROLL_TOP , wxEVT_SCROLL_CHANGED , wxScrollEvent )
108     wxEVENT_PROPERTY( Updated , wxEVT_COMMAND_SLIDER_UPDATED , wxCommandEvent )
109 
110     wxPROPERTY( Value , int , SetValue, GetValue , 0, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
111     wxPROPERTY( Minimum , int , SetMin, GetMin, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
112     wxPROPERTY( Maximum , int , SetMax, GetMax, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
113     wxPROPERTY( PageSize , int , SetPageSize, GetLineSize, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
114     wxPROPERTY( LineSize , int , SetLineSize, GetLineSize, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
115     wxPROPERTY( ThumbLength , int , SetThumbLength, GetThumbLength, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
116     wxPROPERTY_FLAGS( WindowStyle , wxSliderStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
117 wxEND_PROPERTIES_TABLE()
118 
119 wxBEGIN_HANDLERS_TABLE(wxSlider)
120 wxEND_HANDLERS_TABLE()
121 
122 wxCONSTRUCTOR_8( wxSlider , wxWindow* , Parent , wxWindowID , Id , int , Value , int , Minimum , int , Maximum , wxPoint , Position , wxSize , Size , long , WindowStyle )
123 #else
124 IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
125 #endif
126 
127 // ============================================================================
128 // wxSlider implementation
129 // ============================================================================
130 
131 // ----------------------------------------------------------------------------
132 // construction
133 // ----------------------------------------------------------------------------
134 
135 void wxSlider::Init()
136 {
137     m_labels = NULL;
138 
139     m_pageSize = 1;
140     m_lineSize = 1;
141     m_rangeMax = 0;
142     m_rangeMin = 0;
143     m_tickFreq = 0;
144 
145     m_isDragging = false;
146 }
147 
148 bool
Create(wxWindow * parent,wxWindowID id,int value,int minValue,int maxValue,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)149 wxSlider::Create(wxWindow *parent,
150                  wxWindowID id,
151                  int value,
152                  int minValue,
153                  int maxValue,
154                  const wxPoint& pos,
155                  const wxSize& size,
156                  long style,
157                  const wxValidator& validator,
158                  const wxString& name)
159 {
160     // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and
161     // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility
162     // reasons we can't really change it, instead try to infer the orientation
163     // from the flags given to us here
164     switch ( style & (wxSL_LEFT | wxSL_RIGHT | wxSL_TOP | wxSL_BOTTOM) )
165     {
166         case wxSL_LEFT:
167         case wxSL_RIGHT:
168             style |= wxSL_VERTICAL;
169             break;
170 
171         case wxSL_TOP:
172         case wxSL_BOTTOM:
173             style |= wxSL_HORIZONTAL;
174             break;
175 
176         case 0:
177             // no specific direction, do we have at least the orientation?
178             if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) )
179             {
180                 // no, choose default
181                 style |= wxSL_BOTTOM | wxSL_HORIZONTAL;
182             }
183     };
184 
185     wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL),
186                     _T("incompatible slider direction and orientation") );
187 
188 
189     // initialize everything
190     if ( !CreateControl(parent, id, pos, size, style, validator, name) )
191         return false;
192 
193     // ensure that we have correct values for GetLabelsSize()
194     m_rangeMin = minValue;
195     m_rangeMax = maxValue;
196 
197     // create the labels first, so that our DoGetBestSize() could take them
198     // into account
199     //
200     // note that we could simply create 3 wxStaticTexts here but it could
201     // result in some observable side effects at wx level (e.g. the parent of
202     // wxSlider would have 3 more children than expected) and so we prefer not
203     // to do it like this
204     if ( m_windowStyle & wxSL_LABELS )
205     {
206         m_labels = new wxSubwindows(SliderLabel_Last);
207 
208         HWND hwndParent = GetHwndOf(parent);
209         for ( size_t n = 0; n < SliderLabel_Last; n++ )
210         {
211             (*m_labels)[n] = ::CreateWindow
212                                (
213                                     wxT("STATIC"),
214                                     NULL,
215                                     WS_CHILD | WS_VISIBLE | SS_CENTER,
216                                     0, 0, 0, 0,
217                                     hwndParent,
218                                     (HMENU)NewControlId(),
219                                     wxGetInstance(),
220                                     NULL
221                                );
222         }
223 
224         m_labels->SetFont(GetFont());
225     }
226 
227     // now create the main control too
228     if ( !MSWCreateControl(TRACKBAR_CLASS, wxEmptyString, pos, size) )
229         return false;
230 
231     // and initialize everything
232     SetRange(minValue, maxValue);
233     SetValue(value);
234     SetPageSize((maxValue - minValue)/10);
235 
236     // we need to position the labels correctly if we have them and if
237     // SetSize() hadn't been called before (when best size was determined by
238     // MSWCreateControl()) as in this case they haven't been put in place yet
239     if ( m_labels && size.x != wxDefaultCoord && size.y != wxDefaultCoord )
240     {
241         SetSize(size);
242     }
243 
244     return true;
245 }
246 
MSWGetStyle(long style,WXDWORD * exstyle) const247 WXDWORD wxSlider::MSWGetStyle(long style, WXDWORD *exstyle) const
248 {
249     WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
250 
251     // TBS_HORZ, TBS_RIGHT and TBS_BOTTOM are 0 but do include them for clarity
252     msStyle |= style & wxSL_VERTICAL ? TBS_VERT : TBS_HORZ;
253 
254     if ( style & wxSL_BOTH )
255     {
256         // this fully specifies the style combined with TBS_VERT/HORZ above
257         msStyle |= TBS_BOTH;
258     }
259     else // choose one direction
260     {
261         if ( style & wxSL_LEFT )
262             msStyle |= TBS_LEFT;
263         else if ( style & wxSL_RIGHT )
264             msStyle |= TBS_RIGHT;
265         else if ( style & wxSL_TOP )
266             msStyle |= TBS_TOP;
267         else if ( style & wxSL_BOTTOM )
268             msStyle |= TBS_BOTTOM;
269     }
270 
271     if ( style & wxSL_AUTOTICKS )
272         msStyle |= TBS_AUTOTICKS;
273     else
274         msStyle |= TBS_NOTICKS;
275 
276     if ( style & wxSL_SELRANGE )
277         msStyle |= TBS_ENABLESELRANGE;
278 
279     return msStyle;
280 }
281 
~wxSlider()282 wxSlider::~wxSlider()
283 {
284     delete m_labels;
285 }
286 
287 // ----------------------------------------------------------------------------
288 // event handling
289 // ----------------------------------------------------------------------------
290 
MSWOnScroll(int WXUNUSED (orientation),WXWORD wParam,WXWORD WXUNUSED (pos),WXHWND control)291 bool wxSlider::MSWOnScroll(int WXUNUSED(orientation),
292                            WXWORD wParam,
293                            WXWORD WXUNUSED(pos),
294                            WXHWND control)
295 {
296     wxEventType scrollEvent;
297     switch ( wParam )
298     {
299         case SB_TOP:
300             scrollEvent = wxEVT_SCROLL_TOP;
301             break;
302 
303         case SB_BOTTOM:
304             scrollEvent = wxEVT_SCROLL_BOTTOM;
305             break;
306 
307         case SB_LINEUP:
308             scrollEvent = wxEVT_SCROLL_LINEUP;
309             break;
310 
311         case SB_LINEDOWN:
312             scrollEvent = wxEVT_SCROLL_LINEDOWN;
313             break;
314 
315         case SB_PAGEUP:
316             scrollEvent = wxEVT_SCROLL_PAGEUP;
317             break;
318 
319         case SB_PAGEDOWN:
320             scrollEvent = wxEVT_SCROLL_PAGEDOWN;
321             break;
322 
323         case SB_THUMBTRACK:
324             scrollEvent = wxEVT_SCROLL_THUMBTRACK;
325             m_isDragging = true;
326             break;
327 
328         case SB_THUMBPOSITION:
329             if ( m_isDragging )
330             {
331                 scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
332                 m_isDragging = false;
333             }
334             else
335             {
336                 // this seems to only happen when the mouse wheel is used: in
337                 // this case, as it might be unexpected to get THUMBRELEASE
338                 // without preceding THUMBTRACKs, we don't generate it at all
339                 // but generate CHANGED event because the control itself does
340                 // not send us SB_ENDSCROLL for whatever reason when mouse
341                 // wheel is used
342                 scrollEvent = wxEVT_SCROLL_CHANGED;
343             }
344             break;
345 
346         case SB_ENDSCROLL:
347             scrollEvent = wxEVT_SCROLL_CHANGED;
348             break;
349 
350         default:
351             // unknown scroll event?
352             return false;
353     }
354 
355     int newPos = ValueInvertOrNot((int) ::SendMessage((HWND) control, TBM_GETPOS, 0, 0));
356     if ( (newPos < GetMin()) || (newPos > GetMax()) )
357     {
358         // out of range - but we did process it
359         return true;
360     }
361 
362     SetValue(newPos);
363 
364     wxScrollEvent event(scrollEvent, m_windowId);
365     event.SetPosition(newPos);
366     event.SetEventObject( this );
367     GetEventHandler()->ProcessEvent(event);
368 
369     wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, GetId() );
370     cevent.SetInt( newPos );
371     cevent.SetEventObject( this );
372 
373     return GetEventHandler()->ProcessEvent( cevent );
374 }
375 
Command(wxCommandEvent & event)376 void wxSlider::Command (wxCommandEvent & event)
377 {
378     SetValue (event.GetInt());
379     ProcessCommand (event);
380 }
381 
382 // ----------------------------------------------------------------------------
383 // geometry stuff
384 // ----------------------------------------------------------------------------
385 
GetBoundingBox() const386 wxRect wxSlider::GetBoundingBox() const
387 {
388     // take care not to call our own functions which would call us recursively
389     int x, y, w, h;
390     wxSliderBase::DoGetPosition(&x, &y);
391     wxSliderBase::DoGetSize(&w, &h);
392 
393     wxRect rect(x, y, w, h);
394     if ( m_labels )
395     {
396         wxRect lrect = m_labels->GetBoundingBox();
397         GetParent()->ScreenToClient(&lrect.x, &lrect.y);
398         rect.Union(lrect);
399     }
400 
401     return rect;
402 }
403 
DoGetSize(int * width,int * height) const404 void wxSlider::DoGetSize(int *width, int *height) const
405 {
406     wxRect rect = GetBoundingBox();
407 
408     if ( width )
409         *width = rect.width;
410     if ( height )
411         *height = rect.height;
412 }
413 
DoGetPosition(int * x,int * y) const414 void wxSlider::DoGetPosition(int *x, int *y) const
415 {
416     wxRect rect = GetBoundingBox();
417 
418     if ( x )
419         *x = rect.x;
420     if ( y )
421         *y = rect.y;
422 }
423 
GetLabelsSize(int * width) const424 int wxSlider::GetLabelsSize(int *width) const
425 {
426     int cy;
427 
428     if ( width )
429     {
430         // find the max label width
431         int wLabelMin, wLabelMax;
432         GetTextExtent(Format(m_rangeMin), &wLabelMin, &cy);
433         GetTextExtent(Format(m_rangeMax), &wLabelMax, &cy);
434 
435         *width = wxMax(wLabelMin, wLabelMax);
436     }
437     else
438     {
439         cy = GetCharHeight();
440     }
441 
442     return EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
443 }
444 
DoMoveWindow(int x,int y,int width,int height)445 void wxSlider::DoMoveWindow(int x, int y, int width, int height)
446 {
447     // all complications below are because we need to position the labels,
448     // without them everything is easy
449     if ( !m_labels )
450     {
451         wxSliderBase::DoMoveWindow(x, y, width, height);
452         return;
453     }
454 
455     // be careful to position the slider itself after moving the labels as
456     // otherwise our GetBoundingBox(), which is called from WM_SIZE handler,
457     // would return a wrong result and wrong size would be cached internally
458     if ( HasFlag(wxSL_VERTICAL) )
459     {
460         int wLabel;
461         int hLabel = GetLabelsSize(&wLabel);
462 
463         int xLabel = HasFlag(wxSL_LEFT) ? x + width - wLabel : x;
464 
465         // position all labels: min at the top, value in the middle and max at
466         // the bottom
467         DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
468                      xLabel, y, wLabel, hLabel);
469 
470         DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
471                      xLabel, y + (height - hLabel)/2, wLabel, hLabel);
472 
473         DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
474                       xLabel, y + height - hLabel, wLabel, hLabel);
475 
476         // position the slider itself along the left/right edge
477         wxSliderBase::DoMoveWindow(HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
478                                    y + hLabel/2,
479                                    width - wLabel - HGAP,
480                                    height - hLabel);
481     }
482     else // horizontal
483     {
484         int wLabel;
485         int hLabel = GetLabelsSize(&wLabel);
486 
487         int yLabel = HasFlag(wxSL_TOP) ? y + height - hLabel : y;
488 
489         // position all labels: min on the left, value in the middle and max to
490         // the right
491         DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
492                       x, yLabel, wLabel, hLabel);
493 
494         DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
495                       x + (width - wLabel)/2, yLabel, wLabel, hLabel);
496 
497         DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
498                       x + width - wLabel, yLabel, wLabel, hLabel);
499 
500         // position the slider itself along the top/bottom edge
501         wxSliderBase::DoMoveWindow(x,
502                                    HasFlag(wxSL_TOP) ? y : y + hLabel,
503                                    width,
504                                    height - hLabel);
505     }
506 }
507 
DoGetBestSize() const508 wxSize wxSlider::DoGetBestSize() const
509 {
510     // these values are arbitrary
511     static const int length = 100;
512     static const int thumb = 24;
513     static const int ticks = 8;
514 
515     int *width;
516     wxSize size;
517     if ( HasFlag(wxSL_VERTICAL) )
518     {
519         size.x = thumb;
520         size.y = length;
521         width = &size.x;
522 
523         if ( m_labels )
524         {
525             int wLabel;
526             int hLabel = GetLabelsSize(&wLabel);
527 
528             // account for the labels
529             size.x += HGAP + wLabel;
530 
531             // labels are indented relative to the slider itself
532             size.y += hLabel;
533         }
534     }
535     else // horizontal
536     {
537         size.x = length;
538         size.y = thumb;
539         width = &size.y;
540 
541         if ( m_labels )
542         {
543             // labels add extra height
544             size.y += GetLabelsSize();
545         }
546     }
547 
548     // need extra space to show ticks
549     if ( HasFlag(wxSL_TICKS) )
550     {
551         *width += ticks;
552 
553         // and maybe twice as much if we show them on both sides
554         if ( HasFlag(wxSL_BOTH) )
555             *width += ticks;
556     }
557 
558     return size;
559 }
560 
561 // ----------------------------------------------------------------------------
562 // slider-specific methods
563 // ----------------------------------------------------------------------------
564 
GetValue() const565 int wxSlider::GetValue() const
566 {
567     return ValueInvertOrNot(::SendMessage(GetHwnd(), TBM_GETPOS, 0, 0));
568 }
569 
SetValue(int value)570 void wxSlider::SetValue(int value)
571 {
572     ::SendMessage(GetHwnd(), TBM_SETPOS, (WPARAM)TRUE, (LPARAM)ValueInvertOrNot(value));
573 
574     if ( m_labels )
575     {
576         ::SetWindowText((*m_labels)[SliderLabel_Value], Format(value));
577     }
578 }
579 
SetRange(int minValue,int maxValue)580 void wxSlider::SetRange(int minValue, int maxValue)
581 {
582     m_rangeMin = minValue;
583     m_rangeMax = maxValue;
584 
585     ::SendMessage(GetHwnd(), TBM_SETRANGEMIN, TRUE, m_rangeMin);
586     ::SendMessage(GetHwnd(), TBM_SETRANGEMAX, TRUE, m_rangeMax);
587 
588     if ( m_labels )
589     {
590         ::SetWindowText((*m_labels)[SliderLabel_Min], Format(ValueInvertOrNot(m_rangeMin)));
591         ::SetWindowText((*m_labels)[SliderLabel_Max], Format(ValueInvertOrNot(m_rangeMax)));
592     }
593 }
594 
SetTickFreq(int n,int pos)595 void wxSlider::SetTickFreq(int n, int pos)
596 {
597     m_tickFreq = n;
598     ::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) pos );
599 }
600 
SetPageSize(int pageSize)601 void wxSlider::SetPageSize(int pageSize)
602 {
603     ::SendMessage( GetHwnd(), TBM_SETPAGESIZE, (WPARAM) 0, (LPARAM) pageSize );
604     m_pageSize = pageSize;
605 }
606 
GetPageSize() const607 int wxSlider::GetPageSize() const
608 {
609     return m_pageSize;
610 }
611 
ClearSel()612 void wxSlider::ClearSel()
613 {
614     ::SendMessage(GetHwnd(), TBM_CLEARSEL, (WPARAM) TRUE, (LPARAM) 0);
615 }
616 
ClearTicks()617 void wxSlider::ClearTicks()
618 {
619     ::SendMessage(GetHwnd(), TBM_CLEARTICS, (WPARAM) TRUE, (LPARAM) 0);
620 }
621 
SetLineSize(int lineSize)622 void wxSlider::SetLineSize(int lineSize)
623 {
624     m_lineSize = lineSize;
625     ::SendMessage(GetHwnd(), TBM_SETLINESIZE, (WPARAM) 0, (LPARAM) lineSize);
626 }
627 
GetLineSize() const628 int wxSlider::GetLineSize() const
629 {
630     return (int)::SendMessage(GetHwnd(), TBM_GETLINESIZE, 0, 0);
631 }
632 
GetSelEnd() const633 int wxSlider::GetSelEnd() const
634 {
635     return (int)::SendMessage(GetHwnd(), TBM_GETSELEND, 0, 0);
636 }
637 
GetSelStart() const638 int wxSlider::GetSelStart() const
639 {
640     return (int)::SendMessage(GetHwnd(), TBM_GETSELSTART, 0, 0);
641 }
642 
SetSelection(int minPos,int maxPos)643 void wxSlider::SetSelection(int minPos, int maxPos)
644 {
645     ::SendMessage(GetHwnd(), TBM_SETSEL,
646                   (WPARAM) TRUE /* redraw */,
647                   (LPARAM) MAKELONG( minPos, maxPos) );
648 }
649 
SetThumbLength(int len)650 void wxSlider::SetThumbLength(int len)
651 {
652     ::SendMessage(GetHwnd(), TBM_SETTHUMBLENGTH, (WPARAM) len, (LPARAM) 0);
653 }
654 
GetThumbLength() const655 int wxSlider::GetThumbLength() const
656 {
657     return (int)::SendMessage( GetHwnd(), TBM_GETTHUMBLENGTH, 0, 0);
658 }
659 
SetTick(int tickPos)660 void wxSlider::SetTick(int tickPos)
661 {
662     ::SendMessage( GetHwnd(), TBM_SETTIC, (WPARAM) 0, (LPARAM) tickPos );
663 }
664 
665 // ----------------------------------------------------------------------------
666 // composite control methods
667 // ----------------------------------------------------------------------------
668 
GetStaticMin() const669 WXHWND wxSlider::GetStaticMin() const
670 {
671     return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Min] : NULL;
672 }
673 
GetStaticMax() const674 WXHWND wxSlider::GetStaticMax() const
675 {
676     return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Max] : NULL;
677 }
678 
GetEditValue() const679 WXHWND wxSlider::GetEditValue() const
680 {
681     return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Value] : NULL;
682 }
683 
684 WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxSlider, wxSliderBase, m_labels)
685 
686 #endif // wxUSE_SLIDER
687