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 // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and
63 // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility
64 // reasons we can't really change it, instead try to infer the orientation
65 // from the flags given to us here
66 switch ( style
& (wxSL_LEFT
| wxSL_RIGHT
| wxSL_TOP
| wxSL_BOTTOM
) )
70 style
|= wxSL_VERTICAL
;
75 style
|= wxSL_HORIZONTAL
;
79 // no specific direction, do we have at least the orientation?
80 if ( !(style
& (wxSL_HORIZONTAL
| wxSL_VERTICAL
)) )
83 style
|= wxSL_BOTTOM
| wxSL_HORIZONTAL
;
87 wxASSERT_MSG( !(style
& wxSL_VERTICAL
) | !(style
& wxSL_HORIZONTAL
),
88 _T("incompatible slider direction and orientation") );
90 if ( !wxControl::Create(parent
, id
, pos
, size
, style
, validator
, name
) )
93 m_macMinimumStatic
= NULL
;
94 m_macMaximumStatic
= NULL
;
95 m_macValueStatic
= NULL
;
100 m_rangeMax
= maxValue
;
101 m_rangeMin
= minValue
;
103 m_pageSize
= (int)((maxValue
-minValue
)/10);
105 Rect bounds
= wxMacGetBoundsForControl( this , pos
, size
) ;
108 // NB: (RN) Ticks here are sometimes off in the GUI if there
109 // is not as many ticks as there are values
111 UInt16 tickMarks
= 0 ;
112 if ( style
& wxSL_AUTOTICKS
)
113 tickMarks
= (maxValue
- minValue
) + 1; //+1 for the 0 value
115 while (tickMarks
> 20)
116 tickMarks
/= 5; //keep the number of tickmarks from becoming unwieldly
118 m_peer
= new wxMacControl(this) ;
119 verify_noerr ( CreateSliderControl( MAC_WXHWND(parent
->MacGetTopLevelWindowRef()) , &bounds
,
120 value
, minValue
, maxValue
, kControlSliderPointsDownOrRight
, tickMarks
, true /* liveTracking */ ,
121 GetwxMacLiveScrollbarActionProc() , m_peer
->GetControlRefAddr() ) );
123 if(style
& wxSL_VERTICAL
) {
124 SetSizeHints(10, -1, 10, -1); // Forces SetSize to use the proper width
127 SetSizeHints(-1, 10, -1, 10); // Forces SetSize to use the proper height
129 // NB! SetSizeHints is overloaded by wxSlider and will substitute 10 with the
130 // proper dimensions, it also means other people cannot bugger the slider with
133 if(style
& wxSL_LABELS
)
135 m_macMinimumStatic
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString
);
136 m_macMaximumStatic
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString
);
137 m_macValueStatic
= new wxStaticText( parent
, wxID_ANY
, wxEmptyString
);
138 SetRange(minValue
, maxValue
);
142 MacPostControlCreate(pos
,size
) ;
147 wxSlider::~wxSlider()
149 // this is a special case, as we had to add windows as siblings we are
150 // responsible for their disposal, but only if we are not part of a DestroyAllChildren
151 if ( m_parent
&& m_parent
->IsBeingDeleted() == false )
153 delete m_macMinimumStatic
;
154 delete m_macMaximumStatic
;
155 delete m_macValueStatic
;
159 int wxSlider::GetValue() const
161 // We may need to invert the value returned by the widget
162 return ValueInvertOrNot( m_peer
->GetValue() ) ;
165 void wxSlider::SetValue(int value
)
167 wxString valuestring
;
168 valuestring
.Printf( wxT("%d") , value
) ;
169 if ( m_macValueStatic
)
170 m_macValueStatic
->SetLabel( valuestring
) ;
172 // We only invert for the setting of the actual native widget
173 m_peer
->SetValue( ValueInvertOrNot ( value
) ) ;
176 void wxSlider::SetRange(int minValue
, int maxValue
)
180 m_rangeMin
= minValue
;
181 m_rangeMax
= maxValue
;
183 m_peer
->SetMinimum( m_rangeMin
);
184 m_peer
->SetMaximum( m_rangeMax
);
186 if(m_macMinimumStatic
) {
187 value
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin
) );
188 m_macMinimumStatic
->SetLabel(value
);
190 if(m_macMaximumStatic
) {
191 value
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax
) );
192 m_macMaximumStatic
->SetLabel(value
);
194 SetValue(m_rangeMin
);
197 // For trackbars only
198 void wxSlider::SetTickFreq(int n
, int pos
)
204 void wxSlider::SetPageSize(int pageSize
)
207 m_pageSize
= pageSize
;
210 int wxSlider::GetPageSize() const
215 void wxSlider::ClearSel()
220 void wxSlider::ClearTicks()
225 void wxSlider::SetLineSize(int lineSize
)
227 m_lineSize
= lineSize
;
231 int wxSlider::GetLineSize() const
237 int wxSlider::GetSelEnd() const
243 int wxSlider::GetSelStart() const
249 void wxSlider::SetSelection(int minPos
, int maxPos
)
254 void wxSlider::SetThumbLength(int len
)
259 int wxSlider::GetThumbLength() const
265 void wxSlider::SetTick(int tickPos
)
270 void wxSlider::Command (wxCommandEvent
& event
)
272 SetValue (event
.GetInt());
273 ProcessCommand (event
);
276 void wxSlider::MacHandleControlClick( WXWidget control
, wxInt16 controlpart
, bool mouseStillDown
)
278 // Whatever the native value is, we may need to invert it for calling
279 // SetValue and putting the possibly inverted value in the event
280 SInt16 value
= ValueInvertOrNot ( m_peer
->GetValue() ) ;
284 wxEventType scrollEvent
= wxEVT_NULL
;
286 scrollEvent
= wxEVT_SCROLL_THUMBTRACK
;
288 wxScrollEvent
event(scrollEvent
, m_windowId
);
289 event
.SetPosition(value
);
290 event
.SetEventObject( this );
291 GetEventHandler()->ProcessEvent(event
);
293 wxCommandEvent
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId
);
294 cevent
.SetInt( value
);
295 cevent
.SetEventObject( this );
297 GetEventHandler()->ProcessEvent( cevent
);
300 wxInt32
wxSlider::MacControlHit( WXEVENTHANDLERREF handler
, WXEVENTREF mevent
)
302 // Whatever the native value is, we may need to invert it for calling
303 // SetValue and putting the possibly inverted value in the event
304 SInt16 value
= ValueInvertOrNot ( m_peer
->GetValue() ) ;
308 wxEventType scrollEvent
= wxEVT_NULL
;
310 scrollEvent
= wxEVT_SCROLL_THUMBRELEASE
;
312 wxScrollEvent
event(scrollEvent
, m_windowId
);
313 event
.SetPosition(value
);
314 event
.SetEventObject( this );
315 GetEventHandler()->ProcessEvent(event
);
317 wxCommandEvent
cevent( wxEVT_COMMAND_SLIDER_UPDATED
, m_windowId
);
318 cevent
.SetInt( value
);
319 cevent
.SetEventObject( this );
321 GetEventHandler()->ProcessEvent( cevent
);
325 /* This is overloaded in wxSlider so that the proper width/height will always be used
326 * for the slider different values would cause redrawing and mouse detection problems */
327 void wxSlider::DoSetSizeHints( int minW
, int minH
,
328 int maxW
, int maxH
,
329 int incW
, int incH
)
331 wxSize size
= GetBestSize();
333 if(GetWindowStyle() & wxSL_VERTICAL
) {
334 wxWindow::DoSetSizeHints(size
.x
, minH
, size
.x
, maxH
, incW
, incH
);
337 wxWindow::DoSetSizeHints(minW
, size
.y
, maxW
, size
.y
, incW
, incH
);
341 wxSize
wxSlider::DoGetBestSize() const
346 int mintwidth
, mintheight
;
347 int maxtwidth
, maxtheight
;
349 if(GetWindowStyle() & wxSL_LABELS
)
353 // Get maximum text label width and height
354 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin
) );
355 GetTextExtent(text
, &mintwidth
, &mintheight
);
356 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax
) );
357 GetTextExtent(text
, &maxtwidth
, &maxtheight
);
358 if(maxtheight
> mintheight
) {
359 textheight
= maxtheight
;
362 textheight
= mintheight
;
364 if (maxtwidth
> mintwidth
) {
365 textwidth
= maxtwidth
;
368 textwidth
= mintwidth
;
372 if(GetWindowStyle() & wxSL_VERTICAL
)
374 if(GetWindowStyle() & wxSL_AUTOTICKS
) {
375 size
.x
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
;
378 size
.x
= wxSLIDER_DIMENSIONACROSS_ARROW
;
380 if(GetWindowStyle() & wxSL_LABELS
) {
381 size
.x
+= textwidth
+ wxSLIDER_BORDERTEXT
;
387 if(GetWindowStyle() & wxSL_AUTOTICKS
) {
388 size
.y
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
;
391 size
.y
= wxSLIDER_DIMENSIONACROSS_ARROW
;
396 if(GetWindowStyle() & wxSL_LABELS
) {
397 size
.y
+= textheight
+ wxSLIDER_BORDERTEXT
;
398 size
.x
+= (mintwidth
/2) + (maxtwidth
/2);
404 void wxSlider::DoSetSize(int x
, int y
, int w
, int h
, int sizeFlags
)
406 int xborder
, yborder
;
407 int minValWidth
, maxValWidth
, textheight
;
411 xborder
= yborder
= 0;
413 if (GetWindowStyle() & wxSL_LABELS
)
419 // Get maximum text label width and height
420 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin
) );
421 GetTextExtent(text
, &minValWidth
, &textheight
);
422 text
.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax
) );
423 GetTextExtent(text
, &maxValWidth
, &ht
);
425 if(ht
> textheight
) {
429 if(GetWindowStyle() & wxSL_HORIZONTAL
)
431 if ( m_macMinimumStatic
) {
435 if ( m_macMaximumStatic
) {
441 //Labels have this control's parent as their parent
442 //so if this control is not at 0,0 relative to the parent
443 //the labels need to know the position of this control
444 //relative to its parent in order to size properly, so
445 //move the control first so we can use GetPosition()
446 wxControl::DoSetSize( x
, y
, w
, h
,sizeFlags
) ;
448 // If vertical, use current value
449 if(GetWindowStyle() & wxSL_VERTICAL
)
451 text
.Printf(wxT("%d"), (int)m_peer
->GetValue());
453 // Use max so that the current value doesn't drift as centering would need to change
456 text
.Printf(wxT("%d"), m_rangeMax
);
459 GetTextExtent(text
, &valValWidth
, &ht
);
461 yborder
= textheight
+ wxSLIDER_BORDERTEXT
;
463 // Get slider breadth
464 if(GetWindowStyle() & wxSL_AUTOTICKS
) {
465 sliderBreadth
= wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS
;
468 sliderBreadth
= wxSLIDER_DIMENSIONACROSS_ARROW
;
471 if(GetWindowStyle() & wxSL_VERTICAL
)
475 if ( m_macMinimumStatic
)
476 m_macMinimumStatic
->Move(GetPosition().x
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
, GetPosition().y
+ h
- yborder
);
477 if ( m_macMaximumStatic
)
478 m_macMaximumStatic
->Move(GetPosition().x
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
, GetPosition().y
+ 0);
479 if ( m_macValueStatic
)
480 m_macValueStatic
->Move(GetPosition().x
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
, GetPosition().y
+ (h
/2) - (ht
/2));
484 if ( m_macMinimumStatic
)
485 m_macMinimumStatic
->Move(GetPosition().x
, GetPosition().y
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
);
486 if ( m_macMaximumStatic
)
487 m_macMaximumStatic
->Move(GetPosition().x
+ w
- maxValWidth
, GetPosition().y
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
);
488 if ( m_macValueStatic
)
489 m_macValueStatic
->Move(GetPosition().x
+ (w
/2) - (valValWidth
/2), GetPosition().y
+ sliderBreadth
+ wxSLIDER_BORDERTEXT
);
493 // yet another hack since this is a composite control
494 // when wxSlider has it's size hardcoded, we're not allowed to
495 // change the size. But when the control has labels, we DO need
496 // to resize the internal Mac control to accommodate the text labels.
497 // We need to trick the wxWidgets resize mechanism so that we can
498 // resize the slider part of the control ONLY.
500 // TODO: Can all of this code go in the conditional wxSL_LABELS block?
503 minWidth
= m_minWidth
;
505 if (GetWindowStyle() & wxSL_LABELS
)
507 // make sure we don't allow the entire control to be resized accidently
508 if (width
== GetSize().x
)
511 //If the control has labels, we still need to call this again because
512 //the labels alter the control's w and h values.
513 wxControl::DoSetSize( x
, y
, w
, h
,sizeFlags
) ;
515 m_minWidth
= minWidth
;
518 void wxSlider::DoMoveWindow(int x
, int y
, int width
, int height
)
520 wxControl::DoMoveWindow(x
,y
,width
,height
) ;
523 // Common processing to invert slider values based on wxSL_INVERSE
524 int wxSlider::ValueInvertOrNot(int value
) const
526 if (m_windowStyle
& wxSL_VERTICAL
)
528 // The reason for the backwards logic is that Mac's vertical sliders are
529 // inverted compared to Windows and GTK, hence we want inversion to be the
530 // default, and if wxSL_INVERSE is set, then we do not invert (use native)
531 if (m_windowStyle
& wxSL_INVERSE
)
534 return (m_rangeMax
+ m_rangeMin
) - value
;
536 else // normal logic applies to HORIZONTAL sliders
538 return wxSliderBase::ValueInvertOrNot(value
);
542 #endif // wxUSE_SLIDER