1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:       wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #include "wx/wxprec.h" 
  16 #include "wx/slider.h" 
  17 #include "wx/mac/uma.h" 
  19 IMPLEMENT_DYNAMIC_CLASS(wxSlider
, wxControl
) 
  21 BEGIN_EVENT_TABLE(wxSlider
, wxControl
) 
  24  // The dimensions of the different styles of sliders (from Aqua document) 
  25 #define wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS 24 
  26 #define wxSLIDER_DIMENSIONACROSS_ARROW 18 
  28 // Distance between slider and text 
  29 #define wxSLIDER_BORDERTEXT 5 
  31 // NB: The default orientation for a slider is horizontal; however, if the user specifies 
  32 // some slider styles but doesn't specify the orientation we have to assume he wants a 
  33 // horizontal one. Therefore in this file when testing for the slider's orientation 
  34 // vertical is tested for if this is not set then we use the horizontal one 
  35 // e.g., if (GetWindowStyle() & wxSL_VERTICAL) {} else { horizontal case }. 
  45     m_macMinimumStatic 
= NULL
; 
  46     m_macMaximumStatic 
= NULL
; 
  47     m_macValueStatic 
= NULL
; 
  50 bool wxSlider::Create(wxWindow 
*parent
, 
  52     int value
, int minValue
, int maxValue
, 
  54     const wxSize
& size
, long style
, 
  55     const wxValidator
& validator
, 
  58     m_macIsUserPane 
= false; 
  60     m_macMinimumStatic 
= NULL
; 
  61     m_macMaximumStatic 
= NULL
; 
  62     m_macValueStatic 
= NULL
; 
  67     m_rangeMax 
= maxValue
; 
  68     m_rangeMin 
= minValue
; 
  70     m_pageSize 
= (int)((maxValue 
- minValue
) / 10); 
  72     // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and 
  73     // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility 
  74     // reasons we can't really change it, instead try to infer the orientation 
  75     // from the flags given to us here 
  76     switch ( style 
& (wxSL_LEFT 
| wxSL_RIGHT 
| wxSL_TOP 
| wxSL_BOTTOM
) ) 
  80             style 
|= wxSL_VERTICAL
; 
  85             style 
|= wxSL_HORIZONTAL
; 
  90             // no specific direction, do we have at least the orientation? 
  91             if ( !(style 
& (wxSL_HORIZONTAL 
| wxSL_VERTICAL
)) ) 
  93                 style 
|= wxSL_BOTTOM 
| wxSL_HORIZONTAL
; 
  97     wxASSERT_MSG( !(style 
& wxSL_VERTICAL
) || !(style 
& wxSL_HORIZONTAL
), 
  98         wxT("incompatible slider direction and orientation") ); 
 100     if ( !wxControl::Create(parent
, id
, pos
, size
, style
, validator
, name
) ) 
 103     Rect bounds 
= wxMacGetBoundsForControl( this , pos 
, size 
); 
 105     // NB: (RN) Ticks here are sometimes off in the GUI if there 
 106     // are not as many tick marks as there are values 
 109     if ( style 
& wxSL_AUTOTICKS 
) 
 110         tickMarks 
= (maxValue 
- minValue
) + 1; // +1 for the 0 value 
 112     // keep the number of tickmarks from becoming unwieldly, therefore below it is ok to cast 
 114     while (tickMarks 
> 20) 
 117     m_peer 
= new wxMacControl( this ); 
 118     OSStatus err 
= CreateSliderControl( 
 119         MAC_WXHWND(parent
->MacGetTopLevelWindowRef()), &bounds
, 
 120         value
, minValue
, maxValue
, 
 121         kControlSliderPointsDownOrRight
, 
 122         (UInt16
) tickMarks
, true /* liveTracking */, 
 123         GetwxMacLiveScrollbarActionProc(), 
 124         m_peer
->GetControlRefAddr() ); 
 127     if (style 
& wxSL_VERTICAL
) 
 128         // Forces SetSize to use the proper width 
 129         SetSizeHints(10, -1, 10, -1); 
 131         // Forces SetSize to use the proper height 
 132         SetSizeHints(-1, 10, -1, 10); 
 134     // NB: SetSizeHints is overloaded by wxSlider and will substitute 10 with the 
 135     // proper dimensions, it also means other people cannot bugger the slider with 
 138     if (style 
& wxSL_LABELS
) 
 140         m_macMinimumStatic 
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString 
); 
 141         m_macMaximumStatic 
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString 
); 
 142         m_macValueStatic 
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString 
); 
 145     SetRange(minValue
, maxValue
); 
 148     MacPostControlCreate(pos
, size
); 
 153 wxSlider::~wxSlider() 
 155     // this is a special case, as we had to add windows as siblings we are 
 156     // responsible for their disposal, but only if we are not part of a DestroyAllChildren 
 157     if ( m_parent 
&& !m_parent
->IsBeingDeleted() ) 
 159         delete m_macMinimumStatic
