]> git.saurik.com Git - wxWidgets.git/blob - src/msw/slider.cpp
Don't move the slider's value label if it's not being used.
[wxWidgets.git] / src / msw / slider.cpp
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$
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 namespace
44 {
45
46 // indices of labels in wxSlider::m_labels
47 enum
48 {
49 SliderLabel_Min,
50 SliderLabel_Max,
51 SliderLabel_Value,
52 SliderLabel_Last
53 };
54
55 // the gaps between the slider and the labels, in pixels
56 const int HGAP = 5;
57 const int VGAP = 4;
58 // the width of the borders including white space
59 const int BORDERPAD = 8;
60 // these 2 values are arbitrary:
61 const int THUMB = 24;
62 const int TICK = 8;
63
64 } // anonymous namespace
65
66 // ============================================================================
67 // wxSlider implementation
68 // ============================================================================
69
70 // ----------------------------------------------------------------------------
71 // construction
72 // ----------------------------------------------------------------------------
73
74 void wxSlider::Init()
75 {
76 m_labels = NULL;
77
78 m_pageSize = 1;
79 m_lineSize = 1;
80 m_rangeMax = 0;
81 m_rangeMin = 0;
82 m_tickFreq = 0;
83
84 m_isDragging = false;
85 }
86
87 bool wxSlider::Create(wxWindow *parent,
88 wxWindowID id,
89 int value,
90 int minValue,
91 int maxValue,
92 const wxPoint& pos,
93 const wxSize& size,
94 long style,
95 const wxValidator& validator,
96 const wxString& name)
97 {
98 wxCHECK_MSG( minValue < maxValue, false,
99 wxT("Slider minimum must be strictly less than the maximum.") );
100
101 // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and
102 // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility
103 // reasons we can't really change it, instead try to infer the orientation
104 // from the flags given to us here
105 switch ( style & (wxSL_LEFT | wxSL_RIGHT | wxSL_TOP | wxSL_BOTTOM) )
106 {
107 case wxSL_LEFT:
108 case wxSL_RIGHT:
109 style |= wxSL_VERTICAL;
110 break;
111
112 case wxSL_TOP:
113 case wxSL_BOTTOM:
114 style |= wxSL_HORIZONTAL;
115 break;
116
117 case 0:
118 // no specific direction, do we have at least the orientation?
119 if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) )
120 {
121 // no, choose default
122 style |= wxSL_BOTTOM | wxSL_HORIZONTAL;
123 }
124 };
125
126 wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL),
127 wxT("incompatible slider direction and orientation") );
128
129
130 // initialize everything
131 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
132 return false;
133
134 // ensure that we have correct values for GetLabelsSize()
135 m_rangeMin = minValue;
136 m_rangeMax = maxValue;
137
138 // create the labels first, so that our DoGetBestSize() could take them
139 // into account
140 //
141 // note that we could simply create 3 wxStaticTexts here but it could
142 // result in some observable side effects at wx level (e.g. the parent of
143 // wxSlider would have 3 more children than expected) and so we prefer not
144 // to do it like this
145 if ( m_windowStyle & wxSL_LABELS )
146 {
147 m_labels = new wxSubwindows(SliderLabel_Last);
148
149 HWND hwndParent = GetHwndOf(parent);
150 for ( size_t n = 0; n < SliderLabel_Last; n++ )
151 {
152 wxWindowIDRef lblid = NewControlId();
153
154 HWND wnd = ::CreateWindow
155 (
156 wxT("STATIC"),
157 NULL,
158 WS_CHILD | WS_VISIBLE | SS_CENTER,
159 0, 0, 0, 0,
160 hwndParent,
161 (HMENU)wxUIntToPtr(lblid.GetValue()),
162 wxGetInstance(),
163 NULL
164 );
165
166 m_labels->Set(n, wnd, lblid);
167 }
168 m_labels->SetFont(GetFont());
169 }
170
171 // now create the main control too
172 if ( !MSWCreateControl(TRACKBAR_CLASS, wxEmptyString, pos, size) )
173 return false;
174
175 // and initialize everything
176 SetRange(minValue, maxValue);
177 SetValue(value);
178 SetPageSize((maxValue - minValue)/10);
179
180 // we need to position the labels correctly if we have them and if
181 // SetSize() hadn't been called before (when best size was determined by
182 // MSWCreateControl()) as in this case they haven't been put in place yet
183 if ( m_labels && size.x != wxDefaultCoord && size.y != wxDefaultCoord )
184 {
185 SetSize(size);
186 }
187
188 return true;
189 }
190
191 WXDWORD wxSlider::MSWGetStyle(long style, WXDWORD *exstyle) const
192 {
193 WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
194
195 // TBS_HORZ, TBS_RIGHT and TBS_BOTTOM are 0 but do include them for clarity
196 msStyle |= style & wxSL_VERTICAL ? TBS_VERT : TBS_HORZ;
197
198 if ( style & wxSL_BOTH )
199 {
200 // this fully specifies the style combined with TBS_VERT/HORZ above
201 msStyle |= TBS_BOTH;
202 }
203 else // choose one direction
204 {
205 if ( style & wxSL_LEFT )
206 msStyle |= TBS_LEFT;
207 else if ( style & wxSL_RIGHT )
208 msStyle |= TBS_RIGHT;
209 else if ( style & wxSL_TOP )
210 msStyle |= TBS_TOP;
211 else if ( style & wxSL_BOTTOM )
212 msStyle |= TBS_BOTTOM;
213 }
214
215 if ( style & wxSL_AUTOTICKS )
216 msStyle |= TBS_AUTOTICKS;
217 else
218 msStyle |= TBS_NOTICKS;
219
220 if ( style & wxSL_SELRANGE )
221 msStyle |= TBS_ENABLESELRANGE;
222
223 return msStyle;
224 }
225
226 wxSlider::~wxSlider()
227 {
228 delete m_labels;
229 }
230
231 // ----------------------------------------------------------------------------
232 // event handling
233 // ----------------------------------------------------------------------------
234
235 bool wxSlider::MSWOnScroll(int WXUNUSED(orientation),
236 WXWORD wParam,
237 WXWORD WXUNUSED(pos),
238 WXHWND control)
239 {
240 wxEventType scrollEvent;
241 switch ( wParam )
242 {
243 case SB_TOP:
244 scrollEvent = wxEVT_SCROLL_TOP;
245 break;
246
247 case SB_BOTTOM:
248 scrollEvent = wxEVT_SCROLL_BOTTOM;
249 break;
250
251 case SB_LINEUP:
252 scrollEvent = wxEVT_SCROLL_LINEUP;
253 break;
254
255 case SB_LINEDOWN:
256 scrollEvent = wxEVT_SCROLL_LINEDOWN;
257 break;
258
259 case SB_PAGEUP:
260 scrollEvent = wxEVT_SCROLL_PAGEUP;
261 break;
262
263 case SB_PAGEDOWN:
264 scrollEvent = wxEVT_SCROLL_PAGEDOWN;
265 break;
266
267 case SB_THUMBTRACK:
268 scrollEvent = wxEVT_SCROLL_THUMBTRACK;
269 m_isDragging = true;
270 break;
271
272 case SB_THUMBPOSITION:
273 if ( m_isDragging )
274 {
275 scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
276 m_isDragging = false;
277 }
278 else
279 {
280 // this seems to only happen when the mouse wheel is used: in
281 // this case, as it might be unexpected to get THUMBRELEASE
282 // without preceding THUMBTRACKs, we don't generate it at all
283 // but generate CHANGED event because the control itself does
284 // not send us SB_ENDSCROLL for whatever reason when mouse
285 // wheel is used
286 scrollEvent = wxEVT_SCROLL_CHANGED;
287 }
288 break;
289
290 case SB_ENDSCROLL:
291 scrollEvent = wxEVT_SCROLL_CHANGED;
292 break;
293
294 default:
295 // unknown scroll event?
296 return false;
297 }
298
299 int newPos = ValueInvertOrNot((int) ::SendMessage((HWND) control, TBM_GETPOS, 0, 0));
300 if ( (newPos < GetMin()) || (newPos > GetMax()) )
301 {
302 // out of range - but we did process it
303 return true;
304 }
305
306 SetValue(newPos);
307
308 wxScrollEvent event(scrollEvent, m_windowId);
309 event.SetPosition(newPos);
310 event.SetEventObject( this );
311 HandleWindowEvent(event);
312
313 wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, GetId() );
314 cevent.SetInt( newPos );
315 cevent.SetEventObject( this );
316
317 return HandleWindowEvent( cevent );
318 }
319
320 void wxSlider::Command (wxCommandEvent & event)
321 {
322 SetValue (event.GetInt());
323 ProcessCommand (event);
324 }
325
326 // ----------------------------------------------------------------------------
327 // geometry stuff
328 // ----------------------------------------------------------------------------
329
330 wxRect wxSlider::GetBoundingBox() const
331 {
332 // take care not to call our own functions which would call us recursively
333 int x, y, w, h;
334 wxSliderBase::DoGetPosition(&x, &y);
335 wxSliderBase::DoGetSize(&w, &h);
336
337 wxRect rect(x, y, w, h);
338 if ( m_labels )
339 {
340 wxRect lrect = m_labels->GetBoundingBox();
341 GetParent()->ScreenToClient(&lrect.x, &lrect.y);
342 rect.Union(lrect);
343 }
344
345 return rect;
346 }
347
348 void wxSlider::DoGetSize(int *width, int *height) const
349 {
350 wxRect rect = GetBoundingBox();
351
352 if ( width )
353 *width = rect.width;
354 if ( height )
355 *height = rect.height;
356 }
357
358 void wxSlider::DoGetPosition(int *x, int *y) const
359 {
360 wxRect rect = GetBoundingBox();
361
362 if ( x )
363 *x = rect.x;
364 if ( y )
365 *y = rect.y;
366 }
367
368 int wxSlider::GetLabelsSize(int *widthMin, int *widthMax) const
369 {
370 if ( widthMin && widthMax )
371 {
372 *widthMin = GetTextExtent(Format(m_rangeMin)).x;
373 *widthMax = GetTextExtent(Format(m_rangeMax)).x;
374 }
375
376 return HasFlag(wxSL_LABELS) ? GetCharHeight() : 0;
377 }
378
379 void wxSlider::DoMoveWindow(int x, int y, int width, int height)
380 {
381 // all complications below are because we need to position the labels,
382 // without them everything is easy
383 if ( !m_labels )
384 {
385 wxSliderBase::DoMoveWindow(x, y, width, height);
386 return;
387 }
388
389 int minLabelWidth,
390 maxLabelWidth;
391 const int labelHeight = GetLabelsSize(&minLabelWidth, &maxLabelWidth);
392 const int longestLabelWidth = wxMax(minLabelWidth, maxLabelWidth);
393 if ( !HasFlag(wxSL_MIN_MAX_LABELS) )
394 {
395 minLabelWidth =
396 maxLabelWidth = 0;
397 }
398
399 int labelOffset = 0;
400 int tickOffset = 0;
401 if ( HasFlag(wxSL_TICKS))
402 tickOffset = TICK;
403 if ( HasFlag(wxSL_BOTH))
404 tickOffset *= 2;
405
406 // be careful to position the slider itself after moving the labels as
407 // otherwise our GetBoundingBox(), which is called from WM_SIZE handler,
408 // would return a wrong result and wrong size would be cached internally
409 if ( HasFlag(wxSL_VERTICAL) )
410 {
411 int holdTopWidth;
412 int holdTopX;
413 int holdBottomWidth;
414 int holdBottomX;
415 int xLabel = (wxMax((THUMB + (BORDERPAD * 2)), longestLabelWidth) / 2) -
416 (longestLabelWidth / 2) + x;
417 if ( HasFlag(wxSL_LEFT) )
418 {
419 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
420 {
421 holdTopX = xLabel;
422 holdTopWidth = minLabelWidth;
423 holdBottomX = xLabel - ((maxLabelWidth - minLabelWidth) / 2);
424 holdBottomWidth = maxLabelWidth;
425 if ( HasFlag(wxSL_INVERSE) )
426 {
427 wxSwap(holdTopWidth, holdBottomWidth);
428 wxSwap(holdTopX, holdBottomX);
429 }
430 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
431 holdTopX,
432 y,
433 holdTopWidth, labelHeight);
434 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
435 holdBottomX,
436 y + height - labelHeight,
437 holdBottomWidth, labelHeight);
438 }
439 if ( HasFlag(wxSL_VALUE_LABEL) )
440 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
441 x + THUMB + tickOffset + HGAP,
442 y + (height - labelHeight)/2,
443 longestLabelWidth, labelHeight);
444 }
445 else // wxSL_RIGHT
446 {
447 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
448 {
449 holdTopX = xLabel + longestLabelWidth + ((maxLabelWidth - minLabelWidth) / 2);
450 holdTopWidth = minLabelWidth;
451 holdBottomX = xLabel + longestLabelWidth;
452 holdBottomWidth = maxLabelWidth;
453 if ( HasFlag(wxSL_INVERSE) )
454 {
455 wxSwap(holdTopWidth, holdBottomWidth);
456 wxSwap(holdTopX, holdBottomX);
457 }
458 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
459 holdTopX,
460 y,
461 holdTopWidth, labelHeight);
462 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
463 holdBottomX,
464 y + height - labelHeight,
465 holdBottomWidth, labelHeight);
466 }
467 if ( HasFlag(wxSL_VALUE_LABEL) )
468 {
469 labelOffset = longestLabelWidth + HGAP;
470 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
471 x,
472 y + (height - labelHeight)/2,
473 longestLabelWidth, labelHeight);
474 }
475 }
476
477 // position the slider itself along the left/right edge
478 wxSliderBase::DoMoveWindow(
479 x + labelOffset,
480 y + labelHeight,
481 THUMB + tickOffset + HGAP,
482 height - (labelHeight * 2));
483 }
484 else // horizontal
485 {
486 int holdLeftWidth;
487 int holdLeftX;
488 int holdRightWidth;
489 int holdRightX;
490 int yLabelMinMax =
491 (y + ((THUMB + tickOffset) / 2)) - (labelHeight / 2);
492 int xLabelValue =
493 x + minLabelWidth +
494 ((width - (minLabelWidth + maxLabelWidth)) / 2) -
495 (longestLabelWidth / 2);
496
497 int ySlider = y;
498
499 if ( HasFlag(wxSL_BOTTOM) )
500 {
501 if ( HasFlag(wxSL_VALUE_LABEL) )
502 {
503 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
504 xLabelValue,
505 y,
506 longestLabelWidth, labelHeight);
507
508 ySlider += labelHeight;
509 yLabelMinMax += labelHeight;
510 }
511
512 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
513 {
514 holdLeftX = x;
515 holdLeftWidth = minLabelWidth;
516 holdRightX = x + width - maxLabelWidth;
517 holdRightWidth = maxLabelWidth;
518 if ( HasFlag(wxSL_INVERSE) )
519 {
520 wxSwap(holdLeftWidth, holdRightWidth);
521 wxSwap(holdLeftX, holdRightX);
522 }
523 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
524 holdLeftX,
525 yLabelMinMax,
526 holdLeftWidth, labelHeight);
527 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
528 holdRightX,
529 yLabelMinMax,
530 holdRightWidth, labelHeight);
531 }
532 }
533 else // wxSL_TOP
534 {
535 if ( HasFlag(wxSL_VALUE_LABEL) )
536 {
537 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
538 xLabelValue,
539 y + THUMB + tickOffset,
540 longestLabelWidth, labelHeight);
541 }
542
543 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
544 {
545 holdLeftX = x;
546 holdLeftWidth = minLabelWidth;
547 holdRightX = x + width - maxLabelWidth;
548 holdRightWidth = maxLabelWidth;
549 if ( HasFlag(wxSL_INVERSE) )
550 {
551 wxSwap(holdLeftWidth, holdRightWidth);
552 wxSwap(holdLeftX, holdRightX);
553 }
554 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
555 holdLeftX,
556 yLabelMinMax,
557 holdLeftWidth, labelHeight);
558 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
559 holdRightX,
560 yLabelMinMax,
561 holdRightWidth, labelHeight);
562 }
563 }
564
565 // position the slider itself along the top/bottom edge
566 if ( HasFlag(wxSL_MIN_MAX_LABELS) || HasFlag(wxSL_VALUE_LABEL) )
567 labelOffset = labelHeight;
568 wxSliderBase::DoMoveWindow(
569 x + minLabelWidth + VGAP,
570 ySlider,
571 width - (minLabelWidth + maxLabelWidth + (VGAP*2)),
572 THUMB + tickOffset);
573 }
574 }
575
576 wxSize wxSlider::DoGetBestSize() const
577 {
578 // this value is arbitrary:
579 static const int length = 100;
580
581 int *width;
582 wxSize size;
583 if ( HasFlag(wxSL_VERTICAL) )
584 {
585 size.x = THUMB;
586 size.y = length;
587 width = &size.x;
588
589 if ( m_labels )
590 {
591 int widthMin,
592 widthMax;
593 int hLabel = GetLabelsSize(&widthMin, &widthMax);
594
595 // account for the labels
596 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
597 size.x += HGAP + wxMax(widthMin, widthMax);
598
599 // labels are indented relative to the slider itself
600 size.y += hLabel;
601 }
602 }
603 else // horizontal
604 {
605 size.x = length;
606 size.y = THUMB;
607 width = &size.y;
608
609 if ( m_labels )
610 {
611 int labelSize = GetLabelsSize();
612
613 // Min/max labels are compensated by the ticks so we don't need
614 // extra space for them if we're also showing ticks.
615 if ( HasFlag(wxSL_MIN_MAX_LABELS) && !HasFlag(wxSL_TICKS) )
616 size.y += labelSize;
617
618 // The value label is always on top of the control and so does need
619 // extra space in any case.
620 if ( HasFlag(wxSL_VALUE_LABEL) )
621 size.y += labelSize;
622 }
623 }
624
625 // need extra space to show ticks
626 if ( HasFlag(wxSL_TICKS) )
627 {
628 *width += TICK;
629 // and maybe twice as much if we show them on both sides
630 if ( HasFlag(wxSL_BOTH) )
631 *width += TICK;
632 }
633 return size;
634 }
635
636 // ----------------------------------------------------------------------------
637 // slider-specific methods
638 // ----------------------------------------------------------------------------
639
640 int wxSlider::GetValue() const
641 {
642 return ValueInvertOrNot(::SendMessage(GetHwnd(), TBM_GETPOS, 0, 0));
643 }
644
645 void wxSlider::SetValue(int value)
646 {
647 ::SendMessage(GetHwnd(), TBM_SETPOS, (WPARAM)TRUE, (LPARAM)ValueInvertOrNot(value));
648
649 if ( m_labels )
650 {
651 ::SetWindowText((*m_labels)[SliderLabel_Value], Format(value).wx_str());
652 }
653 }
654
655 void wxSlider::SetRange(int minValue, int maxValue)
656 {
657 // Remember the old logical value if we need to update the physical control
658 // value after changing its range in wxSL_INVERSE case (and avoid an
659 // unnecessary call to GetValue() otherwise as it's just not needed).
660 const int valueOld = HasFlag(wxSL_INVERSE) ? GetValue() : 0;
661
662 m_rangeMin = minValue;
663 m_rangeMax = maxValue;
664
665 ::SendMessage(GetHwnd(), TBM_SETRANGEMIN, TRUE, m_rangeMin);
666 ::SendMessage(GetHwnd(), TBM_SETRANGEMAX, TRUE, m_rangeMax);
667
668 if ( m_labels )
669 {
670 ::SetWindowText((*m_labels)[SliderLabel_Min],
671 Format(ValueInvertOrNot(m_rangeMin)).wx_str());
672 ::SetWindowText((*m_labels)[SliderLabel_Max],
673 Format(ValueInvertOrNot(m_rangeMax)).wx_str());
674 }
675
676 // When emulating wxSL_INVERSE style in wxWidgets, we need to update the
677 // value after changing the range to ensure that the value seen by the user
678 // code, i.e. the one returned by GetValue(), does not change.
679 if ( HasFlag(wxSL_INVERSE) )
680 {
681 ::SendMessage(GetHwnd(), TBM_SETPOS, TRUE, ValueInvertOrNot(valueOld));
682 }
683 }
684
685 void wxSlider::DoSetTickFreq(int n)
686 {
687 m_tickFreq = n;
688 ::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) 0 );
689 }
690
691 void wxSlider::SetPageSize(int pageSize)
692 {
693 ::SendMessage( GetHwnd(), TBM_SETPAGESIZE, (WPARAM) 0, (LPARAM) pageSize );
694 m_pageSize = pageSize;
695 }
696
697 int wxSlider::GetPageSize() const
698 {
699 return m_pageSize;
700 }
701
702 void wxSlider::ClearSel()
703 {
704 ::SendMessage(GetHwnd(), TBM_CLEARSEL, (WPARAM) TRUE, (LPARAM) 0);
705 }
706
707 void wxSlider::ClearTicks()
708 {
709 ::SendMessage(GetHwnd(), TBM_CLEARTICS, (WPARAM) TRUE, (LPARAM) 0);
710 }
711
712 void wxSlider::SetLineSize(int lineSize)
713 {
714 m_lineSize = lineSize;
715 ::SendMessage(GetHwnd(), TBM_SETLINESIZE, (WPARAM) 0, (LPARAM) lineSize);
716 }
717
718 int wxSlider::GetLineSize() const
719 {
720 return (int)::SendMessage(GetHwnd(), TBM_GETLINESIZE, 0, 0);
721 }
722
723 int wxSlider::GetSelEnd() const
724 {
725 return (int)::SendMessage(GetHwnd(), TBM_GETSELEND, 0, 0);
726 }
727
728 int wxSlider::GetSelStart() const
729 {
730 return (int)::SendMessage(GetHwnd(), TBM_GETSELSTART, 0, 0);
731 }
732
733 void wxSlider::SetSelection(int minPos, int maxPos)
734 {
735 ::SendMessage(GetHwnd(), TBM_SETSEL,
736 (WPARAM) TRUE /* redraw */,
737 (LPARAM) MAKELONG( minPos, maxPos) );
738 }
739
740 void wxSlider::SetThumbLength(int len)
741 {
742 ::SendMessage(GetHwnd(), TBM_SETTHUMBLENGTH, (WPARAM) len, (LPARAM) 0);
743 }
744
745 int wxSlider::GetThumbLength() const
746 {
747 return (int)::SendMessage( GetHwnd(), TBM_GETTHUMBLENGTH, 0, 0);
748 }
749
750 void wxSlider::SetTick(int tickPos)
751 {
752 ::SendMessage( GetHwnd(), TBM_SETTIC, (WPARAM) 0, (LPARAM) tickPos );
753 }
754
755 // ----------------------------------------------------------------------------
756 // composite control methods
757 // ----------------------------------------------------------------------------
758
759 WXHWND wxSlider::GetStaticMin() const
760 {
761 return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Min] : NULL;
762 }
763
764 WXHWND wxSlider::GetStaticMax() const
765 {
766 return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Max] : NULL;
767 }
768
769 WXHWND wxSlider::GetEditValue() const
770 {
771 return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Value] : NULL;
772 }
773
774 WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxSlider, wxSliderBase, m_labels)
775
776 #endif // wxUSE_SLIDER