X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2f1ae4143271ae63a17e052a1a471d16e9cd8c44..9d5507f7a2701395e1d5c121bd877bb9066ee6ea:/src/mac/carbon/slider.cpp?ds=sidebyside diff --git a/src/mac/carbon/slider.cpp b/src/mac/carbon/slider.cpp index 936ccddb47..ced51f397e 100644 --- a/src/mac/carbon/slider.cpp +++ b/src/mac/carbon/slider.cpp @@ -1,165 +1,222 @@ ///////////////////////////////////////////////////////////////////////////// // Name: slider.cpp // Purpose: wxSlider -// Author: AUTHOR +// Author: Stefan Csomor // Modified by: -// Created: ??/??/98 +// Created: 1998-01-01 // RCS-ID: $Id$ -// Copyright: (c) AUTHOR -// Licence: wxWindows licence +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "slider.h" -#endif +#include "wx/wxprec.h" + +#if wxUSE_SLIDER #include "wx/slider.h" #include "wx/mac/uma.h" -#if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl) BEGIN_EVENT_TABLE(wxSlider, wxControl) END_EVENT_TABLE() -#endif + // The dimensions of the different styles of sliders (from Aqua document) +#define wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS 24 +#define wxSLIDER_DIMENSIONACROSS_ARROW 18 + +// Distance between slider and text +#define wxSLIDER_BORDERTEXT 5 +// NB: The default orientation for a slider is horizontal; however, if the user specifies +// some slider styles but doesn't specify the orientation we have to assume he wants a +// horizontal one. Therefore in this file when testing for the slider's orientation +// vertical is tested for if this is not set then we use the horizontal one +// e.g., if (GetWindowStyle() & wxSL_VERTICAL) {} else { horizontal case }. -// Slider wxSlider::wxSlider() { - m_pageSize = 1; - m_lineSize = 1; - m_rangeMax = 0; - m_rangeMin = 0; - m_tickFreq = 0; + m_pageSize = 1; + m_lineSize = 1; + m_rangeMax = 0; + m_rangeMin = 0; + m_tickFreq = 0; + + m_macMinimumStatic = NULL; + m_macMaximumStatic = NULL; + m_macValueStatic = NULL; } -extern ControlActionUPP wxMacLiveScrollbarActionUPP ; - -bool wxSlider::Create(wxWindow *parent, wxWindowID id, - int value, int minValue, int maxValue, - const wxPoint& pos, - const wxSize& size, long style, - const wxValidator& validator, - const wxString& name) +bool wxSlider::Create(wxWindow *parent, + wxWindowID id, + int value, int minValue, int maxValue, + const wxPoint& pos, + const wxSize& size, long style, + const wxValidator& validator, + const wxString& name) { - Rect bounds ; - Str255 title ; - - MacPreControlCreate( parent , id , "" , pos , size ,style, validator , name , &bounds , title ) ; - - m_macMinimumStatic = NULL ; - - m_lineSize = 1; - m_tickFreq = 0; - - m_rangeMax = maxValue; - m_rangeMin = minValue; - - m_pageSize = (int)((maxValue-minValue)/10); - if ( m_width == -1 ) - { - m_width = 20 ; - if ( style & wxSL_LABELS && style & wxSL_VERTICAL ) - m_width += 24 ; - bounds.right = bounds.left + m_width ; - } - if ( m_height == -1 ) - { - m_height = 20 ; - if ( style & wxSL_LABELS && style & wxSL_HORIZONTAL ) - m_height += 24 ; - bounds.bottom = bounds.top + m_height ; - } - - if ( style & wxSL_LABELS && style & wxSL_HORIZONTAL ) - { - bounds.top += 12 ; - bounds.right -= 24 ; - } - - if ( style & wxSL_LABELS && style & wxSL_VERTICAL ) - { - bounds.left += 24 ; - bounds.top += 12 ; - } - - m_macControl = UMANewControl( parent->GetMacRootWindow() , &bounds , title , true , value , minValue , maxValue, - kControlSliderProc + kControlSliderLiveFeedback + ( ( style & wxSL_AUTOTICKS ) ? kControlSliderHasTickMarks : 0 ) , (long) this ) ; - - wxASSERT_MSG( m_macControl != NULL , "No valid mac control" ) ; - - ::SetControlAction( m_macControl , wxMacLiveScrollbarActionUPP ) ; - - MacPostControlCreate() ; - - if ( style & wxSL_LABELS ) - { - if ( style & wxSL_HORIZONTAL ) - { - wxSize size( 24 , 12 ) ; - wxPoint leftpos( 0 , 0 ) ; - wxPoint rightpos( m_width - 2 * 12 , 0 ) ; - wxPoint valuepos( m_width - 12 , 20 ) ; - wxString valuestring ; - - valuestring.Printf( "%d" , minValue ) ; - m_macMinimumStatic = new wxStaticText( this , -1 , valuestring , leftpos , size ) ; - valuestring.Printf( "%d" , maxValue ) ; - m_macMinimumStatic = new wxStaticText( this , -1 , valuestring , rightpos , size ) ; - valuestring.Printf( "%d" , value ) ; - m_macMinimumStatic = new wxStaticText( this , -1 , valuestring , valuepos , size ) ; - } - else - { - wxSize size( 24 , 12 ) ; - wxPoint toppos( 0 , 12 ) ; - wxPoint bottompos( 0 , m_height - 12 ) ; - wxPoint valuepos( 20 , 0 ) ; - wxString valuestring ; - - valuestring.Printf( "%d" , minValue ) ; - m_macMinimumStatic = new wxStaticText( this , -1 , valuestring , bottompos , size ) ; - valuestring.Printf( "%d" , maxValue ) ; - m_macMinimumStatic = new wxStaticText( this , -1 , valuestring , toppos , size ) ; - valuestring.Printf( "%d" , value ) ; - m_macMinimumStatic = new wxStaticText( this , -1 , valuestring , valuepos , size ) ; - } - } - - return TRUE; + m_macIsUserPane = false; + + m_macMinimumStatic = NULL; + m_macMaximumStatic = NULL; + m_macValueStatic = NULL; + + m_lineSize = 1; + m_tickFreq = 0; + + m_rangeMax = maxValue; + m_rangeMin = minValue; + + m_pageSize = (int)((maxValue - minValue) / 10); + + // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and + // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility + // reasons we can't really change it, instead try to infer the orientation + // from the flags given to us here + switch ( style & (wxSL_LEFT | wxSL_RIGHT | wxSL_TOP | wxSL_BOTTOM) ) + { + case wxSL_LEFT: + case wxSL_RIGHT: + style |= wxSL_VERTICAL; + break; + + case wxSL_TOP: + case wxSL_BOTTOM: + style |= wxSL_HORIZONTAL; + break; + + case 0: + default: + // no specific direction, do we have at least the orientation? + if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) ) + // no: choose default + style |= wxSL_BOTTOM | wxSL_HORIZONTAL; + break; + } + wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL), + wxT("incompatible slider direction and orientation") ); + + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return false; + + Rect bounds = wxMacGetBoundsForControl( this , pos , size ); + + // NB: (RN) Ticks here are sometimes off in the GUI if there + // are not as many tick marks as there are values + // + int tickMarks = 0; + if ( style & wxSL_AUTOTICKS ) + tickMarks = (maxValue - minValue) + 1; // +1 for the 0 value + + // keep the number of tickmarks from becoming unwieldly, therefore below it is ok to cast + // it to a UInt16 + while (tickMarks > 20) + tickMarks /= 5; + + m_peer = new wxMacControl( this ); + OSStatus err = CreateSliderControl( + MAC_WXHWND(parent->MacGetTopLevelWindowRef()), &bounds, + value, minValue, maxValue, + kControlSliderPointsDownOrRight, + (UInt16) tickMarks, true /* liveTracking */, + GetwxMacLiveScrollbarActionProc(), + m_peer->GetControlRefAddr() ); + verify_noerr( err ); + + if (style & wxSL_VERTICAL) + // Forces SetSize to use the proper width + SetSizeHints(10, -1, 10, -1); + else + // Forces SetSize to use the proper height + SetSizeHints(-1, 10, -1, 10); + + // NB: SetSizeHints is overloaded by wxSlider and will substitute 10 with the + // proper dimensions, it also means other people cannot bugger the slider with + // other values + + if (style & wxSL_LABELS) + { + m_macMinimumStatic = new wxStaticText( parent, wxID_ANY, wxEmptyString ); + m_macMaximumStatic = new wxStaticText( parent, wxID_ANY, wxEmptyString ); + m_macValueStatic = new wxStaticText( parent, wxID_ANY, wxEmptyString ); + } + + SetRange(minValue, maxValue); + SetValue(value); + + MacPostControlCreate(pos, size); + + return true; } wxSlider::~wxSlider() { + // this is a special case, as we had to add windows as siblings we are + // responsible for their disposal, but only if we are not part of a DestroyAllChildren + if ( m_parent && !m_parent->IsBeingDeleted() ) + { + delete m_macMinimumStatic; + delete m_macMaximumStatic; + delete m_macValueStatic; + } } int wxSlider::GetValue() const { - return GetControlValue( m_macControl) ; + // We may need to invert the value returned by the widget + return ValueInvertOrNot( m_peer->GetValue() ) ; } void wxSlider::SetValue(int value) { - wxString valuestring ; - valuestring.Printf( "%d" , value ) ; - if ( m_macMinimumStatic ) - m_macMinimumStatic->SetLabel( valuestring ) ; - SetControlValue( m_macControl , value ) ; + if ( m_macValueStatic ) + { + wxString valuestring; + valuestring.Printf( wxT("%d"), value ); + m_macValueStatic->SetLabel( valuestring ); + } + + // We only invert for the setting of the actual native widget + m_peer->SetValue( ValueInvertOrNot( value ) ); } void wxSlider::SetRange(int minValue, int maxValue) { + wxString value; + m_rangeMin = minValue; m_rangeMax = maxValue; - // TODO + m_peer->SetMinimum( m_rangeMin ); + m_peer->SetMaximum( m_rangeMax ); + + if (m_macMinimumStatic) + { + value.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMin ) ); + m_macMinimumStatic->SetLabel( value ); + } + + if (m_macMaximumStatic) + { + value.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMax ) ); + m_macMaximumStatic->SetLabel( value ); + } + + // If the range is out of bounds, set it to a + // value that is within bounds + // RN: Testing reveals OSX does its own + // bounding, perhaps this isn't needed? + int currentValue = GetValue(); + + if(currentValue < m_rangeMin) + SetValue(m_rangeMin); + else if(currentValue > m_rangeMax) + SetValue(m_rangeMax); } // For trackbars only -void wxSlider::SetTickFreq(int n, int pos) +void wxSlider::SetTickFreq(int n, int WXUNUSED(pos)) { // TODO m_tickFreq = n; @@ -195,7 +252,7 @@ void wxSlider::SetLineSize(int lineSize) int wxSlider::GetLineSize() const { // TODO - return 0; + return m_lineSize; } int wxSlider::GetSelEnd() const @@ -210,12 +267,12 @@ int wxSlider::GetSelStart() const return 0; } -void wxSlider::SetSelection(int minPos, int maxPos) +void wxSlider::SetSelection(int WXUNUSED(minPos), int WXUNUSED(maxPos)) { // TODO } -void wxSlider::SetThumbLength(int len) +void wxSlider::SetThumbLength(int WXUNUSED(len)) { // TODO } @@ -226,43 +283,275 @@ int wxSlider::GetThumbLength() const return 0; } -void wxSlider::SetTick(int tickPos) +void wxSlider::SetTick(int WXUNUSED(tickPos)) { // TODO } -void wxSlider::Command (wxCommandEvent & event) +void wxSlider::Command(wxCommandEvent &event) +{ + SetValue(event.GetInt()); + ProcessCommand(event); +} + +void wxSlider::MacHandleControlClick(WXWidget WXUNUSED(control), + wxInt16 WXUNUSED(controlpart), + bool WXUNUSED(mouseStillDown)) { - SetValue (event.GetInt()); - ProcessCommand (event); + // Whatever the native value is, we may need to invert it for calling + // SetValue and putting the possibly inverted value in the event + int value = ValueInvertOrNot( m_peer->GetValue() ); + + SetValue( value ); + + wxScrollEvent event( wxEVT_SCROLL_THUMBTRACK, m_windowId ); + event.SetPosition( value ); + event.SetEventObject( this ); + HandleWindowEvent( event ); + + wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId ); + cevent.SetInt( value ); + cevent.SetEventObject( this ); + HandleWindowEvent( cevent ); } -bool wxSlider::Show( bool show ) +wxInt32 wxSlider::MacControlHit(WXEVENTHANDLERREF WXUNUSED(handler), + WXEVENTREF WXUNUSED(mevent)) { - return wxWindow::Show( show ) ; + // Whatever the native value is, we may need to invert it for calling + // SetValue and putting the possibly inverted value in the event + int value = ValueInvertOrNot( m_peer->GetValue() ) ; + + SetValue( value ) ; + + wxScrollEvent event( wxEVT_SCROLL_THUMBRELEASE, m_windowId ); + event.SetPosition( value ); + event.SetEventObject( this ); + HandleWindowEvent( event ); + + wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId ); + cevent.SetInt( value ); + cevent.SetEventObject( this ); + + HandleWindowEvent( cevent ); + + return noErr; } -void wxSlider::MacHandleControlClick( ControlHandle control , SInt16 controlpart ) +// This is overloaded in wxSlider so that the proper width/height will always be used +// for the slider different values would cause redrawing and mouse detection problems +// +void wxSlider::DoSetSizeHints( int minW, int minH, + int maxW, int maxH, + int WXUNUSED(incW), int WXUNUSED(incH) ) { - SInt16 value = ::GetControlValue( m_macControl ) ; - - SetValue( value ) ; - - wxScrollEvent event(wxEVT_SCROLL_THUMBTRACK, m_windowId); - event.SetPosition(GetControlValue( m_macControl) ); - event.SetEventObject( this ); - -#if WXWIN_COMPATIBILITY - - wxEventType oldEvent = event.GetEventType(); - event.SetEventType( wxEVT_COMMAND_SLIDER_UPDATED ); - if ( !GetEventHandler()->ProcessEvent(event) ) + wxSize size = GetBestSize(); + + if (GetWindowStyle() & wxSL_VERTICAL) { - event.SetEventType( oldEvent ); - if (!GetParent()->GetEventHandler()->ProcessEvent(event)) - event.Skip(); + SetMinSize( wxSize(size.x,minH) ); + SetMaxSize( wxSize(size.x,maxH) ); } -#else - GetEventHandler()->ProcessEvent(event); -#endif + else + { + SetMinSize( wxSize(minW,size.y) ); + SetMaxSize( wxSize(maxW,size.y) ); + } +} + +wxSize wxSlider::DoGetBestSize() const +{ + wxSize size; + int textwidth, textheight; + int mintwidth, mintheight; + int maxtwidth, maxtheight; + + textwidth = textheight = 0; + mintwidth = mintheight = 0; + maxtwidth = maxtheight = 0; + + if (GetWindowStyle() & wxSL_LABELS) + { + wxString text; + + // Get maximum text label width and height + text.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMin ) ); + GetTextExtent(text, &mintwidth, &mintheight); + text.Printf( wxT("%d"), ValueInvertOrNot( m_rangeMax ) ); + GetTextExtent(text, &maxtwidth, &maxtheight); + + if (maxtheight > mintheight) + textheight = maxtheight; + else + textheight = mintheight; + + if (maxtwidth > mintwidth) + textwidth = maxtwidth; + else + textwidth = mintwidth; + } + + if (GetWindowStyle() & wxSL_VERTICAL) + { + size.y = 150; + + if (GetWindowStyle() & wxSL_AUTOTICKS) + size.x = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS; + else + size.x = wxSLIDER_DIMENSIONACROSS_ARROW; + + if (GetWindowStyle() & wxSL_LABELS) + size.x += textwidth + wxSLIDER_BORDERTEXT; + } + else + { + size.x = 150; + + if (GetWindowStyle() & wxSL_AUTOTICKS) + size.y = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS; + else + size.y = wxSLIDER_DIMENSIONACROSS_ARROW; + + if (GetWindowStyle() & wxSL_LABELS) + { + size.y += textheight + wxSLIDER_BORDERTEXT; + size.x += (mintwidth / 2) + (maxtwidth / 2); + } + } + + return size; +} + +void wxSlider::DoSetSize(int x, int y, int w, int h, int sizeFlags) +{ + int yborder = 0; + int minValWidth, maxValWidth, textheight; + int sliderBreadth; + int width = w; + + if (GetWindowStyle() & wxSL_LABELS) + { + wxString text; + int ht, valValWidth; + + // Get maximum text label width and height + text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin ) ); + GetTextExtent(text, &minValWidth, &textheight); + text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax ) ); + GetTextExtent(text, &maxValWidth, &ht); + + if (ht > textheight) + textheight = ht; + + if (GetWindowStyle() & wxSL_HORIZONTAL) + { + if ( m_macMinimumStatic ) + { + w -= minValWidth / 2; + x += minValWidth / 2; + } + + if ( m_macMaximumStatic ) + w -= maxValWidth / 2; + } + + // Labels have this control's parent as their parent + // so if this control is not at 0,0 relative to the parent + // the labels need to know the position of this control + // relative to its parent in order to size properly, so + // move the control first so we can use GetPosition() + wxControl::DoSetSize( x, y, w, h, sizeFlags ); + + if (GetWindowStyle() & wxSL_VERTICAL) + // If vertical, use current value + text.Printf(wxT("%d"), (int)m_peer->GetValue()); + else + // Use max so that the current value doesn't drift as centering would need to change + text.Printf(wxT("%d"), m_rangeMax); + + GetTextExtent(text, &valValWidth, &ht); + + yborder = textheight + wxSLIDER_BORDERTEXT; + + // Get slider breadth + if (GetWindowStyle() & wxSL_AUTOTICKS) + sliderBreadth = wxSLIDER_DIMENSIONACROSS_WITHTICKMARKS; + else + sliderBreadth = wxSLIDER_DIMENSIONACROSS_ARROW; + + if (GetWindowStyle() & wxSL_VERTICAL) + { + h = h - yborder; + + if ( m_macMinimumStatic ) + m_macMinimumStatic->Move(GetPosition().x + sliderBreadth + wxSLIDER_BORDERTEXT, GetPosition().y + h - yborder); + if ( m_macMaximumStatic ) + m_macMaximumStatic->Move(GetPosition().x + sliderBreadth + wxSLIDER_BORDERTEXT, GetPosition().y + 0); + if ( m_macValueStatic ) + m_macValueStatic->Move(GetPosition().x + sliderBreadth + wxSLIDER_BORDERTEXT, GetPosition().y + (h / 2) - (ht / 2)); + } + else + { + if ( m_macMinimumStatic ) + m_macMinimumStatic->Move(GetPosition().x, GetPosition().y + sliderBreadth + wxSLIDER_BORDERTEXT); + if ( m_macMaximumStatic ) + m_macMaximumStatic->Move(GetPosition().x + w - maxValWidth, GetPosition().y + sliderBreadth + wxSLIDER_BORDERTEXT); + if ( m_macValueStatic ) + m_macValueStatic->Move(GetPosition().x + (w / 2) - (valValWidth / 2), GetPosition().y + sliderBreadth + wxSLIDER_BORDERTEXT); + } + } + + // yet another hack since this is a composite control + // when wxSlider has it's size hardcoded, we're not allowed to + // change the size. But when the control has labels, we DO need + // to resize the internal Mac control to accommodate the text labels. + // We need to trick the wxWidgets resize mechanism so that we can + // resize the slider part of the control ONLY. + + // TODO: Can all of this code go in the conditional wxSL_LABELS block? + + int minWidth = m_minWidth; + + if (GetWindowStyle() & wxSL_LABELS) + { + // make sure we don't allow the entire control to be resized accidently + if (width == GetSize().x) + m_minWidth = -1; + } + + // If the control has labels, we still need to call this again because + // the labels alter the control's w and h values. + wxControl::DoSetSize( x, y, w, h, sizeFlags ); + + m_minWidth = minWidth; +} + +void wxSlider::DoMoveWindow(int x, int y, int width, int height) +{ + wxControl::DoMoveWindow( x, y, width, height ); } + +// Common processing to invert slider values based on wxSL_INVERSE +int wxSlider::ValueInvertOrNot(int value) const +{ + int result = 0; + + if (m_windowStyle & wxSL_VERTICAL) + { + // The reason for the backwards logic is that Mac's vertical sliders are + // inverted compared to Windows and GTK, hence we want inversion to be the + // default, and if wxSL_INVERSE is set, then we do not invert (use native) + if (m_windowStyle & wxSL_INVERSE) + result = value; + else + result = (m_rangeMax + m_rangeMin) - value; + } + else // normal logic applies to HORIZONTAL sliders + { + result = wxSliderBase::ValueInvertOrNot(value); + } + + return result; +} + +#endif // wxUSE_SLIDER