X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/936f635341e9b92b37db93cc7781d564babbe25f..96c9640205933ad0673d5af2c96af0816c50160c:/src/msw/slider.cpp diff --git a/src/msw/slider.cpp b/src/msw/slider.cpp index 5eabd63b7d..23e8f0ac87 100644 --- a/src/msw/slider.cpp +++ b/src/msw/slider.cpp @@ -40,6 +40,9 @@ // constants // ---------------------------------------------------------------------------- +namespace +{ + // indices of labels in wxSlider::m_labels enum { @@ -49,80 +52,16 @@ enum SliderLabel_Last }; -// the gap between the slider and the labels, in pixels -static const int HGAP = 5; - -// ---------------------------------------------------------------------------- -// XTI -// ---------------------------------------------------------------------------- +// the gaps between the slider and the labels, in pixels +const int HGAP = 5; +const int VGAP = 4; +// the width of the borders including white space +const int BORDERPAD = 8; +// these 2 values are arbitrary: +const int THUMB = 24; +const int TICK = 8; -#if wxUSE_EXTENDED_RTTI -WX_DEFINE_FLAGS( wxSliderStyle ) - -wxBEGIN_FLAGS( wxSliderStyle ) - // new style border flags, we put them first to - // use them for streaming out - wxFLAGS_MEMBER(wxBORDER_SIMPLE) - wxFLAGS_MEMBER(wxBORDER_SUNKEN) - wxFLAGS_MEMBER(wxBORDER_DOUBLE) - wxFLAGS_MEMBER(wxBORDER_RAISED) - wxFLAGS_MEMBER(wxBORDER_STATIC) - wxFLAGS_MEMBER(wxBORDER_NONE) - - // old style border flags - wxFLAGS_MEMBER(wxSIMPLE_BORDER) - wxFLAGS_MEMBER(wxSUNKEN_BORDER) - wxFLAGS_MEMBER(wxDOUBLE_BORDER) - wxFLAGS_MEMBER(wxRAISED_BORDER) - wxFLAGS_MEMBER(wxSTATIC_BORDER) - wxFLAGS_MEMBER(wxBORDER) - - // standard window styles - wxFLAGS_MEMBER(wxTAB_TRAVERSAL) - wxFLAGS_MEMBER(wxCLIP_CHILDREN) - wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) - wxFLAGS_MEMBER(wxWANTS_CHARS) - wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) - wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) - wxFLAGS_MEMBER(wxVSCROLL) - wxFLAGS_MEMBER(wxHSCROLL) - - wxFLAGS_MEMBER(wxSL_HORIZONTAL) - wxFLAGS_MEMBER(wxSL_VERTICAL) - wxFLAGS_MEMBER(wxSL_AUTOTICKS) - wxFLAGS_MEMBER(wxSL_LABELS) - wxFLAGS_MEMBER(wxSL_LEFT) - wxFLAGS_MEMBER(wxSL_TOP) - wxFLAGS_MEMBER(wxSL_RIGHT) - wxFLAGS_MEMBER(wxSL_BOTTOM) - wxFLAGS_MEMBER(wxSL_BOTH) - wxFLAGS_MEMBER(wxSL_SELRANGE) - wxFLAGS_MEMBER(wxSL_INVERSE) - -wxEND_FLAGS( wxSliderStyle ) - -IMPLEMENT_DYNAMIC_CLASS_XTI(wxSlider, wxControl,"wx/slider.h") - -wxBEGIN_PROPERTIES_TABLE(wxSlider) - wxEVENT_RANGE_PROPERTY( Scroll , wxEVT_SCROLL_TOP , wxEVT_SCROLL_CHANGED , wxScrollEvent ) - wxEVENT_PROPERTY( Updated , wxEVT_COMMAND_SLIDER_UPDATED , wxCommandEvent ) - - wxPROPERTY( Value , int , SetValue, GetValue , 0, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Minimum , int , SetMin, GetMin, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( Maximum , int , SetMax, GetMax, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( PageSize , int , SetPageSize, GetLineSize, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( LineSize , int , SetLineSize, GetLineSize, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY( ThumbLength , int , SetThumbLength, GetThumbLength, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) - wxPROPERTY_FLAGS( WindowStyle , wxSliderStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style -wxEND_PROPERTIES_TABLE() - -wxBEGIN_HANDLERS_TABLE(wxSlider) -wxEND_HANDLERS_TABLE() - -wxCONSTRUCTOR_8( wxSlider , wxWindow* , Parent , wxWindowID , Id , int , Value , int , Minimum , int , Maximum , wxPoint , Position , wxSize , Size , long , WindowStyle ) -#else -IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl) -#endif +} // anonymous namespace // ============================================================================ // wxSlider implementation @@ -145,18 +84,20 @@ void wxSlider::Init() m_isDragging = false; } -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) { + wxCHECK_MSG( minValue < maxValue, false, + wxT("Slider minimum must be strictly less than the maximum.") ); + // 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 @@ -183,7 +124,7 @@ wxSlider::Create(wxWindow *parent, }; wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL), - _T("incompatible slider direction and orientation") ); + wxT("incompatible slider direction and orientation") ); // initialize everything @@ -224,7 +165,6 @@ wxSlider::Create(wxWindow *parent, m_labels->Set(n, wnd, lblid); } - m_labels->SetFont(GetFont()); } @@ -235,7 +175,7 @@ wxSlider::Create(wxWindow *parent, // and initialize everything SetRange(minValue, maxValue); SetValue(value); - SetPageSize((maxValue - minValue)/10); + SetPageSize( wxMax(1, (maxValue - minValue)/10) ); // we need to position the labels correctly if we have them and if // SetSize() hadn't been called before (when best size was determined by @@ -425,25 +365,20 @@ void wxSlider::DoGetPosition(int *x, int *y) const *y = rect.y; } -int wxSlider::GetLabelsSize(int *width) const +int wxSlider::GetLabelsSize(int *widthMin, int *widthMax) const { - int cy; - - if ( width ) + if ( widthMin && widthMax ) { - // find the max label width - int wLabelMin, wLabelMax; - GetTextExtent(Format(m_rangeMin), &wLabelMin, &cy); - GetTextExtent(Format(m_rangeMax), &wLabelMax, &cy); + *widthMin = GetTextExtent(Format(m_rangeMin)).x; + *widthMax = GetTextExtent(Format(m_rangeMax)).x; - *width = wxMax(wLabelMin, wLabelMax); - } - else - { - cy = GetCharHeight(); + if ( HasFlag(wxSL_INVERSE) ) + { + wxSwap(*widthMin, *widthMax); + } } - return EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); + return HasFlag(wxSL_LABELS) ? GetCharHeight() : 0; } void wxSlider::DoMoveWindow(int x, int y, int width, int height) @@ -456,81 +391,145 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height) return; } + int minLabelWidth, + maxLabelWidth; + const int labelHeight = GetLabelsSize(&minLabelWidth, &maxLabelWidth); + const int longestLabelWidth = wxMax(minLabelWidth, maxLabelWidth); + if ( !HasFlag(wxSL_MIN_MAX_LABELS) ) + { + minLabelWidth = + maxLabelWidth = 0; + } + + int tickOffset = 0; + if ( HasFlag(wxSL_TICKS)) + tickOffset = TICK; + if ( HasFlag(wxSL_BOTH)) + tickOffset *= 2; + // be careful to position the slider itself after moving the labels as // otherwise our GetBoundingBox(), which is called from WM_SIZE handler, // would return a wrong result and wrong size would be cached internally if ( HasFlag(wxSL_VERTICAL) ) { - int wLabel; - int hLabel = GetLabelsSize(&wLabel); + int labelOffset = 0; + int holdTopX; + int holdBottomX; + int xLabel = (wxMax((THUMB + (BORDERPAD * 2)), longestLabelWidth) / 2) - + (longestLabelWidth / 2) + x; + if ( HasFlag(wxSL_LEFT) ) + { + holdTopX = xLabel; + holdBottomX = xLabel - (abs(maxLabelWidth - minLabelWidth) / 2); + } + else // wxSL_RIGHT + { + holdTopX = xLabel + longestLabelWidth + (abs(maxLabelWidth - minLabelWidth) / 2); + holdBottomX = xLabel + longestLabelWidth; - int xLabel = HasFlag(wxSL_LEFT) ? x + width - wLabel : x; + labelOffset = longestLabelWidth + HGAP; + } - // position all labels: min at the top, value in the middle and max at - // the bottom - DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min], - xLabel, y, wLabel, hLabel); + if ( HasFlag(wxSL_MIN_MAX_LABELS) ) + { + if ( HasFlag(wxSL_INVERSE) ) + { + wxSwap(holdTopX, holdBottomX); + } - DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value], - xLabel, y + (height - hLabel)/2, wLabel, hLabel); + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min], + holdTopX, + y, + minLabelWidth, labelHeight); + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max], + holdBottomX, + y + height - labelHeight, + maxLabelWidth, labelHeight); + } - DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max], - xLabel, y + height - hLabel, wLabel, hLabel); + if ( HasFlag(wxSL_VALUE_LABEL) ) + { + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value], + x + ( HasFlag(wxSL_LEFT) ? THUMB + tickOffset + HGAP : 0 ), + y + (height - labelHeight)/2, + longestLabelWidth, labelHeight); + } // position the slider itself along the left/right edge - wxSliderBase::DoMoveWindow(HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP, - y + hLabel/2, - width - wLabel - HGAP, - height - hLabel); + wxSliderBase::DoMoveWindow( + x + labelOffset, + y + labelHeight, + THUMB + tickOffset + HGAP, + height - (labelHeight * 2)); } else // horizontal { - int wLabel; - int hLabel = GetLabelsSize(&wLabel); + int yLabelMinMax = + (y + ((THUMB + tickOffset) / 2)) - (labelHeight / 2); + int xLabelValue = + x + minLabelWidth + + ((width - (minLabelWidth + maxLabelWidth)) / 2) - + (longestLabelWidth / 2); - int yLabel = HasFlag(wxSL_TOP) ? y + height - hLabel : y; + int ySlider = y; - // position all labels: min on the left, value in the middle and max to - // the right - DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min], - x, yLabel, wLabel, hLabel); + if ( HasFlag(wxSL_VALUE_LABEL) ) + { + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value], + xLabelValue, + y + (HasFlag(wxSL_BOTTOM) ? 0 : THUMB + tickOffset), + longestLabelWidth, labelHeight); - DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value], - x + (width - wLabel)/2, yLabel, wLabel, hLabel); + if ( HasFlag(wxSL_BOTTOM) ) + { + ySlider += labelHeight; + yLabelMinMax += labelHeight; + } + } - DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max], - x + width - wLabel, yLabel, wLabel, hLabel); + if ( HasFlag(wxSL_MIN_MAX_LABELS) ) + { + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min], + x, + yLabelMinMax, + minLabelWidth, labelHeight); + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max], + x + width - maxLabelWidth, + yLabelMinMax, + maxLabelWidth, labelHeight); + } // position the slider itself along the top/bottom edge - wxSliderBase::DoMoveWindow(x, - HasFlag(wxSL_TOP) ? y : y + hLabel, - width, - height - hLabel); + wxSliderBase::DoMoveWindow( + x + minLabelWidth + VGAP, + ySlider, + width - (minLabelWidth + maxLabelWidth + (VGAP*2)), + THUMB + tickOffset); } } wxSize wxSlider::DoGetBestSize() const { - // these values are arbitrary + // this value is arbitrary: static const int length = 100; - static const int thumb = 24; - static const int ticks = 8; int *width; wxSize size; if ( HasFlag(wxSL_VERTICAL) ) { - size.x = thumb; + size.x = THUMB; size.y = length; width = &size.x; if ( m_labels ) { - int wLabel; - int hLabel = GetLabelsSize(&wLabel); + int widthMin, + widthMax; + int hLabel = GetLabelsSize(&widthMin, &widthMax); // account for the labels - size.x += HGAP + wLabel; + if ( HasFlag(wxSL_MIN_MAX_LABELS) ) + size.x += HGAP + wxMax(widthMin, widthMax); // labels are indented relative to the slider itself size.y += hLabel; @@ -539,26 +538,33 @@ wxSize wxSlider::DoGetBestSize() const else // horizontal { size.x = length; - size.y = thumb; + size.y = THUMB; width = &size.y; if ( m_labels ) { - // labels add extra height - size.y += GetLabelsSize(); + int labelSize = GetLabelsSize(); + + // Min/max labels are compensated by the ticks so we don't need + // extra space for them if we're also showing ticks. + if ( HasFlag(wxSL_MIN_MAX_LABELS) && !HasFlag(wxSL_TICKS) ) + size.y += labelSize; + + // The value label is always on top of the control and so does need + // extra space in any case. + if ( HasFlag(wxSL_VALUE_LABEL) ) + size.y += labelSize; } } // need extra space to show ticks if ( HasFlag(wxSL_TICKS) ) { - *width += ticks; - + *width += TICK; // and maybe twice as much if we show them on both sides if ( HasFlag(wxSL_BOTH) ) - *width += ticks; + *width += TICK; } - return size; } @@ -583,6 +589,11 @@ void wxSlider::SetValue(int value) void wxSlider::SetRange(int minValue, int maxValue) { + // Remember the old logical value if we need to update the physical control + // value after changing its range in wxSL_INVERSE case (and avoid an + // unnecessary call to GetValue() otherwise as it's just not needed). + const int valueOld = HasFlag(wxSL_INVERSE) ? GetValue() : 0; + m_rangeMin = minValue; m_rangeMax = maxValue; @@ -596,12 +607,20 @@ void wxSlider::SetRange(int minValue, int maxValue) ::SetWindowText((*m_labels)[SliderLabel_Max], Format(ValueInvertOrNot(m_rangeMax)).wx_str()); } + + // When emulating wxSL_INVERSE style in wxWidgets, we need to update the + // value after changing the range to ensure that the value seen by the user + // code, i.e. the one returned by GetValue(), does not change. + if ( HasFlag(wxSL_INVERSE) ) + { + ::SendMessage(GetHwnd(), TBM_SETPOS, TRUE, ValueInvertOrNot(valueOld)); + } } -void wxSlider::SetTickFreq(int n, int pos) +void wxSlider::DoSetTickFreq(int n) { m_tickFreq = n; - ::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) pos ); + ::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) 0 ); } void wxSlider::SetPageSize(int pageSize)