1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Stefan Csomor 
   8 // Copyright:   (c) Stefan Csomor 
   9 // Licence:       wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  13 #pragma implementation "slider.h" 
  16 #include "wx/wxprec.h" 
  20 #include "wx/slider.h" 
  21 #include "wx/mac/uma.h" 
  23 IMPLEMENT_DYNAMIC_CLASS(wxSlider
, wxControl
) 
  25 BEGIN_EVENT_TABLE(wxSlider
, wxControl
) 
  28  // The dimensions of the different styles of sliders (From Aqua document) 
  29 #define wxSLIDER_DIMENSIONACROSS 15 
  30 #define wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS 24 
  31 #define wxSLIDER_DIMENSIONACROSS_ARROW 18 
  33 // Distance between slider and text 
  34 #define wxSLIDER_BORDERTEXT 5 
  36 /* NB!  The default orientation for a slider is horizontal however if the user specifies 
  37  * some slider styles but dosen't specify the orientation we have to assume he wants a 
  38  * horizontal one.  Therefore in this file when testing for the sliders orientation 
  39  * vertical is tested for if this is not set then we use the horizontal one 
  40  * eg.  if(GetWindowStyle() & wxSL_VERTICAL) {}  else { horizontal case }> 
  53 bool wxSlider::Create(wxWindow 
*parent
, wxWindowID id
, 
  54                       int value
, int minValue
, int maxValue
, 
  56                       const wxSize
& size
, long style
, 
  57                       const wxValidator
& validator
, 
  60     m_macIsUserPane 
= false ; 
  62     if ( !wxControl::Create(parent
, id
, pos
, size
, style
, validator
, name
) ) 
  65     m_macMinimumStatic 
= NULL 
; 
  66     m_macMaximumStatic 
= NULL 
; 
  67     m_macValueStatic 
= NULL 
; 
  72     m_rangeMax 
= maxValue
; 
  73     m_rangeMin 
= minValue
; 
  75     m_pageSize 
= (int)((maxValue
-minValue
)/10); 
  77     Rect bounds 
= wxMacGetBoundsForControl( this , pos 
, size 
) ; 
  80     // NB: (RN) Ticks here are sometimes off in the GUI if there 
  81     // is not as many ticks as there are values 
  83     UInt16 tickMarks 
= 0 ; 
  84     if ( style 
& wxSL_AUTOTICKS 
) 
  85         tickMarks 
= (maxValue 
- minValue
) + 1; //+1 for the 0 value 
  87     while (tickMarks 
> 20) 
  88         tickMarks 
/= 5; //keep the number of tickmarks from becoming unwieldly 
  90     m_peer 
= new wxMacControl(this) ; 
  91     verify_noerr ( CreateSliderControl( MAC_WXHWND(parent
->MacGetTopLevelWindowRef()) , &bounds 
, 
  92         value 
, minValue 
, maxValue 
, kControlSliderPointsDownOrRight 
, tickMarks 
, true /* liveTracking */ , 
  93         GetwxMacLiveScrollbarActionProc() , m_peer
->GetControlRefAddr() ) ); 
  96     if(style 
& wxSL_VERTICAL
) { 
  97         SetSizeHints(10, -1, 10, -1);  // Forces SetSize to use the proper width 
 100         SetSizeHints(-1, 10, -1, 10);  // Forces SetSize to use the proper height 
 102     // NB!  SetSizeHints is overloaded by wxSlider and will substitute 10 with the 
 103     // proper dimensions, it also means other people cannot bugger the slider with 
 106     if(style 
& wxSL_LABELS
) 
 108         m_macMinimumStatic 
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString 
); 
 109         m_macMaximumStatic 
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString 
); 
 110         m_macValueStatic 
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString 
); 
 111         SetRange(minValue
, maxValue
); 
 115     MacPostControlCreate(pos
,size
) ; 
 120 wxSlider::~wxSlider() 
 122     // this is a special case, as we had to add windows as siblings we are 
 123     // responsible for their disposal, but only if we are not part of a DestroyAllChildren 
 124     if ( m_parent 
&& m_parent
->IsBeingDeleted() == false ) 
 126         delete m_macMinimumStatic 
; 
 127         delete m_macMaximumStatic 
; 
 128         delete m_macValueStatic 
; 
 132 int wxSlider::GetValue() const 
 134     // We may need to invert the value returned by the widget 
 135     return ValueInvertOrNot( m_peer
->GetValue() ) ; 
 138 void wxSlider::SetValue(int value
) 
 140     wxString valuestring 
; 
 141     valuestring
.Printf( wxT("%d") , value 
) ; 
 142     if ( m_macValueStatic 
) 
 143         m_macValueStatic
->SetLabel( valuestring 
) ; 
 145     // We only invert for the setting of the actual native widget 
 146     m_peer
->SetValue( ValueInvertOrNot ( value 
) ) ; 
 149 void wxSlider::SetRange(int minValue
, int maxValue
) 
 153     m_rangeMin 
= minValue
; 
 154     m_rangeMax 
= maxValue
; 
 156     m_peer
->SetMinimum( m_rangeMin
); 
 157     m_peer
