X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b45ed7a273799b1b360482496a706a211eca6435..8b2858410444b111cb192d1539ef6c76209091fd:/src/mac/carbon/slider.cpp?ds=sidebyside diff --git a/src/mac/carbon/slider.cpp b/src/mac/carbon/slider.cpp index 4bd4bab532..d7613a3edd 100644 --- a/src/mac/carbon/slider.cpp +++ b/src/mac/carbon/slider.cpp @@ -9,33 +9,31 @@ // 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 15 #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 dosen't specify the orientation we have to assume he wants a * horizontal one. Therefore in this file when testing for the sliders orientation * vertical is tested for if this is not set then we use the horizontal one - * eg. if(GetWindowStyle() & wxSL_VERTICAL) {} else { horizontal case }> + * eg. if(GetWindowStyle() & wxSL_VERTICAL) {} else { horizontal case }> */ // Slider @@ -48,8 +46,6 @@ END_EVENT_TABLE() m_tickFreq = 0; } -extern ControlActionUPP wxMacLiveScrollbarActionUPP ; - bool wxSlider::Create(wxWindow *parent, wxWindowID id, int value, int minValue, int maxValue, const wxPoint& pos, @@ -57,57 +53,69 @@ bool wxSlider::Create(wxWindow *parent, wxWindowID id, const wxValidator& validator, const wxString& name) { + m_macIsUserPane = false ; + + // 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: + // no specific direction, do we have at least the orientation? + if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) ) + { + // no, choose default + style |= wxSL_BOTTOM | wxSL_HORIZONTAL; + } + }; + + wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL), + _T("incompatible slider direction and orientation") ); + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) return false; - Rect bounds ; - Str255 title ; - SInt16 procID; - 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); - - MacPreControlCreate( parent, id, wxEmptyString, pos, size, style, - validator, name, &bounds, title ); - - procID = kControlSliderProc + kControlSliderLiveFeedback; - if(style & wxSL_AUTOTICKS) { - procID += kControlSliderHasTickMarks; - } - - - m_macControl = ::NewControl( MAC_WXHWND(parent->MacGetRootWindow()), &bounds, title, false, - value, minValue, maxValue, procID, (long) this); - - wxASSERT_MSG( (ControlHandle) m_macControl != NULL , wxT("No valid mac control") ) ; - - ::SetControlAction( (ControlHandle) m_macControl , wxMacLiveScrollbarActionUPP ) ; - - if(style & wxSL_LABELS) - { - m_macMinimumStatic = new wxStaticText( this, -1, wxEmptyString ); - m_macMaximumStatic = new wxStaticText( this, -1, wxEmptyString ); - m_macValueStatic = new wxStaticText( this, -1, wxEmptyString ); - SetRange(minValue, maxValue); - SetValue(value); - } - - else { - m_macMinimumStatic = NULL ; - m_macMaximumStatic = NULL ; - m_macValueStatic = NULL ; - } - + + Rect bounds = wxMacGetBoundsForControl( this , pos , size ) ; + + // + // NB: (RN) Ticks here are sometimes off in the GUI if there + // is not as many ticks as there are values + // + UInt16 tickMarks = 0 ; + if ( style & wxSL_AUTOTICKS ) + tickMarks = (maxValue - minValue) + 1; //+1 for the 0 value + + while (tickMarks > 20) + tickMarks /= 5; //keep the number of tickmarks from becoming unwieldly + + m_peer = new wxMacControl(this) ; + verify_noerr ( CreateSliderControl( MAC_WXHWND(parent->MacGetTopLevelWindowRef()) , &bounds , + value , minValue , maxValue , kControlSliderPointsDownOrRight , tickMarks , true /* liveTracking */ , + GetwxMacLiveScrollbarActionProc() , m_peer->GetControlRefAddr() ) ); + if(style & wxSL_VERTICAL) { SetSizeHints(10, -1, 10, -1); // Forces SetSize to use the proper width } @@ -117,46 +125,66 @@ bool wxSlider::Create(wxWindow *parent, wxWindowID id, // 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 - - MacPostControlCreate() ; - + + 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() == false ) + { + delete m_macMinimumStatic ; + delete m_macMaximumStatic ; + delete m_macValueStatic ; + } } int wxSlider::GetValue() const { - return GetControl32BitValue( (ControlHandle) 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( wxT("%d") , value ) ; + valuestring.Printf( wxT("%d") , value ) ; if ( m_macValueStatic ) m_macValueStatic->SetLabel( valuestring ) ; - SetControl32BitValue( (ControlHandle) m_macControl , value ) ; + + // 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; - - SetControl32BitMinimum( (ControlHandle) m_macControl, m_rangeMin); - SetControl32BitMaximum( (ControlHandle) m_macControl, m_rangeMax); - + + m_peer->SetMinimum( m_rangeMin); + m_peer->SetMaximum( m_rangeMax); + if(m_macMinimumStatic) { - value.Printf(wxT("%d"), m_rangeMin); + value.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin ) ); m_macMinimumStatic->SetLabel(value); } if(m_macMaximumStatic) { - value.Printf(wxT("%d"), m_rangeMax); + value.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax ) ); m_macMaximumStatic->SetLabel(value); } SetValue(m_rangeMin); @@ -241,70 +269,102 @@ void wxSlider::Command (wxCommandEvent & event) ProcessCommand (event); } -void wxSlider::MacHandleControlClick( WXWidget control , wxInt16 controlpart, bool mouseStillDown ) +void wxSlider::MacHandleControlClick( WXWidget control , wxInt16 controlpart, bool mouseStillDown ) { - SInt16 value = ::GetControl32BitValue( (ControlHandle) m_macControl ) ; - - SetValue( value ) ; - + // Whatever the native value is, we may need to invert it for calling + // SetValue and putting the possibly inverted value in the event + SInt16 value = ValueInvertOrNot ( m_peer->GetValue() ) ; + + SetValue( value ) ; + wxEventType scrollEvent = wxEVT_NULL ; - - if ( mouseStillDown ) - scrollEvent = wxEVT_SCROLL_THUMBTRACK; - else - scrollEvent = wxEVT_SCROLL_THUMBRELEASE; - + + scrollEvent = wxEVT_SCROLL_THUMBTRACK; + + wxScrollEvent event(scrollEvent, m_windowId); + event.SetPosition(value); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); + + wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId ); + cevent.SetInt( value ); + cevent.SetEventObject( this ); + + GetEventHandler()->ProcessEvent( cevent ); +} + +wxInt32 wxSlider::MacControlHit( WXEVENTHANDLERREF handler , WXEVENTREF mevent ) +{ + // Whatever the native value is, we may need to invert it for calling + // SetValue and putting the possibly inverted value in the event + SInt16 value = ValueInvertOrNot ( m_peer->GetValue() ) ; + + SetValue( value ) ; + + wxEventType scrollEvent = wxEVT_NULL ; + + scrollEvent = wxEVT_SCROLL_THUMBRELEASE; + wxScrollEvent event(scrollEvent, m_windowId); event.SetPosition(value); event.SetEventObject( this ); GetEventHandler()->ProcessEvent(event); - + wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, m_windowId ); cevent.SetInt( value ); cevent.SetEventObject( this ); - + GetEventHandler()->ProcessEvent( cevent ); + return noErr ; } /* 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::SetSizeHints( int minW, int minH, - int maxW , int maxH , - int incW , int incH ) +void wxSlider::DoSetSizeHints( int minW, int minH, + int maxW , int maxH , + int incW , int incH ) { wxSize size = GetBestSize(); - + if(GetWindowStyle() & wxSL_VERTICAL) { - wxWindow::SetSizeHints(size.x, minH, size.x, maxH, incW, incH); + wxWindow::DoSetSizeHints(size.x, minH, size.x, maxH, incW, incH); } else { - wxWindow::SetSizeHints(minW, size.y, maxW, size.y, incW, incH); + wxWindow::DoSetSizeHints(minW, size.y, maxW, size.y, incW, incH); } } wxSize wxSlider::DoGetBestSize() const { wxSize size; - int textwidth, textheight; - + int textwidth = 0; + int textheight = 0; + int mintwidth, mintheight; + int maxtwidth, maxtheight; + if(GetWindowStyle() & wxSL_LABELS) { wxString text; - int ht, wd; - + // Get maximum text label width and height - text.Printf(wxT("%d"), m_rangeMin); - GetTextExtent(text, &textwidth, &textheight); - text.Printf(wxT("%d"), m_rangeMax); - GetTextExtent(text, &wd, &ht); - if(ht > textheight) { - textheight = ht; + 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; } - if (wd > textwidth) { - textwidth = wd; + else { + textheight = mintheight; + } + if (maxtwidth > mintwidth) { + textwidth = maxtwidth; + } + else { + textwidth = mintwidth; } } - + if(GetWindowStyle() & wxSL_VERTICAL) { if(GetWindowStyle() & wxSL_AUTOTICKS) { @@ -326,58 +386,76 @@ wxSize wxSlider::DoGetBestSize() const else { size.y = wxSLIDER_DIMENSIONACROSS_ARROW; } + + size.x = 150; + if(GetWindowStyle() & wxSL_LABELS) { size.y += textheight + wxSLIDER_BORDERTEXT; + size.x += (mintwidth/2) + (maxtwidth/2); } - size.x = 150; } return size; } -void wxSlider::DoSetSize(int x, int y, int width, int height, int sizeFlags) -{ - wxControl::DoSetSize( x, y , width , height ,sizeFlags ) ; -} - -void wxSlider::MacUpdateDimensions() +void wxSlider::DoSetSize(int x, int y, int w, int h, int sizeFlags) { - // actually in the current systems this should never be possible, but later reparenting - // may become a reality - - if ( (ControlHandle) m_macControl == NULL ) - return ; - - if ( GetParent() == NULL ) - return ; - - WindowRef rootwindow = (WindowRef) MacGetRootWindow() ; - if ( rootwindow == NULL ) - return ; - int xborder, yborder; - int minValWidth, maxValWidth, textwidth, textheight; + int minValWidth, maxValWidth, textheight; int sliderBreadth; - + int width = w; + xborder = yborder = 0; - + if (GetWindowStyle() & wxSL_LABELS) { + wxString text; - int ht; - + int ht, valValWidth; + // Get maximum text label width and height - text.Printf(wxT("%d"), m_rangeMin); + text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMin ) ); GetTextExtent(text, &minValWidth, &textheight); - text.Printf(wxT("%d"), m_rangeMax); + text.Printf(wxT("%d"), ValueInvertOrNot( m_rangeMax ) ); GetTextExtent(text, &maxValWidth, &ht); + if(ht > textheight) { textheight = ht; } - textwidth = (minValWidth > maxValWidth ? minValWidth : maxValWidth); - - xborder = textwidth + wxSLIDER_BORDERTEXT; + + 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 vertical, use current value + if(GetWindowStyle() & wxSL_VERTICAL) + { + text.Printf(wxT("%d"), (int)m_peer->GetValue()); + } + // Use max so that the current value doesn't drift as centering would need to change + else + { + 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; @@ -385,49 +463,76 @@ void wxSlider::MacUpdateDimensions() else { sliderBreadth = wxSLIDER_DIMENSIONACROSS_ARROW; } - + if(GetWindowStyle() & wxSL_VERTICAL) { - m_macMinimumStatic->Move(sliderBreadth + wxSLIDER_BORDERTEXT, - m_height - yborder - textheight); - m_macMaximumStatic->Move(sliderBreadth + wxSLIDER_BORDERTEXT, 0); - m_macValueStatic->Move(0, m_height - textheight); + 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 { - m_macMinimumStatic->Move(0, sliderBreadth + wxSLIDER_BORDERTEXT); - m_macMaximumStatic->Move(m_width - xborder - maxValWidth / 2, - sliderBreadth + wxSLIDER_BORDERTEXT); - m_macValueStatic->Move(m_width - textwidth, 0); + 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); } } - - Rect oldBounds ; - GetControlBounds( (ControlHandle) m_macControl , &oldBounds ) ; - - int new_x = m_x + MacGetLeftBorderSize() + m_macHorizontalBorder ; - int new_y = m_y + MacGetTopBorderSize() + m_macVerticalBorder ; - int new_width = m_width - MacGetLeftBorderSize() - MacGetRightBorderSize() - 2 * m_macHorizontalBorder - xborder ; - int new_height = m_height - MacGetTopBorderSize() - MacGetBottomBorderSize() - 2 * m_macVerticalBorder - yborder ; - - GetParent()->MacWindowToRootWindow( & new_x , & new_y ) ; - bool doMove = new_x != oldBounds.left || new_y != oldBounds.top ; - bool doResize = ( oldBounds.right - oldBounds.left ) != new_width || (oldBounds.bottom - oldBounds.top ) != new_height ; - if ( doMove || doResize ) + + // 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; + minWidth = m_minWidth; + + if (GetWindowStyle() & wxSL_LABELS) { - InvalWindowRect( rootwindow, &oldBounds ) ; - if ( doMove ) - { - UMAMoveControl( (ControlHandle) m_macControl , new_x , new_y ) ; - } - if ( doResize ) - { - UMASizeControl( (ControlHandle) m_macControl , new_width , new_height ) ; - } + // 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 +{ + 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) + return value; + else + return (m_rangeMax + m_rangeMin) - value; + } + else // normal logic applies to HORIZONTAL sliders + { + return wxSliderBase::ValueInvertOrNot(value); + } +} + +#endif // wxUSE_SLIDER