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 15
26 #define wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS 24
27 #define wxSLIDER_DIMENSIONACROSS_ARROW 18
29 // Distance between slider and text
30 #define wxSLIDER_BORDERTEXT 5
32 /* NB! The default orientation for a slider is horizontal however if the user specifies
33 * some slider styles but doesn't specify the orientation we have to assume he wants a
34 * horizontal one. Therefore in this file when testing for the slider's orientation
35 * vertical is tested for if this is not set then we use the horizontal one
36 * eg. if(GetWindowStyle() & wxSL_VERTICAL) {} else { horizontal case }>
49 bool wxSlider::Create(wxWindow
*parent
, wxWindowID id
,
50 int value
, int minValue
, int maxValue
,
52 const wxSize
& size
, long style
,
53 const wxValidator
& validator
,
56 m_macIsUserPane
= false ;
58 // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and
59 // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility
60 // reasons we can't really change it, instead try to infer the orientation
61 // from the flags given to us here
62 switch ( style
& (wxSL_LEFT
| wxSL_RIGHT
| wxSL_TOP
| wxSL_BOTTOM
) )
66 style
|= wxSL_VERTICAL
;
71 style
|= wxSL_HORIZONTAL
;
75 // no specific direction, do we have at least the orientation?
76 if ( !(style
& (wxSL_HORIZONTAL
| wxSL_VERTICAL
)) )
79 style
|= wxSL_BOTTOM
| wxSL_HORIZONTAL
;
83 wxASSERT_MSG( !(style
& wxSL_VERTICAL
) || !(style
& wxSL_HORIZONTAL
),
84 _T("incompatible slider direction and orientation") );
86 if ( !wxControl::Create(parent
, id
, pos
, size
, style
, validator
, name
) )
89 m_macMinimumStatic
= NULL
;
90 m_macMaximumStatic
= NULL
;
91 m_macValueStatic
= NULL
;
96 m_rangeMax
= maxValue
;
97 m_rangeMin
= minValue
;
99 m_pageSize
= (int)((maxValue
-minValue
)/10);
101 Rect bounds
= wxMacGetBoundsForControl( this , pos
, size
) ;
104 // NB: (RN) Ticks here are sometimes off in the GUI if there
105 // is not as many ticks as there are values
107 UInt16 tickMarks
= 0 ;
108 if ( style
& wxSL_AUTOTICKS
)
109 tickMarks
= (maxValue
- minValue
) + 1; //+1 for the 0 value
111 while (tickMarks
> 20)
112 tickMarks
/= 5; //keep the number of tickmarks from becoming unwieldly
114 m_peer
= new wxMacControl(this) ;
115 verify_noerr ( CreateSliderControl( MAC_WXHWND(parent
->MacGetTopLevelWindowRef()) , &bounds
,
116 value
, minValue
, maxValue
, kControlSliderPointsDownOrRight
, tickMarks
, true /* liveTracking */ ,
117 GetwxMacLiveScrollbarActionProc() , m_peer
->GetControlRefAddr() ) );
119 if(style
& wxSL_VERTICAL
) {
120 SetSizeHints(10, -1, 10, -1); // Forces SetSize to use the proper width
123 SetSizeHints(-1, 10, -1, 10); // Forces SetSize to use the proper height
125 // NB! SetSizeHints is overloaded by wxSlider and will substitute 10 with the
126 // proper dimensions, it also means other people cannot bugger the slider with
129 if(style
& wxSL_LABELS
)
131 m_macMinimumStatic
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString
);
132 m_macMaximumStatic
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString
);
133 m_macValueStatic
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString
);
134 SetRange(minValue
, maxValue
);
138 MacPostControlCreate(pos
,size
) ;
143 wxSlider::~wxSlider()
145 // this is a special case, as we had to add windows as siblings we are
146 // responsible for their disposal, but only if we are not part of a DestroyAllChildren
147 if ( m_parent
&& m_parent
->IsBeingDeleted() == false )
149 delete m_macMinimumStatic
;
150 delete m_macMaximumStatic
;
151 delete m_macValueStatic
;
155 int wxSlider::GetValue() const
157 // We may need to invert the value returned by the widget
158 return ValueInvertOrNot( m_peer
->GetValue() ) ;
161 void wxSlider::SetValue(int value
)
163 wxString valuestring
;
164 valuestring
.Printf( wxT("%d") , value
) ;
165 if ( m_macValueStatic
)
166 m_macValueStatic
->SetLabel( valuestring
) ;
168 // We only invert for the setting of the actual native widget
169 m_peer
->SetValue( ValueInvertOrNot ( value
) ) ;
172 void wxSlider::SetRange(int minValue
, int maxValue
)
176 m_rangeMin
= minValue
;
177 m_rangeMax
= maxValue
;
179 m_peer
->SetMinimum( m_rangeMin
);
180 m_peer
->SetMaximum( m_rangeMax
);
182 if(m_macMinimumStatic
) {
183 value
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin
) );
184 m_macMinimumStatic
->SetLabel(value
);
186 if(m_macMaximumStatic
) {
187 value
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax
) );
188 m_macMaximumStatic
->SetLabel(value
);
190 SetValue(m_rangeMin
);
193 // For trackbars only
194 void wxSlider::SetTickFreq(int n
, int pos
)
200 void wxSlider::SetPageSize(int pageSize
)
203 m_pageSize
= pageSize
;
206 int wxSlider::GetPageSize() const
211 void wxSlider::ClearSel()
216 void wxSlider::ClearTicks()
221 void wxSlider::SetLineSize(int lineSize
)
223 m_lineSize
= lineSize
;
227 int wxSlider::GetLineSize() const
233 int wxSlider::GetSelEnd() const
239 int wxSlider::GetSelStart() const
245 void wxSlider::SetSelection(int minPos
, int maxPos
)
250 void wxSlider::SetThumbLength(int len
)
255 int wxSlider::GetThumbLength() const
261 void wxSlider::SetTick(int tickPos
)
266 void wxSlider::Command (wxCommandEvent
& event
)
268 SetValue (event
.GetInt());
269 ProcessCommand (event
);
272 void wxSlider::MacHandleControlClick( WXWidget control
, wxInt16 controlpart
, bool mouseStillDown
)
274 // Whatever the native value is, we may need to invert it for calling
275 // SetValue and putting the possibly inverted value in the event
276 SInt16 value
= ValueInvertOrNot ( m_peer
->GetValue() ) ;
280 wxEventType scrollEvent
= wxEVT_NULL
;
282 scrollEvent
= wxEVT_SCROLL_THUMBTRACK
;
284 wxScrollEvent
event(scrollEvent
, m_windowId
);
285 event
.SetPosition(value
);
286 event
.SetEventObject( this );
287 GetEventHandler()->ProcessEvent(event
);
289 wxCommandEvent
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId
);
290 cevent
.SetInt( value
);
291 cevent
.SetEventObject( this );
293 GetEventHandler()->ProcessEvent( cevent
);
296 wxInt32
wxSlider::MacControlHit( WXEVENTHANDLERREF handler
, WXEVENTREF mevent
)
298 // Whatever the native value is, we may need to invert it for calling
299 // SetValue and putting the possibly inverted value in the event
300 SInt16 value
= ValueInvertOrNot ( m_peer
->GetValue() ) ;
304 wxEventType scrollEvent
= wxEVT_NULL
;
306 scrollEvent
= wxEVT_SCROLL_THUMBRELEASE
;
308 wxScrollEvent
event(scrollEvent
, m_windowId
);
309 event
.SetPosition(value
);
310 event
.SetEventObject( this );
311 GetEventHandler()->ProcessEvent(event
);
313 wxCommandEvent
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId
);
314 cevent
.SetInt( value
);
315 cevent
.SetEventObject( this );
317 GetEventHandler()->ProcessEvent( cevent
);
321 /* This is overloaded in wxSlider so that the proper width/height will always be used
322 * for the slider different values would cause redrawing and mouse detection problems */
323 void wxSlider::DoSetSizeHints( int minW
, int minH
,
324 int maxW
, int maxH
,
325 int incW
, int incH
)
327 wxSize size
= GetBestSize();
329 if(GetWindowStyle() & wxSL_VERTICAL
) {
330 wxWindow::DoSetSizeHints(size
.x
, minH
, size
.x
, maxH
, incW
, incH
);
333 wxWindow::DoSetSizeHints(minW
, size
.y
, maxW
, size
.y
, incW
, incH
);
337 wxSize
wxSlider::DoGetBestSize() const
342 int mintwidth
, mintheight
;
343 int maxtwidth
, maxtheight
;
345 if(GetWindowStyle() & wxSL_LABELS
)
349 // Get maximum text label width and height
350 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin
) );
351 GetTextExtent(text
, &mintwidth
, &mintheight
);
352 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax
) );
353 GetTextExtent(text
, &maxtwidth
, &maxtheight
);
354 if(maxtheight
> mintheight
) {
355 textheight
= maxtheight
;
358 textheight
= mintheight
;
360 if (maxtwidth
> mintwidth
) {
361 textwidth
= maxtwidth
;
364 textwidth
= mintwidth
;
368 if(GetWindowStyle() & wxSL_VERTICAL
)
370 if(GetWindowStyle() & wxSL_AUTOTICKS
) {
371 size
.x
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
;
374 size
.x
= wxSLIDER_DIMENSIONACROSS_ARROW
;
376 if(GetWindowStyle() & wxSL_LABELS
) {
377 size
.x
+= textwidth
+ wxSLIDER_BORDERTEXT
;
383 if(GetWindowStyle() & wxSL_AUTOTICKS
) {
384 size
.y
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
;
387 size
.y
= wxSLIDER_DIMENSIONACROSS_ARROW
;
392 if(GetWindowStyle() & wxSL_LABELS
) {
393 size
.y
+= textheight
+ wxSLIDER_BORDERTEXT
;
394 size
.x
+= (mintwidth
/2) + (maxtwidth
/2);
400 void wxSlider::DoSetSize(int x
, int y
, int w
, int h
, int sizeFlags
)
402 int xborder
, yborder
;
403 int minValWidth
, maxValWidth
, textheight
;
407 xborder
= yborder
= 0;
409 if (GetWindowStyle() & wxSL_LABELS
)
415 // Get maximum text label width and height
416 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin
) );
417 GetTextExtent(text
, &minValWidth
, &textheight
);
418 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax
) );
419 GetTextExtent(text
, &maxValWidth
, &ht
);
421 if(ht
> textheight
) {
425 if(GetWindowStyle() & wxSL_HORIZONTAL
)
427 if ( m_macMinimumStatic
) {
431 if ( m_macMaximumStatic
) {
437 //Labels have this control's parent as their parent
438 //so if this control is not at 0,0 relative to the parent
439 //the labels need to know the position of this control
440 //relative to its parent in order to size properly, so
441 //move the control first so we can use GetPosition()
442 wxControl::DoSetSize( x
, y
, w
, h
,sizeFlags
) ;
444 // If vertical, use current value
445 if(GetWindowStyle() & wxSL_VERTICAL
)
447 text
.Printf(wxT("%d"), (int)m_peer
->GetValue());
449 // Use max so that the current value doesn't drift as centering would need to change
452 text
.Printf(wxT("%d"), m_rangeMax
);
455 GetTextExtent(text
, &valValWidth
, &ht
);
457 yborder
= textheight
+ wxSLIDER_BORDERTEXT
;
459 // Get slider breadth
460 if(GetWindowStyle() & wxSL_AUTOTICKS
) {
461 sliderBreadth
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
;
464 sliderBreadth
= wxSLIDER_DIMENSIONACROSS_ARROW
;
467 if(GetWindowStyle() & wxSL_VERTICAL
)
471 if ( m_macMinimumStatic
)
472 m_macMinimumStatic
->Move(GetPosition().x
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
, GetPosition().y
+ h
- yborder
);
473 if ( m_macMaximumStatic
)
474 m_macMaximumStatic
->Move(GetPosition().x
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
, GetPosition().y
+ 0);
475 if ( m_macValueStatic
)
476 m_macValueStatic
->Move(GetPosition().x
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
, GetPosition().y
+ (h
/2) - (ht
/2));
480 if ( m_macMinimumStatic
)
481 m_macMinimumStatic
->Move(GetPosition().x
, GetPosition().y
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
);
482 if ( m_macMaximumStatic
)
483 m_macMaximumStatic
->Move(GetPosition().x
+ w
- maxValWidth
, GetPosition().y
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
);
484 if ( m_macValueStatic
)
485 m_macValueStatic
->Move(GetPosition().x
+ (w
/2) - (valValWidth
/2), GetPosition().y
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
);
489 // yet another hack since this is a composite control
490 // when wxSlider has it's size hardcoded, we're not allowed to
491 // change the size. But when the control has labels, we DO need
492 // to resize the internal Mac control to accommodate the text labels.
493 // We need to trick the wxWidgets resize mechanism so that we can
494 // resize the slider part of the control ONLY.
496 // TODO: Can all of this code go in the conditional wxSL_LABELS block?
499 minWidth
= m_minWidth
;
501 if (GetWindowStyle() & wxSL_LABELS
)
503 // make sure we don't allow the entire control to be resized accidently
504 if (width
== GetSize().x
)
507 //If the control has labels, we still need to call this again because
508 //the labels alter the control's w and h values.
509 wxControl::DoSetSize( x
, y
, w
, h
,sizeFlags
) ;
511 m_minWidth
= minWidth
;
514 void wxSlider::DoMoveWindow(int x
, int y
, int width
, int height
)
516 wxControl::DoMoveWindow(x
,y
,width
,height
) ;
519 // Common processing to invert slider values based on wxSL_INVERSE
520 int wxSlider::ValueInvertOrNot(int value
) const
522 if (m_windowStyle
& wxSL_VERTICAL
)
524 // The reason for the backwards logic is that Mac's vertical sliders are
525 // inverted compared to Windows and GTK, hence we want inversion to be the
526 // default, and if wxSL_INVERSE is set, then we do not invert (use native)
527 if (m_windowStyle
& wxSL_INVERSE
)
530 return (m_rangeMax
+ m_rangeMin
) - value
;
532 else // normal logic applies to HORIZONTAL sliders
534 return wxSliderBase::ValueInvertOrNot(value
);
538 #endif // wxUSE_SLIDER