; 
 160         delete m_macMaximumStatic
; 
 161         delete m_macValueStatic
; 
 165 int wxSlider::GetValue() const 
 167     // We may need to invert the value returned by the widget 
 168     return ValueInvertOrNot( m_peer
->GetValue() ) ; 
 171 void wxSlider::SetValue(int value
) 
 173     if ( m_macValueStatic 
) 
 175         wxString valuestring
; 
 176         valuestring
.Printf( wxT("%d"), value 
); 
 177         m_macValueStatic
->SetLabel( valuestring 
); 
 180     // We only invert for the setting of the actual native widget 
 181     m_peer
->SetValue( ValueInvertOrNot( value 
) ); 
 184 void wxSlider::SetRange(int minValue
, int maxValue
) 
 188     m_rangeMin 
= minValue
; 
 189     m_rangeMax 
= maxValue
; 
 191     m_peer
->SetMinimum( m_rangeMin 
); 
 192     m_peer
->SetMaximum( m_rangeMax 
); 
 194     if (m_macMinimumStatic
) 
 196         value
.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMin 
) ); 
 197         m_macMinimumStatic
->SetLabel( value 
); 
 200     if (m_macMaximumStatic
) 
 202         value
.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMax 
) ); 
 203         m_macMaximumStatic
->SetLabel( value 
); 
 206     // If the range is out of bounds, set it to a  
 207     // value that is within bounds 
 208     // RN: Testing reveals OSX does its own  
 209     // bounding, perhaps this isn't needed? 
 210     int currentValue 
= GetValue(); 
 212     if(currentValue 
< m_rangeMin
) 
 213         SetValue(m_rangeMin
); 
 214     else if(currentValue 
> m_rangeMax
) 
 215         SetValue(m_rangeMax
); 
 218 // For trackbars only 
 219 void wxSlider::SetTickFreq(int n
, int pos
) 
 225 void wxSlider::SetPageSize(int pageSize
) 
 228     m_pageSize 
= pageSize
; 
 231 int wxSlider::GetPageSize() const 
 236 void wxSlider::ClearSel() 
 241 void wxSlider::ClearTicks() 
 246 void wxSlider::SetLineSize(int lineSize
) 
 248     m_lineSize 
= lineSize
; 
 252 int wxSlider::GetLineSize() const 
 258 int wxSlider::GetSelEnd() const 
 264 int wxSlider::GetSelStart() const 
 270 void wxSlider::SetSelection(int minPos
, int maxPos
) 
 275 void wxSlider::SetThumbLength(int len
) 
 280 int wxSlider::GetThumbLength() const 
 286 void wxSlider::SetTick(int tickPos
) 
 291 void wxSlider::Command(wxCommandEvent 
&event
) 
 293     SetValue(event
.GetInt()); 
 294     ProcessCommand(event
); 
 297 void wxSlider::MacHandleControlClick( WXWidget control
, wxInt16 controlpart
, bool mouseStillDown 
) 
 299     // Whatever the native value is, we may need to invert it for calling 
 300     // SetValue and putting the possibly inverted value in the event 
 301     int value 
= ValueInvertOrNot( m_peer
->GetValue() ); 
 305     wxScrollEvent 
event( wxEVT_SCROLL_THUMBTRACK
, m_windowId 
); 
 306     event
.SetPosition( value 
); 
 307     event
.SetEventObject( this ); 
 308     GetEventHandler()->ProcessEvent( event 
); 
 310     wxCommandEvent 
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId 
); 
 311     cevent
.SetInt( value 
); 
 312     cevent