->SetMaximum( m_rangeMax
); 
 159     if(m_macMinimumStatic
) { 
 160         value
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin 
) ); 
 161         m_macMinimumStatic
->SetLabel(value
); 
 163     if(m_macMaximumStatic
) { 
 164         value
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax 
) ); 
 165         m_macMaximumStatic
->SetLabel(value
); 
 167     SetValue(m_rangeMin
); 
 170 // For trackbars only 
 171 void wxSlider::SetTickFreq(int n
, int pos
) 
 177 void wxSlider::SetPageSize(int pageSize
) 
 180     m_pageSize 
= pageSize
; 
 183 int wxSlider::GetPageSize() const 
 188 void wxSlider::ClearSel() 
 193 void wxSlider::ClearTicks() 
 198 void wxSlider::SetLineSize(int lineSize
) 
 200     m_lineSize 
= lineSize
; 
 204 int wxSlider::GetLineSize() const 
 210 int wxSlider::GetSelEnd() const 
 216 int wxSlider::GetSelStart() const 
 222 void wxSlider::SetSelection(int minPos
, int maxPos
) 
 227 void wxSlider::SetThumbLength(int len
) 
 232 int wxSlider::GetThumbLength() const 
 238 void wxSlider::SetTick(int tickPos
) 
 243 void wxSlider::Command (wxCommandEvent 
& event
) 
 245     SetValue (event
.GetInt()); 
 246     ProcessCommand (event
); 
 249 void wxSlider::MacHandleControlClick( WXWidget control 
, wxInt16 controlpart
, bool mouseStillDown 
) 
 251     // Whatever the native value is, we may need to invert it for calling 
 252     // SetValue and putting the possibly inverted value in the event 
 253     SInt16 value 
= ValueInvertOrNot ( m_peer
->GetValue() ) ; 
 257     wxEventType scrollEvent 
= wxEVT_NULL 
; 
 259     scrollEvent 
= wxEVT_SCROLL_THUMBTRACK
; 
 261     wxScrollEvent 
event(scrollEvent
, m_windowId
); 
 262     event
.SetPosition(value
); 
 263     event
.SetEventObject( this ); 
 264     GetEventHandler()->ProcessEvent(event
); 
 266     wxCommandEvent 
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId 
); 
 267     cevent
.SetInt( value 
); 
 268     cevent
.SetEventObject( this ); 
 270     GetEventHandler()->ProcessEvent( cevent 
); 
 273 wxInt32 
wxSlider::MacControlHit( WXEVENTHANDLERREF handler 
, WXEVENTREF mevent 
) 
 275     // Whatever the native value is, we may need to invert it for calling 
 276     // SetValue and putting the possibly inverted value in the event 
 277     SInt16 value 
= ValueInvertOrNot ( m_peer
->GetValue() ) ; 
 281     wxEventType scrollEvent 
= wxEVT_NULL 
; 
 283     scrollEvent 
= wxEVT_SCROLL_THUMBRELEASE
; 
 285     wxScrollEvent 
event(scrollEvent
, m_windowId
); 
 286     event
.SetPosition(value
); 
 287     event
.SetEventObject( this ); 
 288     GetEventHandler()->ProcessEvent(event
); 
 290     wxCommandEvent 
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId 
); 
 291     cevent
.SetInt( value 
); 
 292     cevent
.SetEventObject( this ); 
 294     GetEventHandler()->ProcessEvent( cevent 
); 
 298 /* This is overloaded in wxSlider so that the proper width/height will always be used 
 299 * for the slider different values would cause redrawing and mouse detection problems */ 
 300 void wxSlider::DoSetSizeHints( int minW
, int minH
, 
 301                                int maxW 
, int maxH 
, 
 302                                int incW 
, int incH 
) 
 304     wxSize size 
