Bug 372047, support reverse direction scales, r=neil,josh

This commit is contained in:
enndeakin@sympatico.ca 2007-04-09 15:39:57 -07:00
parent 14eecdeff4
commit c04abaf92b
6 changed files with 128 additions and 82 deletions

View File

@ -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<nsIContent> 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);
}
}

View File

@ -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();

View File

@ -26,7 +26,7 @@
<content align="center" pack="center">
<xul:slider anonid="slider" class="scale-slider" snap="true" flex="1"
xbl:inherits="disabled,orient,curpos=value,minpos=min,maxpos=max,increment,pageincrement">
xbl:inherits="disabled,orient,dir,curpos=value,minpos=min,maxpos=max,increment,pageincrement">
<xul:thumb class="scale-thumb" xbl:inherits="disabled,orient"/>
</xul:slider>
</content>
@ -52,6 +52,18 @@
</getter>
</property>
<constructor>
<![CDATA[
var value = parseInt(this.getAttribute("value"), 10);
if (!isNaN(value))
this.value = value;
else if (this.min > 0)
this.value = this.min;
else if (this.max < 0)
this.value = this.max;
]]>
</constructor>
<method name="_getIntegerAttribute">
<parameter name="aAttr"/>
<parameter name="aDefaultValue"/>
@ -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 @@
</handler>
<handler event="keypress" keycode="VK_UP" preventdefault="true">
this.decrease();
return (this.dir == "reverse") ? this.increase() : this.decrease();
</handler>
<handler event="keypress" keycode="VK_LEFT" preventdefault="true">
this.decrease();
return (this.dir == "reverse") ? this.increase() : this.decrease();
</handler>
<handler event="keypress" keycode="VK_DOWN" preventdefault="true">
this.increase();
return (this.dir == "reverse") ? this.decrease() : this.increase();
</handler>
<handler event="keypress" keycode="VK_RIGHT" preventdefault="true">
this.increase();
return (this.dir == "reverse") ? this.decrease() : this.increase();
</handler>
<handler event="keypress" keycode="VK_PAGE_UP" preventdefault="true">
this.decreasePage();
return (this.dir == "reverse") ? this.increasePage() : this.decreasePage();
</handler>
<handler event="keypress" keycode="VK_PAGE_DOWN" preventdefault="true">
this.increasePage();
return (this.dir == "reverse") ? this.decreasePage() : this.increasePage();
</handler>
<handler event="keypress" keycode="VK_HOME" preventdefault="true">
this.value = this.min;
this.value = (this.dir == "reverse") ? this.max : this.min;
</handler>
<handler event="keypress" keycode="VK_END" preventdefault="true">
this.value = this.max;
this.value = (this.dir == "reverse") ? this.min : this.max;
</handler>
</handlers>

View File

@ -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,

View File

@ -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;

View File

@ -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)