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