= GetBestSize(); 
 306     if(GetWindowStyle() & wxSL_VERTICAL
) { 
 307         wxWindow::DoSetSizeHints(size
.x
, minH
, size
.x
, maxH
, incW
, incH
); 
 310         wxWindow::DoSetSizeHints(minW
, size
.y
, maxW
, size
.y
, incW
, incH
); 
 314 wxSize 
wxSlider::DoGetBestSize() const 
 317     int textwidth
, textheight
; 
 319     if(GetWindowStyle() & wxSL_LABELS
) 
 324         // Get maximum text label width and height 
 325         text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin 
) ); 
 326         GetTextExtent(text
, &textwidth
, &textheight
); 
 327         text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax 
) ); 
 328         GetTextExtent(text
, &wd
, &ht
); 
 329         if(ht 
> textheight
) { 
 332         if (wd 
> textwidth
) { 
 337     if(GetWindowStyle() & wxSL_VERTICAL
) 
 339         if(GetWindowStyle() & wxSL_AUTOTICKS
) { 
 340             size
.x 
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
; 
 343             size
.x 
= wxSLIDER_DIMENSIONACROSS_ARROW
; 
 345         if(GetWindowStyle() & wxSL_LABELS
) { 
 346             size
.x 
+= textwidth 
+ wxSLIDER_BORDERTEXT
; 
 352         if(GetWindowStyle() & wxSL_AUTOTICKS
) { 
 353             size
.y 
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
; 
 356             size
.y 
= wxSLIDER_DIMENSIONACROSS_ARROW
; 
 358         if(GetWindowStyle() & wxSL_LABELS
) { 
 359             size
.y 
+= textheight 
+ wxSLIDER_BORDERTEXT
; 
 366 void wxSlider::DoSetSize(int x
, int y
, int w
, int h
, int sizeFlags
) 
 368     int  xborder
, yborder
; 
 369     int  minValWidth
, maxValWidth
, textwidth
, textheight
; 
 373     xborder 
= yborder 
= 0; 
 375     if (GetWindowStyle() & wxSL_LABELS
) 
 377         //Labels have this control's parent as their parent 
 378         //so if this control is not at 0,0 relative to the parent 
 379         //the labels need to know the position of this control 
 380         //relative to its parent in order to size properly, so 
 381         //move the control first so we can use GetPosition() 
 382         wxControl::DoSetSize( x
, y 
, w 
, h 
,sizeFlags 
) ; 
 387         // Get maximum text label width and height 
 388         text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin 
) ); 
 389         GetTextExtent(text
, &minValWidth
, &textheight
); 
 390         text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax 
) ); 
 391         GetTextExtent(text
, &maxValWidth
, &ht
); 
 392         if(ht 
> textheight
) { 
 395         textwidth 
= (minValWidth 
> maxValWidth 
? minValWidth 
: maxValWidth
); 
 397         xborder 
= textwidth 
+ wxSLIDER_BORDERTEXT
; 
 398         yborder 
= textheight 
+ wxSLIDER_BORDERTEXT
; 
 400         // Get slider breadth 
 401         if(GetWindowStyle() & wxSL_AUTOTICKS
) { 
 402             sliderBreadth 
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
; 
 405             sliderBreadth 
= wxSLIDER_DIMENSIONACROSS_ARROW
; 
 408         if(GetWindowStyle() & wxSL_VERTICAL
) 
 412             if ( m_macMinimumStatic 
) 
 413                 m_macMinimumStatic
->Move(GetPosition().x 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
, 
 414                 GetPosition().y 
+ h 
- yborder
); 
 415             if ( m_macMaximumStatic 
) 
 416                 m_macMaximumStatic
->Move(GetPosition().x 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
, GetPosition().y 
+ 0); 
 417             if ( m_macValueStatic 
) 
 418                 m_macValueStatic
->Move(GetPosition().x
, GetPosition().y 
+ h 
); 
 423             if ( m_macMinimumStatic 
) 
 424                 m_macMinimumStatic
->Move(GetPosition().x 
+ 0, GetPosition().y 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
); 
 425             if ( m_macMaximumStatic 
) 
 426                 m_macMaximumStatic
->Move(GetPosition().x 
+ w 
- (maxValWidth
/2), 
 427                 GetPosition().y 
+ sliderBreadth 
+ wxSLIDER_BORDERTEXT
); 
 428             if ( m_macValueStatic 
) 
 429                 m_macValueStatic
->Move(GetPosition().x 
+ w
, GetPosition().y 
+ 0); 
 433     // yet another hack since this is a composite control 
 434     // when wxSlider has it's size hardcoded, we're not allowed to 
 435     // change the size. But when the control has labels, we DO need 
 436     // to resize the internal Mac control to accommodate the text labels. 
 437     // We need to trick the wxWidgets resize mechanism so that we can 
 438     // resize the slider part of the control ONLY. 
 440     // TODO: Can all of this code go in the conditional wxSL_LABELS block? 
 443     minWidth 
= m_minWidth
; 
 445     if (GetWindowStyle() & wxSL_LABELS
) 
 447         // make sure we don't allow the entire control to be resized accidently 
 448         if (width 
== GetSize().x
) 
 451     //If the control has labels, we still need to call this again because 
 452     //the labels alter the control's w and h values. 
 453     wxControl::DoSetSize( x
, y 
, w 
, h 
,sizeFlags 
) ; 
 455     m_minWidth 
= minWidth
; 
 458 void wxSlider::DoMoveWindow(int x
, int y
, int width
, int height
) 
 460     wxControl::DoMoveWindow(x
,y
,width
,height
) ; 
 463 // Common processing to invert slider values based on wxSL_INVERSE 
 464 int wxSlider::ValueInvertOrNot(int value
) const 
 466     if (m_windowStyle 
& wxSL_VERTICAL
) 
 468         // The reason for the backwards logic is that Mac's vertical sliders are 
 469         // inverted compared to Windows and GTK, hence we want inversion to be the 
 470         // default, and if wxSL_INVERSE is set, then we do not invert (use native) 
 471         if (m_windowStyle 
& wxSL_INVERSE
) 
 474             return (m_rangeMax 
+ m_rangeMin
) - value
; 
 476     else // normal logic applies to HORIZONTAL sliders 
 478         return wxSliderBase::ValueInvertOrNot(value
); 
 482 #endif // wxUSE_SLIDER