.SetEventObject( this ); 
 313     GetEventHandler()->ProcessEvent( cevent 
); 
 316 wxInt32 
wxSlider::MacControlHit( WXEVENTHANDLERREF handler 
, WXEVENTREF mevent 
) 
 318     // Whatever the native value is, we may need to invert it for calling 
 319     // SetValue and putting the possibly inverted value in the event 
 320     int value 
= ValueInvertOrNot( m_peer
->GetValue() ) ; 
 324     wxScrollEvent 
event( wxEVT_SCROLL_THUMBRELEASE
, m_windowId 
); 
 325     event
.SetPosition( value 
); 
 326     event
.SetEventObject( this ); 
 327     GetEventHandler()->ProcessEvent( event 
); 
 329     wxCommandEvent 
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId 
); 
 330     cevent
.SetInt( value 
); 
 331     cevent
.SetEventObject( this ); 
 333     GetEventHandler()->ProcessEvent( cevent 
); 
 338 // This is overloaded in wxSlider so that the proper width/height will always be used 
 339 // for the slider different values would cause redrawing and mouse detection problems 
 341 void wxSlider::DoSetSizeHints( int minW
, int minH
, 
 345     wxSize size 
= GetBestSize(); 
 347     if (GetWindowStyle() & wxSL_VERTICAL
) 
 349         SetMinSize( wxSize(size
.x
,minH
) ); 
 350         SetMaxSize( wxSize(size
.x
,maxH
) ); 
 354         SetMinSize( wxSize(minW
,size
.y
) ); 
 355         SetMaxSize( wxSize(maxW
,size
.y
) ); 
 359 wxSize 
wxSlider::DoGetBestSize() const 
 362     int textwidth
, textheight
; 
 363     int mintwidth
, mintheight
; 
 364     int maxtwidth
, maxtheight
; 
 366     textwidth 
= textheight 
= 0; 
 367     mintwidth 
= mintheight 
= 0; 
 368     maxtwidth 
= maxtheight 
= 0; 
 370     if (GetWindowStyle() & wxSL_LABELS
) 
 374         // Get maximum text label width and height 
 375         text
.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMin 
) ); 
 376         GetTextExtent(text
, &mintwidth
, &mintheight
); 
 377         text
.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMax 
) ); 
 378         GetTextExtent(text
, &maxtwidth
, &maxtheight
); 
 380         if (maxtheight 
> mintheight
) 
 381             textheight 
= maxtheight
; 
 383             textheight 
= mintheight
; 
 385         if (maxtwidth 
> mintwidth
) 
 386             textwidth 
= maxtwidth
; 
 388             textwidth 
= mintwidth
; 
 391     if (GetWindowStyle() & wxSL_VERTICAL
) 
 395         if (GetWindowStyle() & wxSL_AUTOTICKS
) 
 396             size
.x 
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
; 
 398             size
.x 
= wxSLIDER_DIMENSIONACROSS_ARROW
; 
 400         if (GetWindowStyle() & wxSL_LABELS
) 
 401             size
.x 
+= textwidth 
+ wxSLIDER_BORDERTEXT
; 
 407         if (GetWindowStyle() & wxSL_AUTOTICKS
) 
 408             size
.y 
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
; 
 410             size
.y 
= wxSLIDER_DIMENSIONACROSS_ARROW
; 
 412         if (GetWindowStyle() & wxSL_LABELS
) 
 414             size
.y 
+= textheight 
+ wxSLIDER_BORDERTEXT
; 
 415             size
.x 
+= (mintwidth 
/ 2) + (maxtwidth 
/ 2); 
 422 void wxSlider::DoSetSize(int x
, int y
, int w
, int h
, int sizeFlags
) 
 425     int minValWidth
, maxValWidth
, textheight
; 
 429     if (GetWindowStyle() & wxSL_LABELS
) 
 434         // Get maximum text label width and height 
 435         text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin 
) ); 
 436         GetTextExtent(text
, &minValWidth
, &textheight
); 
 437         text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax 
) ); 
 438         GetTextExtent(text
, &maxValWidth
, &ht
); 
 443         if (GetWindowStyle() & wxSL_HORIZONTAL
) 
 445             if ( m_macMinimumStatic 
) 
 447                 w 
-= minValWidth 
/ 2; 
 448                 x 
