]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/slider.cpp
187b651bcc0ab3d1ae7fab562a2f4f065c7ab5aa
[wxWidgets.git] / src / mac / carbon / slider.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: slider.cpp
3 // Purpose: wxSlider
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_SLIDER
15
16 #include "wx/slider.h"
17 #include "wx/mac/uma.h"
18
19 IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl)
20
21 BEGIN_EVENT_TABLE(wxSlider, wxControl)
22 END_EVENT_TABLE()
23
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
28
29 // Distance between slider and text
30 #define wxSLIDER_BORDERTEXT 5
31
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 }>
37 */
38
39 // Slider
40 wxSlider::wxSlider()
41 {
42 m_pageSize = 1;
43 m_lineSize = 1;
44 m_rangeMax = 0;
45 m_rangeMin = 0;
46 m_tickFreq = 0;
47
48 m_macMinimumStatic = NULL ;
49 m_macMaximumStatic = NULL ;
50 m_macValueStatic = NULL ;
51 }
52
53 bool wxSlider::Create(wxWindow *parent, wxWindowID id,
54 int value, int minValue, int maxValue,
55 const wxPoint& pos,
56 const wxSize& size, long style,
57 const wxValidator& validator,
58 const wxString& name)
59 {
60 m_macIsUserPane = false ;
61
62 m_macMinimumStatic = NULL ;
63 m_macMaximumStatic = NULL ;
64 m_macValueStatic = NULL ;
65
66 m_lineSize = 1;
67 m_tickFreq = 0;
68
69 m_rangeMax = maxValue;
70 m_rangeMin = minValue;
71
72 m_pageSize = (int)((maxValue-minValue)/10);
73
74 // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and
75 // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility
76 // reasons we can't really change it, instead try to infer the orientation
77 // from the flags given to us here
78 switch ( style & (wxSL_LEFT | wxSL_RIGHT | wxSL_TOP | wxSL_BOTTOM) )
79 {
80 case wxSL_LEFT:
81 case wxSL_RIGHT:
82 style |= wxSL_VERTICAL;
83 break;
84
85 case wxSL_TOP:
86 case wxSL_BOTTOM:
87 style |= wxSL_HORIZONTAL;
88 break;
89
90 case 0:
91 default:
92 // no specific direction, do we have at least the orientation?
93 if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) )
94 {
95 // no, choose default
96 style |= wxSL_BOTTOM | wxSL_HORIZONTAL;
97 }
98 break;
99 }
100
101 wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL),
102 _T("incompatible slider direction and orientation") );
103
104 if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
105 return false;
106
107 Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ;
108
109 //
110 // NB: (RN) Ticks here are sometimes off in the GUI if there
111 // is not as many ticks as there are values
112 //
113 UInt16 tickMarks = 0 ;
114 if ( style & wxSL_AUTOTICKS )
115 tickMarks = (maxValue - minValue) + 1; //+1 for the 0 value
116
117 while (tickMarks > 20)
118 tickMarks /= 5; //keep the number of tickmarks from becoming unwieldly
119
120 m_peer = new wxMacControl(this) ;
121 verify_noerr ( CreateSliderControl( MAC_WXHWND(parent->MacGetTopLevelWindowRef()) , &bounds ,
122 value , minValue , maxValue , kControlSliderPointsDownOrRight , tickMarks , true /* liveTracking */ ,
123 GetwxMacLiveScrollbarActionProc() , m_peer->GetControlRefAddr() ) );
124
125 if(style & wxSL_VERTICAL) {
126 SetSizeHints(10, -1, 10, -1); // Forces SetSize to use the proper width
127 }
128 else {
129 SetSizeHints(-1, 10, -1, 10); // Forces SetSize to use the proper height
130 }
131 // NB! SetSizeHints is overloaded by wxSlider and will substitute 10 with the
132 // proper dimensions, it also means other people cannot bugger the slider with
133 // other values
134
135 if(style & wxSL_LABELS)
136 {
137 m_macMinimumStatic = new wxStaticText( parent, wxID_ANY, wxEmptyString );
138 m_macMaximumStatic = new wxStaticText( parent, wxID_ANY, wxEmptyString );
139 m_macValueStatic = new wxStaticText( parent, wxID_ANY, wxEmptyString );
140 }
141
142 SetRange(minValue, maxValue);
143 SetValue(value);
144
145 MacPostControlCreate(pos,size) ;
146
147 return true;
148 }
149
150 wxSlider::~wxSlider()
151 {
152 // this is a special case, as we had to add windows as siblings we are
153 // responsible for their disposal, but only if we are not part of a DestroyAllChildren
154 if ( m_parent && m_parent->IsBeingDeleted() == false )
155 {
156 delete m_macMinimumStatic ;
157 delete m_macMaximumStatic ;
158 delete m_macValueStatic ;
159 }
160 }
161
162 int wxSlider::GetValue() const
163 {
164 // We may need to invert the value returned by the widget
165 return ValueInvertOrNot( m_peer->GetValue() ) ;
166 }
167
168 void wxSlider::SetValue(int value)
169 {
170 if ( m_macValueStatic )
171 {
172 wxString valuestring ;
173 valuestring.Printf( wxT("%d") , value ) ;
174 m_macValueStatic->SetLabel( valuestring ) ;
175 }
176
177 // We only invert for the setting of the actual native widget
178 m_peer->SetValue( ValueInvertOrNot ( value ) ) ;
179 }
180
181 void wxSlider::SetRange(int minValue, int maxValue)
182 {
183 wxString value;
184
185 m_rangeMin = minValue;
186 m_rangeMax = maxValue;
187
188 m_peer->SetMinimum( m_rangeMin);
189 m_peer->SetMaximum( m_rangeMax);
190
191 if(m_macMinimumStatic) {
192 value.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin ) );
193 m_macMinimumStatic->SetLabel(value);
194 }
195 if(m_macMaximumStatic) {
196 value.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax ) );
197 m_macMaximumStatic->SetLabel(value);
198 }
199 SetValue(m_rangeMin);
200 }
201
202 // For trackbars only
203 void wxSlider::SetTickFreq(int n, int pos)
204 {
205 // TODO
206 m_tickFreq = n;
207 }
208
209 void wxSlider::SetPageSize(int pageSize)
210 {
211 // TODO
212 m_pageSize = pageSize;
213 }
214
215 int wxSlider::GetPageSize() const
216 {
217 return m_pageSize;
218 }
219
220 void wxSlider::ClearSel()
221 {
222 // TODO
223 }
224
225 void wxSlider::ClearTicks()
226 {
227 // TODO
228 }
229
230 void wxSlider::SetLineSize(int lineSize)
231 {
232 m_lineSize = lineSize;
233 // TODO
234 }
235
236 int wxSlider::GetLineSize() const
237 {
238 // TODO
239 return 0;
240 }
241
242 int wxSlider::GetSelEnd() const
243 {
244 // TODO
245 return 0;
246 }
247
248 int wxSlider::GetSelStart() const
249 {
250 // TODO
251 return 0;
252 }
253
254 void wxSlider::SetSelection(int minPos, int maxPos)
255 {
256 // TODO
257 }
258
259 void wxSlider::SetThumbLength(int len)
260 {
261 // TODO
262 }
263
264 int wxSlider::GetThumbLength() const
265 {
266 // TODO
267 return 0;
268 }
269
270 void wxSlider::SetTick(int tickPos)
271 {
272 // TODO
273 }
274
275 void wxSlider::Command (wxCommandEvent & event)
276 {
277 SetValue (event.GetInt());
278 ProcessCommand (event);
279 }
280
281 void wxSlider::MacHandleControlClick( WXWidget control , wxInt16 controlpart, bool mouseStillDown )
282 {
283 // Whatever the native value is, we may need to invert it for calling
284 // SetValue and putting the possibly inverted value in the event
285 SInt16 value = ValueInvertOrNot ( m_peer->GetValue() ) ;
286
287 SetValue( value ) ;
288
289 wxEventType scrollEvent = wxEVT_NULL ;
290
291 scrollEvent = wxEVT_SCROLL_THUMBTRACK;
292
293 wxScrollEvent event(scrollEvent, m_windowId);
294 event.SetPosition(value);
295 event.SetEventObject( this );
296 GetEventHandler()->ProcessEvent(event);
297
298 wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId );
299 cevent.SetInt( value );
300 cevent.SetEventObject( this );
301
302 GetEventHandler()->ProcessEvent( cevent );
303 }
304
305 wxInt32 wxSlider::MacControlHit( WXEVENTHANDLERREF handler , WXEVENTREF mevent )
306 {
307 // Whatever the native value is, we may need to invert it for calling
308 // SetValue and putting the possibly inverted value in the event
309 SInt16 value = ValueInvertOrNot ( m_peer->GetValue() ) ;
310
311 SetValue( value ) ;
312
313 wxEventType scrollEvent = wxEVT_NULL ;
314
315 scrollEvent = wxEVT_SCROLL_THUMBRELEASE;
316
317 wxScrollEvent event(scrollEvent, m_windowId);
318 event.SetPosition(value);
319 event.SetEventObject( this );
320 GetEventHandler()->ProcessEvent(event);
321
322 wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId );
323 cevent.SetInt( value );
324 cevent.SetEventObject( this );
325
326 GetEventHandler()->ProcessEvent( cevent );
327 return noErr ;
328 }
329
330 /* This is overloaded in wxSlider so that the proper width/height will always be used
331 * for the slider different values would cause redrawing and mouse detection problems */
332 void wxSlider::DoSetSizeHints( int minW, int minH,
333 int maxW , int maxH ,
334 int incW , int incH )
335 {
336 wxSize size = GetBestSize();
337
338 if(GetWindowStyle() & wxSL_VERTICAL) {
339 wxWindow::DoSetSizeHints(size.x, minH, size.x, maxH, incW, incH);
340 }
341 else {
342 wxWindow::DoSetSizeHints(minW, size.y, maxW, size.y, incW, incH);
343 }
344 }
345
346 wxSize wxSlider::DoGetBestSize() const
347 {
348 wxSize size;
349 int textwidth = 0;
350 int textheight = 0;
351 int mintwidth, mintheight;
352 int maxtwidth, maxtheight;
353
354 if(GetWindowStyle() & wxSL_LABELS)
355 {
356 wxString text;
357
358 // Get maximum text label width and height
359 text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin ) );
360 GetTextExtent(text, &mintwidth, &mintheight);
361 text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax ) );
362 GetTextExtent(text, &maxtwidth, &maxtheight);
363 if(maxtheight > mintheight) {
364 textheight = maxtheight;
365 }
366 else {
367 textheight = mintheight;
368 }
369 if (maxtwidth > mintwidth) {
370 textwidth = maxtwidth;
371 }
372 else {
373 textwidth = mintwidth;
374 }
375 }
376
377 if(GetWindowStyle() & wxSL_VERTICAL)
378 {
379 if(GetWindowStyle() & wxSL_AUTOTICKS) {
380 size.x = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS;
381 }
382 else {
383 size.x = wxSLIDER_DIMENSIONACROSS_ARROW;
384 }
385 if(GetWindowStyle() & wxSL_LABELS) {
386 size.x += textwidth + wxSLIDER_BORDERTEXT;
387 }
388 size.y = 150;
389 }
390 else
391 {
392 if(GetWindowStyle() & wxSL_AUTOTICKS) {
393 size.y = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS;
394 }
395 else {
396 size.y = wxSLIDER_DIMENSIONACROSS_ARROW;
397 }
398
399 size.x = 150;
400
401 if(GetWindowStyle() & wxSL_LABELS) {
402 size.y += textheight + wxSLIDER_BORDERTEXT;
403 size.x += (mintwidth/2) + (maxtwidth/2);
404 }
405 }
406 return size;
407 }
408
409 void wxSlider::DoSetSize(int x, int y, int w, int h, int sizeFlags)
410 {
411 int xborder, yborder;
412 int minValWidth, maxValWidth, textheight;
413 int sliderBreadth;
414 int width = w;
415
416 xborder = yborder = 0;
417
418 if (GetWindowStyle() & wxSL_LABELS)
419 {
420
421 wxString text;
422 int ht, valValWidth;
423
424 // Get maximum text label width and height
425 text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin ) );
426 GetTextExtent(text, &minValWidth, &textheight);
427 text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax ) );
428 GetTextExtent(text, &maxValWidth, &ht);
429
430 if(ht > textheight) {
431 textheight = ht;
432 }
433
434 if(GetWindowStyle() & wxSL_HORIZONTAL)
435 {
436 if ( m_macMinimumStatic ) {
437 w-=minValWidth/2;
438 x+=minValWidth/2;
439 }
440 if ( m_macMaximumStatic ) {
441 w-=maxValWidth/2;
442 }
443 }
444
445
446 //Labels have this control's parent as their parent
447 //so if this control is not at 0,0 relative to the parent
448 //the labels need to know the position of this control
449 //relative to its parent in order to size properly, so
450 //move the control first so we can use GetPosition()
451 wxControl::DoSetSize( x, y , w , h ,sizeFlags ) ;
452
453 // If vertical, use current value
454 if(GetWindowStyle() & wxSL_VERTICAL)
455 {
456 text.Printf(wxT("%d"), (int)m_peer->GetValue());
457 }
458 // Use max so that the current value doesn't drift as centering would need to change
459 else
460 {
461 text.Printf(wxT("%d"), m_rangeMax);
462 }
463
464 GetTextExtent(text, &valValWidth, &ht);
465
466 yborder = textheight + wxSLIDER_BORDERTEXT;
467
468 // Get slider breadth
469 if(GetWindowStyle() & wxSL_AUTOTICKS) {
470 sliderBreadth = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS;
471 }
472 else {
473 sliderBreadth = wxSLIDER_DIMENSIONACROSS_ARROW;
474 }
475
476 if(GetWindowStyle() & wxSL_VERTICAL)
477 {
478 h = h - yborder ;
479
480 if ( m_macMinimumStatic )
481 m_macMinimumStatic->Move(GetPosition().x + sliderBreadth + wxSLIDER_BORDERTEXT, GetPosition().y + h - yborder);
482 if ( m_macMaximumStatic )
483 m_macMaximumStatic->Move(GetPosition().x + sliderBreadth + wxSLIDER_BORDERTEXT, GetPosition().y + 0);
484 if ( m_macValueStatic )
485 m_macValueStatic->Move(GetPosition().x + sliderBreadth + wxSLIDER_BORDERTEXT, GetPosition().y + (h/2) - (ht/2));
486 }
487 else
488 {
489 if ( m_macMinimumStatic )
490 m_macMinimumStatic->Move(GetPosition().x, GetPosition().y + sliderBreadth + wxSLIDER_BORDERTEXT);
491 if ( m_macMaximumStatic )
492 m_macMaximumStatic->Move(GetPosition().x + w - maxValWidth, GetPosition().y + sliderBreadth + wxSLIDER_BORDERTEXT);
493 if ( m_macValueStatic )
494 m_macValueStatic->Move(GetPosition().x + (w/2) - (valValWidth/2), GetPosition().y + sliderBreadth + wxSLIDER_BORDERTEXT);
495 }
496 }
497
498 // yet another hack since this is a composite control
499 // when wxSlider has it's size hardcoded, we're not allowed to
500 // change the size. But when the control has labels, we DO need
501 // to resize the internal Mac control to accommodate the text labels.
502 // We need to trick the wxWidgets resize mechanism so that we can
503 // resize the slider part of the control ONLY.
504
505 // TODO: Can all of this code go in the conditional wxSL_LABELS block?
506
507 int minWidth;
508 minWidth = m_minWidth;
509
510 if (GetWindowStyle() & wxSL_LABELS)
511 {
512 // make sure we don't allow the entire control to be resized accidently
513 if (width == GetSize().x)
514 m_minWidth = -1;
515 }
516 //If the control has labels, we still need to call this again because
517 //the labels alter the control's w and h values.
518 wxControl::DoSetSize( x, y , w , h ,sizeFlags ) ;
519
520 m_minWidth = minWidth;
521 }
522
523 void wxSlider::DoMoveWindow(int x, int y, int width, int height)
524 {
525 wxControl::DoMoveWindow(x,y,width,height) ;
526 }
527
528 // Common processing to invert slider values based on wxSL_INVERSE
529 int wxSlider::ValueInvertOrNot(int value) const
530 {
531 if (m_windowStyle & wxSL_VERTICAL)
532 {
533 // The reason for the backwards logic is that Mac's vertical sliders are
534 // inverted compared to Windows and GTK, hence we want inversion to be the
535 // default, and if wxSL_INVERSE is set, then we do not invert (use native)
536 if (m_windowStyle & wxSL_INVERSE)
537 return value;
538 else
539 return (m_rangeMax + m_rangeMin) - value;
540 }
541 else // normal logic applies to HORIZONTAL sliders
542 {
543 return wxSliderBase::ValueInvertOrNot(value);
544 }
545 }
546
547 #endif // wxUSE_SLIDER