From c04abaf92b77912bae71e830d1df83de80063413 Mon Sep 17 00:00:00 2001 From: "enndeakin@sympatico.ca" Date: Mon, 9 Apr 2007 15:39:57 -0700 Subject: [PATCH] Bug 372047, support reverse direction scales, r=neil,josh --- layout/xul/base/src/nsSliderFrame.cpp | 158 ++++++++++++++----------- layout/xul/base/src/nsSliderFrame.h | 5 +- toolkit/content/widgets/scale.xml | 32 +++-- widget/src/cocoa/nsNativeThemeCocoa.h | 3 +- widget/src/cocoa/nsNativeThemeCocoa.mm | 10 +- xpfe/global/jar.mn | 2 +- 6 files changed, 128 insertions(+), 82 deletions(-) diff --git a/layout/xul/base/src/nsSliderFrame.cpp b/layout/xul/base/src/nsSliderFrame.cpp index 2087ed0348f4..9157383f5f42 100644 --- a/layout/xul/base/src/nsSliderFrame.cpp +++ b/layout/xul/base/src/nsSliderFrame.cpp @@ -398,21 +398,23 @@ nsSliderFrame::DoLayout(nsBoxLayoutState& aState) if (float(maxpos) != 0) mRatio = float(ourmaxpos) / float(maxpos); - nscoord curpos = (curpospx - minpospx) * onePixel; + // in reverse mode, curpos is reversed such that lower values are to the + // right or bottom and increase leftwards or upwards. In this case, use the + // offset from the end instead of the beginning. + PRBool reverse = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, + nsGkAtoms::reverse, eCaseMatters); + nscoord pos = reverse ? (maxpospx - curpospx) : (curpospx - minpospx); - // set the thumbs y coord to be the current pos * the ratio. - nscoord pos = nscoord(float(curpos)*mRatio); + // set the thumb's coord to be the current pos * the ratio. nsRect thumbRect(clientRect.x, clientRect.y, thumbSize.width, thumbSize.height); - if (isHorizontal) - thumbRect.x += pos; + thumbRect.x += nscoord(float(pos * onePixel) * mRatio); else - thumbRect.y += pos; + thumbRect.y += nscoord(float(pos * onePixel) * mRatio); nsRect oldThumbRect(thumbBox->GetRect()); LayoutChildAt(aState, thumbBox, thumbRect); - SyncLayout(aState); #ifdef DEBUG_SLIDER @@ -494,11 +496,10 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext, if (isMouseOutsideThumb) { // XXX see bug 81586 - SetCurrentPosition(scrollbar, thumbFrame, (int) (mThumbStart / onePixel / mRatio), PR_FALSE); + SetCurrentPosition(scrollbar, (int) (mThumbStart / onePixel / mRatio), PR_FALSE); return NS_OK; } - // convert to pixels nscoord pospx = pos/onePixel; @@ -514,8 +515,7 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext, } // set it - SetCurrentPosition(scrollbar, thumbFrame, pospx, PR_FALSE); - + SetCurrentPosition(scrollbar, pospx, PR_FALSE); } break; @@ -566,12 +566,11 @@ nsSliderFrame::HandleEvent(nsPresContext* aPresContext, thumbLength /= onePixel; pospx -= (thumbLength/2); - // convert to our internal coordinate system pospx = nscoord(pospx/mRatio); // set it - SetCurrentPosition(scrollbar, thumbFrame, pospx, PR_FALSE); + SetCurrentPosition(scrollbar, pospx, PR_FALSE); DragThumb(PR_TRUE); @@ -610,7 +609,7 @@ nsSliderFrame::GetScrollbar() } void -nsSliderFrame::PageUpDown(nsIFrame* aThumbFrame, nscoord change) +nsSliderFrame::PageUpDown(nscoord change) { // on a page up or down get our page increment. We get this by getting the scrollbar we are in and // asking it for the current position and the page increment. If we are not in a scrollbar we will @@ -619,13 +618,26 @@ nsSliderFrame::PageUpDown(nsIFrame* aThumbFrame, nscoord change) nsCOMPtr scrollbar; scrollbar = GetContentOfBox(scrollbarBox); + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, + nsGkAtoms::reverse, eCaseMatters)) + change = -change; + if (mScrollbarListener) mScrollbarListener->PagedUpDown(); // Let the listener decide our increment. nscoord pageIncrement = GetPageIncrement(scrollbar); PRInt32 curpos = GetCurrentPosition(scrollbar); PRInt32 minpos = GetMinPosition(scrollbar); - SetCurrentPosition(scrollbar, aThumbFrame, curpos - minpos + change*pageIncrement, PR_TRUE); + PRInt32 maxpos = GetMaxPosition(scrollbar); + + // get the new position and make sure it is in bounds + PRInt32 newpos = curpos - minpos + change * pageIncrement; + if (newpos < minpos || maxpos < minpos) + newpos = minpos; + else if (newpos > maxpos) + newpos = maxpos; + + SetCurrentPositionInternal(scrollbar, newpos, PR_TRUE); } // called when the current position changed and we need to update the thumb's location @@ -638,62 +650,64 @@ nsSliderFrame::CurrentPositionChanged(nsPresContext* aPresContext) PRBool isHorizontal = IsHorizontal(); - // get the current position - PRInt32 curpos = GetCurrentPosition(scrollbar); + // get the current position + PRInt32 curpospx = GetCurrentPosition(scrollbar); - // do nothing if the position did not change - if (mCurPos == curpos) - return NS_OK; + // do nothing if the position did not change + if (mCurPos == curpospx) + return NS_OK; - // get our current min and max position from our content node - PRInt32 minpos = GetMinPosition(scrollbar); - PRInt32 maxpos = GetMaxPosition(scrollbar); + // get our current min and max position from our content node + PRInt32 minpospx = GetMinPosition(scrollbar); + PRInt32 maxpospx = GetMaxPosition(scrollbar); - if (curpos < minpos || maxpos < minpos) - curpos = minpos; - else if (curpos > maxpos) - curpos = maxpos; + if (curpospx < minpospx || maxpospx < minpospx) + curpospx = minpospx; + else if (curpospx > maxpospx) + curpospx = maxpospx; - // convert to pixels - nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); - nscoord curpospx = (curpos - minpos) * onePixel; + // get the thumb's rect + nsIFrame* thumbFrame = mFrames.FirstChild(); + if (!thumbFrame) + return NS_OK; // The thumb may stream in asynchronously via XBL. - // get the thumb's rect - nsIFrame* thumbFrame = mFrames.FirstChild(); - if (!thumbFrame) - return NS_OK; // The thumb may stream in asynchronously via XBL. + nsRect thumbRect = thumbFrame->GetRect(); - nsRect thumbRect = thumbFrame->GetRect(); + nsRect clientRect; + GetClientRect(clientRect); - nsRect clientRect; - GetClientRect(clientRect); + // figure out the new rect + nsRect newThumbRect(thumbRect); - // figure out the new rect - nsRect newThumbRect(thumbRect); + PRBool reverse = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, + nsGkAtoms::reverse, eCaseMatters); + nscoord pos = reverse ? (maxpospx - curpospx) : (curpospx - minpospx); - if (isHorizontal) - newThumbRect.x = clientRect.x + nscoord(float(curpospx)*mRatio); - else - newThumbRect.y = clientRect.y + nscoord(float(curpospx)*mRatio); + // convert to pixels + nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); + if (isHorizontal) + newThumbRect.x = clientRect.x + nscoord(float(pos * onePixel) * mRatio); + else + newThumbRect.y = clientRect.y + nscoord(float(pos * onePixel) * mRatio); - // set the rect - thumbFrame->SetRect(newThumbRect); + // set the rect + thumbFrame->SetRect(newThumbRect); - // Figure out the union of the rect so we know what to redraw. - // Combine the old and new thumb overflow areas. - nsRect changeRect; - changeRect.UnionRect(thumbFrame->GetOverflowRect() + thumbRect.TopLeft(), - thumbFrame->GetOverflowRect() + newThumbRect.TopLeft()); + // Figure out the union of the rect so we know what to redraw. + // Combine the old and new thumb overflow areas. + nsRect changeRect; + changeRect.UnionRect(thumbFrame->GetOverflowRect() + thumbRect.TopLeft(), + thumbFrame->GetOverflowRect() + newThumbRect.TopLeft()); - // redraw just the change - Invalidate(changeRect, mRedrawImmediate); + // redraw just the change + Invalidate(changeRect, mRedrawImmediate); - if (mScrollbarListener) - mScrollbarListener->PositionChanged(aPresContext, mCurPos, curpos); + if (mScrollbarListener) + mScrollbarListener->PositionChanged(aPresContext, mCurPos, curpospx); - mCurPos = curpos; + mCurPos = curpospx; - return NS_OK; + return NS_OK; } static void UpdateAttribute(nsIContent* aScrollbar, nscoord aNewPos, PRBool aNotify, PRBool aIsSmooth) { @@ -710,23 +724,35 @@ static void UpdateAttribute(nsIContent* aScrollbar, nscoord aNewPos, PRBool aNot } // newpos should be passed to this function as a position as if the minpos is 0. -// That is, the minpos will be added to the position by this function. +// That is, the minpos will be added to the position by this function. In a reverse +// direction slider, the newpos should be the distance from the end. void -nsSliderFrame::SetCurrentPosition(nsIContent* scrollbar, nsIFrame* aThumbFrame, nscoord newpos, PRBool aIsSmooth) +nsSliderFrame::SetCurrentPosition(nsIContent* scrollbar, nscoord newpos, PRBool aIsSmooth) { - - // get our current, min and max position from our content node + // get min and max position from our content node PRInt32 minpos = GetMinPosition(scrollbar); PRInt32 maxpos = GetMaxPosition(scrollbar); - newpos += minpos; + // in reverse direction sliders, flip the value so that it goes from + // right to left, or bottom to top. + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, + nsGkAtoms::reverse, eCaseMatters)) + newpos = maxpos - newpos; + else + newpos += minpos; // get the new position and make sure it is in bounds if (newpos < minpos || maxpos < minpos) - newpos = minpos; + newpos = minpos; else if (newpos > maxpos) - newpos = maxpos; + newpos = maxpos; + SetCurrentPositionInternal(scrollbar, newpos, aIsSmooth); +} + +void +nsSliderFrame::SetCurrentPositionInternal(nsIContent* scrollbar, nscoord newpos, PRBool aIsSmooth) +{ nsIBox* scrollbarBox = GetScrollbar(); nsIScrollbarFrame* scrollbarFrame; CallQueryInterface(scrollbarBox, &scrollbarFrame); @@ -842,7 +868,7 @@ nsSliderFrame::MouseDown(nsIDOMEvent* aMouseEvent) scrollbar = GetContentOfBox(scrollbarBox); // set it - SetCurrentPosition(scrollbar, thumbFrame, pospx, PR_FALSE); + SetCurrentPosition(scrollbar, pospx, PR_FALSE); } DragThumb(PR_TRUE); @@ -972,7 +998,7 @@ nsSliderFrame::HandlePress(nsPresContext* aPresContext, mChange = change; DragThumb(PR_TRUE); mDestinationPoint = eventPoint; - PageUpDown(thumbFrame, change); + PageUpDown(change); nsRepeatService::GetInstance()->Start(mMediator); @@ -1090,7 +1116,7 @@ NS_IMETHODIMP_(void) nsSliderFrame::Notify(nsITimer *timer) if (stop) { nsRepeatService::GetInstance()->Stop(); } else { - PageUpDown(thumbFrame, mChange); + PageUpDown(mChange); } } diff --git a/layout/xul/base/src/nsSliderFrame.h b/layout/xul/base/src/nsSliderFrame.h index 2eb8329d78c7..697a2b146942 100644 --- a/layout/xul/base/src/nsSliderFrame.h +++ b/layout/xul/base/src/nsSliderFrame.h @@ -217,8 +217,9 @@ private: nsIBox* GetScrollbar(); - void PageUpDown(nsIFrame* aThumbFrame, nscoord change); - void SetCurrentPosition(nsIContent* scrollbar, nsIFrame* aThumbFrame, nscoord pos, PRBool aIsSmooth); + void PageUpDown(nscoord change); + void SetCurrentPosition(nsIContent* scrollbar, nscoord pos, PRBool aIsSmooth); + void SetCurrentPositionInternal(nsIContent* scrollbar, nscoord pos, PRBool aIsSmooth); void DragThumb(PRBool aGrabMouseEvents); void AddListener(); void RemoveListener(); diff --git a/toolkit/content/widgets/scale.xml b/toolkit/content/widgets/scale.xml index 678e69384ba9..6b885a62c478 100644 --- a/toolkit/content/widgets/scale.xml +++ b/toolkit/content/widgets/scale.xml @@ -26,7 +26,7 @@ + xbl:inherits="disabled,orient,dir,curpos=value,minpos=min,maxpos=max,increment,pageincrement"> @@ -52,6 +52,18 @@ + + 0) + this.value = this.min; + else if (this.max < 0) + this.value = this.max; + ]]> + + @@ -134,7 +146,7 @@ this.setAttribute("value", event.newValue); var changeEvent = document.createEvent("Events"); - changeEvent.initEvent("change", false, true); + changeEvent.initEvent("change", true, true); this.dispatchEvent(changeEvent); break; @@ -149,28 +161,28 @@ - this.decrease(); + return (this.dir == "reverse") ? this.increase() : this.decrease(); - this.decrease(); + return (this.dir == "reverse") ? this.increase() : this.decrease(); - this.increase(); + return (this.dir == "reverse") ? this.decrease() : this.increase(); - this.increase(); + return (this.dir == "reverse") ? this.decrease() : this.increase(); - this.decreasePage(); + return (this.dir == "reverse") ? this.increasePage() : this.decreasePage(); - this.increasePage(); + return (this.dir == "reverse") ? this.decreasePage() : this.increasePage(); - this.value = this.min; + this.value = (this.dir == "reverse") ? this.max : this.min; - this.value = this.max; + this.value = (this.dir == "reverse") ? this.min : this.max; diff --git a/widget/src/cocoa/nsNativeThemeCocoa.h b/widget/src/cocoa/nsNativeThemeCocoa.h index 67d59be9804e..bf0f1cd1cc78 100644 --- a/widget/src/cocoa/nsNativeThemeCocoa.h +++ b/widget/src/cocoa/nsNativeThemeCocoa.h @@ -111,7 +111,8 @@ protected: void DrawTabPanel (CGContextRef context, const HIRect& inBoxRect); void DrawScale (CGContextRef context, const HIRect& inBoxRect, PRBool inIsDisabled, PRInt32 inState, - PRBool inDirection, PRInt32 inCurrentValue, + PRBool inDirection, PRBool inIsReverse, + PRInt32 inCurrentValue, PRInt32 inMinValue, PRInt32 inMaxValue); void DrawButton (CGContextRef context, ThemeButtonKind inKind, const HIRect& inBoxRect, PRBool inIsDefault, diff --git a/widget/src/cocoa/nsNativeThemeCocoa.mm b/widget/src/cocoa/nsNativeThemeCocoa.mm index 8d4c24509ea0..b88a7cdffff5 100644 --- a/widget/src/cocoa/nsNativeThemeCocoa.mm +++ b/widget/src/cocoa/nsNativeThemeCocoa.mm @@ -247,7 +247,8 @@ nsNativeThemeCocoa::DrawTabPanel(CGContextRef cgContext, const HIRect& inBoxRect void nsNativeThemeCocoa::DrawScale(CGContextRef cgContext, const HIRect& inBoxRect, PRBool inIsDisabled, PRInt32 inState, - PRBool inIsVertical, PRInt32 inCurrentValue, + PRBool inIsVertical, PRBool inIsReverse, + PRInt32 inCurrentValue, PRInt32 inMinValue, PRInt32 inMaxValue) { HIThemeTrackDrawInfo tdi; @@ -261,6 +262,8 @@ nsNativeThemeCocoa::DrawScale(CGContextRef cgContext, const HIRect& inBoxRect, tdi.attributes = kThemeTrackShowThumb; if (!inIsVertical) tdi.attributes |= kThemeTrackHorizontal; + if (inIsReverse) + tdi.attributes |= kThemeTrackRightToLeft; if (inState & NS_EVENT_STATE_FOCUS) tdi.attributes |= kThemeTrackHasFocus; tdi.enableState = inIsDisabled ? kThemeTrackDisabled : kThemeTrackActive; @@ -610,8 +613,11 @@ nsNativeThemeCocoa::DrawWidgetBackground(nsIRenderingContext* aContext, nsIFrame if (!maxpos) maxpos = 100; + PRBool reverse = aFrame->GetContent()-> + AttrValueIs(kNameSpaceID_None, nsWidgetAtoms::dir, + NS_LITERAL_STRING("reverse"), eCaseMatters); DrawScale(cgContext, macRect, IsDisabled(aFrame), eventState, - (aWidgetType == NS_THEME_SCALE_VERTICAL), + (aWidgetType == NS_THEME_SCALE_VERTICAL), reverse, curpos, minpos, maxpos); } break; diff --git a/xpfe/global/jar.mn b/xpfe/global/jar.mn index 1346f6eba00c..50c9ee44b146 100644 --- a/xpfe/global/jar.mn +++ b/xpfe/global/jar.mn @@ -54,7 +54,7 @@ toolkit.jar: content/global/bindings/radio.xml (resources/content/bindings/radio.xml) content/global/bindings/scrollbar.xml (resources/content/bindings/scrollbar.xml) content/global/bindings/nativescrollbar.xml (resources/content/bindings/nativescrollbar.xml) - content/global/bindings/scale.xml (resources/content/bindings/scale.xml) + content/global/bindings/scale.xml (/toolkit/content/widgets/scale.xml) content/global/bindings/scrollbox.xml (resources/content/bindings/scrollbox.xml) content/global/bindings/splitter.xml (resources/content/bindings/splitter.xml) content/global/bindings/spinbuttons.xml (/toolkit/content/widgets/spinbuttons.xml)