+= minValWidth 
/ 2; 
 451             if ( m_macMaximumStatic 
) 
 452                 w 
-= maxValWidth 
/ 2; 
 455         // Labels have this control's parent as their parent 
 456         // so if this control is not at 0,0 relative to the parent 
 457         // the labels need to know the position of this control 
 458         // relative to its parent in order to size properly, so 
 459         // move the control first so we can use GetPosition() 
 460         wxControl::DoSetSize( x
, y
, w
, h
, sizeFlags 
); 
 462         if (GetWindowStyle() & wxSL_VERTICAL
) 
 463             // If vertical, use current value 
 464             text
.Printf(wxT("%d"), (int)m_peer
->GetValue()); 
 466             // Use max so that the current value doesn't drift as centering would need to change 
 467             text
.Printf(wxT("%d"), m_rangeMax
); 
 469         GetTextExtent(text
, &valValWidth
, &ht
); 
 471         yborder 
= textheight 
+ wxSLIDER_BORDERTEXT
; 
 473         // Get slider breadth 
 474         if (GetWindowStyle() & wxSL_AUTOTICKS
) 
 475             sliderBreadth 
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
; 
 477             sliderBreadth 
= wxSLIDER_DIMENSIONACROSS_ARROW
; 
 479         if (GetWindowStyle() & wxSL_VERTICAL
) 
 483             if ( m_macMinimumStatic 
) 
 484                 m_macMinimumStatic
->Move(GetPosition().x 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
, GetPosition().y 
+ h 
- yborder
); 
 485             if ( m_macMaximumStatic 
) 
 486                 m_macMaximumStatic
->Move(GetPosition().x 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
, GetPosition().y 
+ 0); 
 487             if ( m_macValueStatic 
) 
 488                 m_macValueStatic
->Move(GetPosition().x 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
, GetPosition().y 
+ (h 
/ 2) - (ht 
/ 2)); 
 492             if ( m_macMinimumStatic 
) 
 493                 m_macMinimumStatic
->Move(GetPosition().x
, GetPosition().y 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
); 
 494             if ( m_macMaximumStatic 
) 
 495                  m_macMaximumStatic
->Move(GetPosition().x 
+ w 
- maxValWidth
, GetPosition().y 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
); 
 496             if ( m_macValueStatic 
) 
 497                 m_macValueStatic
->Move(GetPosition().x 
+ (w 
/ 2) - (valValWidth 
/ 2), GetPosition().y 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
); 
 501     // yet another hack since this is a composite control 
 502     // when wxSlider has it's size hardcoded, we're not allowed to 
 503     // change the size. But when the control has labels, we DO need 
 504     // to resize the internal Mac control to accommodate the text labels. 
 505     // We need to trick the wxWidgets resize mechanism so that we can 
 506     // resize the slider part of the control ONLY. 
 508     // TODO: Can all of this code go in the conditional wxSL_LABELS block? 
 510     int minWidth 
= m_minWidth
; 
 512     if (GetWindowStyle() & wxSL_LABELS
) 
 514         // make sure we don't allow the entire control to be resized accidently 
 515         if (width 
== GetSize().x
) 
 519     // If the control has labels, we still need to call this again because 
 520     // the labels alter the control's w and h values. 
 521     wxControl::DoSetSize( x
, y
, w
, h
, sizeFlags 
); 
 523     m_minWidth 
= minWidth
; 
 526 void wxSlider::DoMoveWindow(int x
, int y
, int width
, int height
) 
 528     wxControl::DoMoveWindow( x
, y
, width
, height 
); 
 531 // Common processing to invert slider values based on wxSL_INVERSE 
 532 int wxSlider::ValueInvertOrNot(int value
) const 
 536     if (m_windowStyle 
& wxSL_VERTICAL
) 
 538         // The reason for the backwards logic is that Mac's vertical sliders are 
 539         // inverted compared to Windows and GTK, hence we want inversion to be the 
 540         // default, and if wxSL_INVERSE is set, then we do not invert (use native) 
 541         if (m_windowStyle 
& wxSL_INVERSE
) 
 544             result 
= (m_rangeMax 
+ m_rangeMin
) - value
; 
 546     else // normal logic applies to HORIZONTAL sliders 
 548         result 
= wxSliderBase::ValueInvertOrNot(value
); 
 554 #endif // wxUSE_SLIDER