]> git.saurik.com Git - wxWidgets.git/blame - src/msw/slider.cpp
Avoid an assert when m_dir is empty
[wxWidgets.git] / src / msw / slider.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
851dee09 2// Name: src/msw/slider.cpp
7d0d80bd 3// Purpose: wxSlider, using the Win95 (and later) trackbar control
2bda0e17
KB
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6181cef5
VZ
8// Copyright: (c) Julian Smart 1998
9// Vadim Zeitlin 2004
65571936 10// Licence: wxWindows licence
2bda0e17
KB
11/////////////////////////////////////////////////////////////////////////////
12
6181cef5
VZ
13// ============================================================================
14// declarations
15// ============================================================================
16
6181cef5
VZ
17// ----------------------------------------------------------------------------
18// headers
19// ----------------------------------------------------------------------------
20
2bda0e17
KB
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
6181cef5 25 #pragma hdrstop
2bda0e17
KB
26#endif
27
1e6feb95
VZ
28#if wxUSE_SLIDER
29
f4da9a94
WS
30#include "wx/slider.h"
31
2bda0e17 32#ifndef WX_PRECOMP
57bd4c60 33 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
6181cef5 34 #include "wx/brush.h"
2bda0e17
KB
35#endif
36
6181cef5 37#include "wx/msw/subwin.h"
2bda0e17 38
6181cef5
VZ
39// ----------------------------------------------------------------------------
40// constants
41// ----------------------------------------------------------------------------
42
ce0ee9ae
VZ
43namespace
44{
45
7d0d80bd 46// indices of labels in wxSlider::m_labels
6181cef5
VZ
47enum
48{
49 SliderLabel_Min,
50 SliderLabel_Max,
51 SliderLabel_Value,
52 SliderLabel_Last
53};
54
ce0ee9ae
VZ
55// the gaps between the slider and the labels, in pixels
56const int HGAP = 5;
57const int VGAP = 4;
58// the width of the borders including white space
59const int BORDERPAD = 8;
60// these 2 values are arbitrary:
61const int THUMB = 24;
62const int TICK = 8;
63
64} // anonymous namespace
6181cef5 65
6181cef5 66// ============================================================================
7d0d80bd 67// wxSlider implementation
6181cef5
VZ
68// ============================================================================
69
70// ----------------------------------------------------------------------------
71// construction
72// ----------------------------------------------------------------------------
73
7d0d80bd 74void wxSlider::Init()
2bda0e17 75{
6181cef5
VZ
76 m_labels = NULL;
77
5f605ccf
VZ
78 m_pageSize = 1;
79 m_lineSize = 1;
80 m_rangeMax = 0;
81 m_rangeMin = 0;
82 m_tickFreq = 0;
3c96417a
VZ
83
84 m_isDragging = false;
2bda0e17
KB
85}
86
ce0ee9ae
VZ
87bool 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)
2bda0e17 97{
ce0ee9ae
VZ
98 wxCHECK_MSG( minValue < maxValue, false,
99 wxT("Slider minimum must be strictly less than the maximum.") );
100
10f80f9b
VZ
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
d1103787 126 wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL),
9a83f860 127 wxT("incompatible slider direction and orientation") );
10f80f9b
VZ
128
129
6181cef5
VZ
130 // initialize everything
131 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
822e690b 132 return false;
2bda0e17 133
6181cef5
VZ
134 // ensure that we have correct values for GetLabelsSize()
135 m_rangeMin = minValue;
136 m_rangeMax = maxValue;
5f605ccf 137
6181cef5
VZ
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
5f605ccf
VZ
145 if ( m_windowStyle & wxSL_LABELS )
146 {
6181cef5
VZ
147 m_labels = new wxSubwindows(SliderLabel_Last);
148
149 HWND hwndParent = GetHwndOf(parent);
150 for ( size_t n = 0; n < SliderLabel_Last; n++ )
151 {
52ca4ec4
VZ
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,
dca0f651 161 (HMENU)wxUIntToPtr(lblid.GetValue()),
52ca4ec4
VZ
162 wxGetInstance(),
163 NULL
164 );
165
166 m_labels->Set(n, wnd, lblid);
6181cef5 167 }
6181cef5 168 m_labels->SetFont(GetFont());
5f605ccf
VZ
169 }
170
6181cef5
VZ
171 // now create the main control too
172 if ( !MSWCreateControl(TRACKBAR_CLASS, wxEmptyString, pos, size) )
173 return false;
5f605ccf 174
6181cef5
VZ
175 // and initialize everything
176 SetRange(minValue, maxValue);
177 SetValue(value);
178 SetPageSize((maxValue - minValue)/10);
822e690b 179
8a8dcc34
VZ
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
6181cef5
VZ
188 return true;
189}
2bda0e17 190
7d0d80bd 191WXDWORD wxSlider::MSWGetStyle(long style, WXDWORD *exstyle) const
6181cef5
VZ
192{
193 WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
b0766406 194
10f80f9b 195 // TBS_HORZ, TBS_RIGHT and TBS_BOTTOM are 0 but do include them for clarity
6181cef5
VZ
196 msStyle |= style & wxSL_VERTICAL ? TBS_VERT : TBS_HORZ;
197
10f80f9b 198 if ( style & wxSL_BOTH )
cbc6af74
VZ
199 {
200 // this fully specifies the style combined with TBS_VERT/HORZ above
5f605ccf 201 msStyle |= TBS_BOTH;
cbc6af74
VZ
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 }
10f80f9b
VZ
214
215 if ( style & wxSL_AUTOTICKS )
216 msStyle |= TBS_AUTOTICKS;
217 else
5f605ccf 218 msStyle |= TBS_NOTICKS;
2bda0e17 219
6181cef5 220 if ( style & wxSL_SELRANGE )
5f605ccf 221 msStyle |= TBS_ENABLESELRANGE;
2bda0e17 222
6181cef5
VZ
223 return msStyle;
224}
7a5a5718 225
7d0d80bd 226wxSlider::~wxSlider()
6181cef5
VZ
227{
228 delete m_labels;
2bda0e17
KB
229}
230
6181cef5
VZ
231// ----------------------------------------------------------------------------
232// event handling
233// ----------------------------------------------------------------------------
234
7d0d80bd
WS
235bool wxSlider::MSWOnScroll(int WXUNUSED(orientation),
236 WXWORD wParam,
237 WXWORD WXUNUSED(pos),
238 WXHWND control)
2bda0e17 239{
1e6feb95 240 wxEventType scrollEvent;
2bda0e17
KB
241 switch ( wParam )
242 {
a23fd0e1 243 case SB_TOP:
a23fd0e1
VZ
244 scrollEvent = wxEVT_SCROLL_TOP;
245 break;
246
247 case SB_BOTTOM:
a23fd0e1
VZ
248 scrollEvent = wxEVT_SCROLL_BOTTOM;
249 break;
250
251 case SB_LINEUP:
a23fd0e1
VZ
252 scrollEvent = wxEVT_SCROLL_LINEUP;
253 break;
254
255 case SB_LINEDOWN:
a23fd0e1
VZ
256 scrollEvent = wxEVT_SCROLL_LINEDOWN;
257 break;
258
259 case SB_PAGEUP:
a23fd0e1
VZ
260 scrollEvent = wxEVT_SCROLL_PAGEUP;
261 break;
262
263 case SB_PAGEDOWN:
a23fd0e1
VZ
264 scrollEvent = wxEVT_SCROLL_PAGEDOWN;
265 break;
266
267 case SB_THUMBTRACK:
a23fd0e1 268 scrollEvent = wxEVT_SCROLL_THUMBTRACK;
3c96417a 269 m_isDragging = true;
a23fd0e1
VZ
270 break;
271
e8b669d3 272 case SB_THUMBPOSITION:
3c96417a
VZ
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 }
e8b669d3
VZ
288 break;
289
290 case SB_ENDSCROLL:
cbc85508 291 scrollEvent = wxEVT_SCROLL_CHANGED;
e8b669d3
VZ
292 break;
293
a23fd0e1 294 default:
1e6feb95 295 // unknown scroll event?
822e690b 296 return false;
2bda0e17
KB
297 }
298
01526d4f 299 int newPos = ValueInvertOrNot((int) ::SendMessage((HWND) control, TBM_GETPOS, 0, 0));
a23fd0e1 300 if ( (newPos < GetMin()) || (newPos > GetMax()) )
2bda0e17 301 {
a23fd0e1 302 // out of range - but we did process it
822e690b 303 return true;
a23fd0e1 304 }
2bda0e17 305
a23fd0e1 306 SetValue(newPos);
2bda0e17 307
a23fd0e1
VZ
308 wxScrollEvent event(scrollEvent, m_windowId);
309 event.SetPosition(newPos);
310 event.SetEventObject( this );
937013e0 311 HandleWindowEvent(event);
f3a65071 312
a23fd0e1 313 wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, GetId() );
f6bcfd97 314 cevent.SetInt( newPos );
a23fd0e1 315 cevent.SetEventObject( this );
f3a65071 316
937013e0 317 return HandleWindowEvent( cevent );
2bda0e17
KB
318}
319
7d0d80bd 320void wxSlider::Command (wxCommandEvent & event)
2bda0e17 321{
6181cef5
VZ
322 SetValue (event.GetInt());
323 ProcessCommand (event);
2bda0e17
KB
324}
325
6181cef5
VZ
326// ----------------------------------------------------------------------------
327// geometry stuff
328// ----------------------------------------------------------------------------
2bda0e17 329
7d0d80bd 330wxRect wxSlider::GetBoundingBox() const
2bda0e17 331{
6181cef5
VZ
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);
5f605ccf 336
6181cef5
VZ
337 wxRect rect(x, y, w, h);
338 if ( m_labels )
b5c45059
RD
339 {
340 wxRect lrect = m_labels->GetBoundingBox();
341 GetParent()->ScreenToClient(&lrect.x, &lrect.y);
342 rect.Union(lrect);
343 }
6181cef5
VZ
344
345 return rect;
5f605ccf
VZ
346}
347
7d0d80bd 348void wxSlider::DoGetSize(int *width, int *height) const
2bda0e17 349{
6181cef5 350 wxRect rect = GetBoundingBox();
5f605ccf 351
6819fb9b 352 if ( width )
6181cef5 353 *width = rect.width;
6819fb9b 354 if ( height )
6181cef5 355 *height = rect.height;
2bda0e17
KB
356}
357
7d0d80bd 358void wxSlider::DoGetPosition(int *x, int *y) const
2bda0e17 359{
6181cef5 360 wxRect rect = GetBoundingBox();
5f605ccf 361
6181cef5
VZ
362 if ( x )
363 *x = rect.x;
364 if ( y )
365 *y = rect.y;
366}
5f605ccf 367
ce0ee9ae 368int wxSlider::GetLabelsSize(int *widthMin, int *widthMax) const
6181cef5 369{
ce0ee9ae 370 if ( widthMin && widthMax )
5f605ccf 371 {
16e79d48
VZ
372 *widthMin = GetTextExtent(Format(m_rangeMin)).x;
373 *widthMax = GetTextExtent(Format(m_rangeMax)).x;
5f605ccf
VZ
374 }
375
ce0ee9ae 376 return HasFlag(wxSL_LABELS) ? GetCharHeight() : 0;
2bda0e17
KB
377}
378
7d0d80bd 379void wxSlider::DoMoveWindow(int x, int y, int width, int height)
2bda0e17 380{
6181cef5
VZ
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 }
2bda0e17 388
5db90253
VZ
389 int minLabelWidth,
390 maxLabelWidth;
391 const int labelHeight = GetLabelsSize(&minLabelWidth, &maxLabelWidth);
392 const int longestLabelWidth = wxMax(minLabelWidth, maxLabelWidth);
16e79d48
VZ
393 if ( !HasFlag(wxSL_MIN_MAX_LABELS) )
394 {
395 minLabelWidth =
396 maxLabelWidth = 0;
397 }
ce0ee9ae
VZ
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
8a8dcc34
VZ
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
6181cef5
VZ
409 if ( HasFlag(wxSL_VERTICAL) )
410 {
ce0ee9ae
VZ
411 int holdTopWidth;
412 int holdTopX;
413 int holdBottomWidth;
414 int holdBottomX;
5db90253
VZ
415 int xLabel = (wxMax((THUMB + (BORDERPAD * 2)), longestLabelWidth) / 2) -
416 (longestLabelWidth / 2) + x;
ce0ee9ae
VZ
417 if ( HasFlag(wxSL_LEFT) )
418 {
419 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
420 {
421 holdTopX = xLabel;
5db90253
VZ
422 holdTopWidth = minLabelWidth;
423 holdBottomX = xLabel - ((maxLabelWidth - minLabelWidth) / 2);
424 holdBottomWidth = maxLabelWidth;
ce0ee9ae
VZ
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,
5db90253 443 longestLabelWidth, labelHeight);
ce0ee9ae
VZ
444 }
445 else // wxSL_RIGHT
446 {
447 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
448 {
5db90253
VZ
449 holdTopX = xLabel + longestLabelWidth + ((maxLabelWidth - minLabelWidth) / 2);
450 holdTopWidth = minLabelWidth;
451 holdBottomX = xLabel + longestLabelWidth;
452 holdBottomWidth = maxLabelWidth;
ce0ee9ae
VZ
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) )
5db90253 468 labelOffset = longestLabelWidth + HGAP;
ce0ee9ae
VZ
469 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
470 x,
471 y + (height - labelHeight)/2,
5db90253 472 longestLabelWidth, labelHeight);
ce0ee9ae 473 }
8a8dcc34
VZ
474
475 // position the slider itself along the left/right edge
ce0ee9ae
VZ
476 wxSliderBase::DoMoveWindow(
477 x + labelOffset,
478 y + labelHeight,
479 THUMB + tickOffset + HGAP,
480 height - (labelHeight * 2));
a23fd0e1 481 }
6181cef5 482 else // horizontal
2bda0e17 483 {
ce0ee9ae
VZ
484 int holdLeftWidth;
485 int holdLeftX;
486 int holdRightWidth;
487 int holdRightX;
488 int yLabelMinMax =
489 (y + ((THUMB + tickOffset) / 2)) - (labelHeight / 2);
490 int xLabelValue =
5db90253
VZ
491 x + minLabelWidth +
492 ((width - (minLabelWidth + maxLabelWidth)) / 2) -
b748750e 493 (longestLabelWidth / 2);
ce0ee9ae 494
c12d4e1d
VZ
495 int ySlider = y;
496
ce0ee9ae
VZ
497 if ( HasFlag(wxSL_BOTTOM) )
498 {
c12d4e1d
VZ
499 if ( HasFlag(wxSL_VALUE_LABEL) )
500 {
501 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
502 xLabelValue,
503 y,
5db90253 504 longestLabelWidth, labelHeight);
c12d4e1d
VZ
505
506 ySlider += labelHeight;
507 yLabelMinMax += labelHeight;
508 }
509
ce0ee9ae
VZ
510 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
511 {
512 holdLeftX = x;
5db90253
VZ
513 holdLeftWidth = minLabelWidth;
514 holdRightX = x + width - maxLabelWidth;
515 holdRightWidth = maxLabelWidth;
ce0ee9ae
VZ
516 if ( HasFlag(wxSL_INVERSE) )
517 {
518 wxSwap(holdLeftWidth, holdRightWidth);
519 wxSwap(holdLeftX, holdRightX);
520 }
521 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
522 holdLeftX,
523 yLabelMinMax,
524 holdLeftWidth, labelHeight);
525 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
526 holdRightX,
527 yLabelMinMax,
528 holdRightWidth, labelHeight);
529 }
c12d4e1d
VZ
530 }
531 else // wxSL_TOP
532 {
ce0ee9ae
VZ
533 if ( HasFlag(wxSL_VALUE_LABEL) )
534 {
535 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value],
536 xLabelValue,
c12d4e1d 537 y + THUMB + tickOffset,
5db90253 538 longestLabelWidth, labelHeight);
ce0ee9ae 539 }
c12d4e1d 540
ce0ee9ae
VZ
541 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
542 {
543 holdLeftX = x;
5db90253
VZ
544 holdLeftWidth = minLabelWidth;
545 holdRightX = x + width - maxLabelWidth;
546 holdRightWidth = maxLabelWidth;
ce0ee9ae
VZ
547 if ( HasFlag(wxSL_INVERSE) )
548 {
549 wxSwap(holdLeftWidth, holdRightWidth);
550 wxSwap(holdLeftX, holdRightX);
551 }
552 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min],
553 holdLeftX,
554 yLabelMinMax,
555 holdLeftWidth, labelHeight);
556 DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max],
557 holdRightX,
558 yLabelMinMax,
559 holdRightWidth, labelHeight);
560 }
ce0ee9ae 561 }
8a8dcc34
VZ
562
563 // position the slider itself along the top/bottom edge
ce0ee9ae
VZ
564 if ( HasFlag(wxSL_MIN_MAX_LABELS) || HasFlag(wxSL_VALUE_LABEL) )
565 labelOffset = labelHeight;
566 wxSliderBase::DoMoveWindow(
5db90253 567 x + minLabelWidth + VGAP,
c12d4e1d 568 ySlider,
5db90253 569 width - (minLabelWidth + maxLabelWidth + (VGAP*2)),
ce0ee9ae 570 THUMB + tickOffset);
8e44f3ca 571 }
2bda0e17
KB
572}
573
7d0d80bd 574wxSize wxSlider::DoGetBestSize() const
7bdfb981 575{
ce0ee9ae 576 // this value is arbitrary:
6181cef5 577 static const int length = 100;
57f4f925 578
cbc6af74 579 int *width;
6181cef5
VZ
580 wxSize size;
581 if ( HasFlag(wxSL_VERTICAL) )
7bdfb981 582 {
ce0ee9ae 583 size.x = THUMB;
6181cef5 584 size.y = length;
cbc6af74 585 width = &size.x;
57f4f925 586
6181cef5 587 if ( m_labels )
7bdfb981 588 {
ce0ee9ae
VZ
589 int widthMin,
590 widthMax;
591 int hLabel = GetLabelsSize(&widthMin, &widthMax);
7bdfb981 592
6181cef5 593 // account for the labels
16e79d48
VZ
594 if ( HasFlag(wxSL_MIN_MAX_LABELS) )
595 size.x += HGAP + wxMax(widthMin, widthMax);
6181cef5
VZ
596
597 // labels are indented relative to the slider itself
598 size.y += hLabel;
7bdfb981
RD
599 }
600 }
6181cef5 601 else // horizontal
7bdfb981 602 {
6181cef5 603 size.x = length;
ce0ee9ae 604 size.y = THUMB;
cbc6af74 605 width = &size.y;
7bdfb981 606
6181cef5 607 if ( m_labels )
7bdfb981 608 {
ce0ee9ae 609 int labelSize = GetLabelsSize();
c12d4e1d
VZ
610
611 // Min/max labels are compensated by the ticks so we don't need
612 // extra space for them if we're also showing ticks.
613 if ( HasFlag(wxSL_MIN_MAX_LABELS) && !HasFlag(wxSL_TICKS) )
ce0ee9ae 614 size.y += labelSize;
c12d4e1d
VZ
615
616 // The value label is always on top of the control and so does need
617 // extra space in any case.
ce0ee9ae 618 if ( HasFlag(wxSL_VALUE_LABEL) )
c12d4e1d 619 size.y += labelSize;
7bdfb981
RD
620 }
621 }
6181cef5 622
cbc6af74
VZ
623 // need extra space to show ticks
624 if ( HasFlag(wxSL_TICKS) )
625 {
ce0ee9ae 626 *width += TICK;
cbc6af74
VZ
627 // and maybe twice as much if we show them on both sides
628 if ( HasFlag(wxSL_BOTH) )
ce0ee9ae 629 *width += TICK;
cbc6af74 630 }
6181cef5 631 return size;
7bdfb981
RD
632}
633
6181cef5
VZ
634// ----------------------------------------------------------------------------
635// slider-specific methods
636// ----------------------------------------------------------------------------
637
7d0d80bd 638int wxSlider::GetValue() const
6181cef5 639{
01526d4f 640 return ValueInvertOrNot(::SendMessage(GetHwnd(), TBM_GETPOS, 0, 0));
6181cef5
VZ
641}
642
7d0d80bd 643void wxSlider::SetValue(int value)
6181cef5 644{
01526d4f 645 ::SendMessage(GetHwnd(), TBM_SETPOS, (WPARAM)TRUE, (LPARAM)ValueInvertOrNot(value));
6181cef5 646
ce0ee9ae 647 if ( m_labels )
6181cef5 648 {
e0a050e3 649 ::SetWindowText((*m_labels)[SliderLabel_Value], Format(value).wx_str());
6181cef5
VZ
650 }
651}
7bdfb981 652
7d0d80bd 653void wxSlider::SetRange(int minValue, int maxValue)
2bda0e17 654{
d383f40e
VZ
655 // Remember the old logical value if we need to update the physical control
656 // value after changing its range in wxSL_INVERSE case (and avoid an
657 // unnecessary call to GetValue() otherwise as it's just not needed).
658 const int valueOld = HasFlag(wxSL_INVERSE) ? GetValue() : 0;
659
5f605ccf
VZ
660 m_rangeMin = minValue;
661 m_rangeMax = maxValue;
662
b552060a
WS
663 ::SendMessage(GetHwnd(), TBM_SETRANGEMIN, TRUE, m_rangeMin);
664 ::SendMessage(GetHwnd(), TBM_SETRANGEMAX, TRUE, m_rangeMax);
5f605ccf 665
ce0ee9ae 666 if ( m_labels )
5f605ccf 667 {
e0a050e3
VS
668 ::SetWindowText((*m_labels)[SliderLabel_Min],
669 Format(ValueInvertOrNot(m_rangeMin)).wx_str());
670 ::SetWindowText((*m_labels)[SliderLabel_Max],
671 Format(ValueInvertOrNot(m_rangeMax)).wx_str());
5f605ccf 672 }
d383f40e
VZ
673
674 // When emulating wxSL_INVERSE style in wxWidgets, we need to update the
675 // value after changing the range to ensure that the value seen by the user
676 // code, i.e. the one returned by GetValue(), does not change.
677 if ( HasFlag(wxSL_INVERSE) )
678 {
679 ::SendMessage(GetHwnd(), TBM_SETPOS, TRUE, ValueInvertOrNot(valueOld));
680 }
2bda0e17
KB
681}
682
0a12e013 683void wxSlider::DoSetTickFreq(int n)
2bda0e17 684{
6181cef5 685 m_tickFreq = n;
0a12e013 686 ::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) 0 );
2bda0e17
KB
687}
688
7d0d80bd 689void wxSlider::SetPageSize(int pageSize)
2bda0e17 690{
6181cef5
VZ
691 ::SendMessage( GetHwnd(), TBM_SETPAGESIZE, (WPARAM) 0, (LPARAM) pageSize );
692 m_pageSize = pageSize;
2bda0e17
KB
693}
694
7d0d80bd 695int wxSlider::GetPageSize() const
2bda0e17 696{
6181cef5 697 return m_pageSize;
2bda0e17
KB
698}
699
7d0d80bd 700void wxSlider::ClearSel()
2bda0e17 701{
6181cef5 702 ::SendMessage(GetHwnd(), TBM_CLEARSEL, (WPARAM) TRUE, (LPARAM) 0);
2bda0e17
KB
703}
704
7d0d80bd 705void wxSlider::ClearTicks()
2bda0e17 706{
6181cef5 707 ::SendMessage(GetHwnd(), TBM_CLEARTICS, (WPARAM) TRUE, (LPARAM) 0);
2bda0e17
KB
708}
709
7d0d80bd 710void wxSlider::SetLineSize(int lineSize)
2bda0e17 711{
5f605ccf 712 m_lineSize = lineSize;
6181cef5 713 ::SendMessage(GetHwnd(), TBM_SETLINESIZE, (WPARAM) 0, (LPARAM) lineSize);
2bda0e17
KB
714}
715
7d0d80bd 716int wxSlider::GetLineSize() const
2bda0e17 717{
6181cef5 718 return (int)::SendMessage(GetHwnd(), TBM_GETLINESIZE, 0, 0);
2bda0e17
KB
719}
720
7d0d80bd 721int wxSlider::GetSelEnd() const
2bda0e17 722{
0a936028 723 return (int)::SendMessage(GetHwnd(), TBM_GETSELEND, 0, 0);
2bda0e17
KB
724}
725
7d0d80bd 726int wxSlider::GetSelStart() const
2bda0e17 727{
6181cef5 728 return (int)::SendMessage(GetHwnd(), TBM_GETSELSTART, 0, 0);
2bda0e17
KB
729}
730
7d0d80bd 731void wxSlider::SetSelection(int minPos, int maxPos)
2bda0e17 732{
5f605ccf 733 ::SendMessage(GetHwnd(), TBM_SETSEL,
6181cef5
VZ
734 (WPARAM) TRUE /* redraw */,
735 (LPARAM) MAKELONG( minPos, maxPos) );
2bda0e17
KB
736}
737
7d0d80bd 738void wxSlider::SetThumbLength(int len)
2bda0e17 739{
6181cef5 740 ::SendMessage(GetHwnd(), TBM_SETTHUMBLENGTH, (WPARAM) len, (LPARAM) 0);
2bda0e17
KB
741}
742
7d0d80bd 743int wxSlider::GetThumbLength() const
2bda0e17 744{
6bee5ffb 745 return (int)::SendMessage( GetHwnd(), TBM_GETTHUMBLENGTH, 0, 0);
2bda0e17
KB
746}
747
7d0d80bd 748void wxSlider::SetTick(int tickPos)
2bda0e17 749{
6bee5ffb 750 ::SendMessage( GetHwnd(), TBM_SETTIC, (WPARAM) 0, (LPARAM) tickPos );
2bda0e17
KB
751}
752
6181cef5
VZ
753// ----------------------------------------------------------------------------
754// composite control methods
755// ----------------------------------------------------------------------------
756
7d0d80bd 757WXHWND wxSlider::GetStaticMin() const
2bda0e17 758{
6181cef5 759 return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Min] : NULL;
2bda0e17
KB
760}
761
7d0d80bd 762WXHWND wxSlider::GetStaticMax() const
2bda0e17 763{
6181cef5 764 return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Max] : NULL;
2bda0e17
KB
765}
766
7d0d80bd 767WXHWND wxSlider::GetEditValue() const
2bda0e17 768{
6181cef5
VZ
769 return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Value] : NULL;
770}
2bda0e17 771
7d0d80bd 772WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxSlider, wxSliderBase, m_labels)
8a8dcc34 773
1e6feb95 774#endif // wxUSE_SLIDER