/* void scrollToElement (in nsIDOMElement child); */ NS_IMETHODIMP nsScrollBoxObject::ScrollToElement(nsIDOMElement *child) { NS_ENSURE_ARG_POINTER(child); nsIScrollableView* scrollableView = GetScrollableView(); if (!scrollableView) return NS_ERROR_FAILURE; nsCOMPtr<nsIPresShell> shell = GetPresShell(PR_FALSE); if (!shell) { return NS_ERROR_UNEXPECTED; } nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) return NS_ERROR_FAILURE; nsRect rect, crect; nsCOMPtr<nsIDOMDocument> doc; child->GetOwnerDocument(getter_AddRefs(doc)); nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc)); if(!nsDoc) return NS_ERROR_UNEXPECTED; nsCOMPtr<nsIBoxObject> childBoxObject; nsDoc->GetBoxObjectFor(child, getter_AddRefs(childBoxObject)); if(!childBoxObject) return NS_ERROR_UNEXPECTED; PRInt32 x,y; childBoxObject->GetX(&x); childBoxObject->GetY(&y); // get the twips rectangle from the boxobject (which has pixels) rect.x = nsPresContext::CSSPixelsToAppUnits(x); rect.y = nsPresContext::CSSPixelsToAppUnits(y); // TODO: make sure the child is inside the box // get our current info nsPoint cp; scrollableView->GetScrollPosition(cp.x,cp.y); nsIntRect prect; GetOffsetRect(prect); crect = nsIntRect::ToAppUnits(prect, nsPresContext::AppUnitsPerCSSPixel()); nscoord newx=cp.x, newy=cp.y; // we only scroll in the direction of the scrollbox orientation // always scroll to left or top edge of child element if (scrolledBox->IsHorizontal()) { newx = rect.x - crect.x; } else { newy = rect.y - crect.y; } // scroll away return scrollableView->ScrollTo(newx, newy, 0); }
/* private helper */ void ScrollBoxObject::GetScrolledSize(nsRect& aRect, ErrorResult& aRv) { nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) { aRv.Throw(NS_ERROR_FAILURE); return; } aRect = scrolledBox->GetRect(); aRect.width = nsPresContext::AppUnitsToIntCSSPixels(aRect.width); aRect.height = nsPresContext::AppUnitsToIntCSSPixels(aRect.height); }
/* void getScrolledSize (out long width, out long height); */ NS_IMETHODIMP nsScrollBoxObject::GetScrolledSize(PRInt32 *width, PRInt32 *height) { nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) return NS_ERROR_FAILURE; nsRect scrollRect = scrolledBox->GetRect(); *width = nsPresContext::AppUnitsToIntCSSPixels(scrollRect.width); *height = nsPresContext::AppUnitsToIntCSSPixels(scrollRect.height); return NS_OK; }
/* void scrollByIndex (long dindexes); */ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv) { nsIScrollableFrame* sf = GetScrollFrame(); if (!sf) { aRv.Throw(NS_ERROR_FAILURE); return; } nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) { aRv.Throw(NS_ERROR_FAILURE); return; } nsRect rect; // now get the scrolled boxes first child. nsIFrame* child = nsBox::GetChildBox(scrolledBox); bool horiz = scrolledBox->IsHorizontal(); nsPoint cp = sf->GetScrollPosition(); nscoord diff = 0; int32_t curIndex = 0; bool isLTR = scrolledBox->IsNormalDirection(); int32_t frameWidth = 0; if (!isLTR && horiz) { GetWidth(&frameWidth); nsCOMPtr<nsIPresShell> shell = GetPresShell(false); if (!shell) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth); } // first find out what index we are currently at while(child) { rect = child->GetRect(); if (horiz) { // In the left-to-right case we break from the loop when the center of // the current child rect is greater than the scrolled position of // the left edge of the scrollbox // In the right-to-left case we break when the center of the current // child rect is less than the scrolled position of the right edge of // the scrollbox. diff = rect.x + rect.width/2; // use the center, to avoid rounding errors if ((isLTR && diff > cp.x) || (!isLTR && diff < cp.x + frameWidth)) { break; } } else { diff = rect.y + rect.height/2;// use the center, to avoid rounding errors if (diff > cp.y) { break; } } child = nsBox::GetNextBox(child); curIndex++; } int32_t count = 0; if (dindexes == 0) return; if (dindexes > 0) { while(child) { child = nsBox::GetNextBox(child); if (child) { rect = child->GetRect(); } count++; if (count >= dindexes) { break; } } } else if (dindexes < 0) { child = nsBox::GetChildBox(scrolledBox); while(child) { rect = child->GetRect(); if (count >= curIndex + dindexes) { break; } count++; child = nsBox::GetNextBox(child); } } nscoord csspixel = nsPresContext::CSSPixelsToAppUnits(1); if (horiz) { // In the left-to-right case we scroll so that the left edge of the // selected child is scrolled to the left edge of the scrollbox. // In the right-to-left case we scroll so that the right edge of the // selected child is scrolled to the right edge of the scrollbox. nsPoint pt(isLTR ? rect.x : rect.x + rect.width - frameWidth, cp.y); // Use a destination range that ensures the left edge (or right edge, // for RTL) will indeed be visible. Also ensure that the top edge // is visible. nsRect range(pt.x, pt.y, csspixel, 0); if (isLTR) { range.x -= csspixel; } sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range); } else { // Use a destination range that ensures the top edge will be visible. nsRect range(cp.x, rect.y - csspixel, 0, csspixel); sf->ScrollTo(nsPoint(cp.x, rect.y), nsIScrollableFrame::INSTANT, &range); } }
/* void ensureElementIsVisible (in nsIDOMElement child); */ NS_IMETHODIMP nsScrollBoxObject::EnsureElementIsVisible(nsIDOMElement *child) { NS_ENSURE_ARG_POINTER(child); // Start with getting info about the child, since that will flush // layout and possibly destroy scrollable views, presshells, etc. nsCOMPtr<nsIDOMDocument> doc; // XXXbz sXBL/XBL2 issue -- which document? child->GetOwnerDocument(getter_AddRefs(doc)); nsCOMPtr<nsIDOMNSDocument> nsDoc(do_QueryInterface(doc)); if(!nsDoc) return NS_ERROR_UNEXPECTED; nsCOMPtr<nsIBoxObject> childBoxObject; nsDoc->GetBoxObjectFor(child, getter_AddRefs(childBoxObject)); if(!childBoxObject) return NS_ERROR_UNEXPECTED; PRInt32 x, y, width, height; childBoxObject->GetX(&x); childBoxObject->GetY(&y); childBoxObject->GetWidth(&width); childBoxObject->GetHeight(&height); nsIScrollableView* scrollableView = GetScrollableView(); if (!scrollableView) return NS_ERROR_FAILURE; nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) return NS_ERROR_FAILURE; nsRect rect, crect; // get the twips rectangle from the boxobject (which has pixels) rect.x = nsPresContext::CSSPixelsToAppUnits(x); rect.y = nsPresContext::CSSPixelsToAppUnits(y); rect.width = nsPresContext::CSSPixelsToAppUnits(width); rect.height = nsPresContext::CSSPixelsToAppUnits(height); // TODO: make sure the child is inside the box // get our current info nsPoint cp; scrollableView->GetScrollPosition(cp.x,cp.y); nsIntRect prect; GetOffsetRect(prect); crect = nsIntRect::ToAppUnits(prect, nsPresContext::AppUnitsPerCSSPixel()); nscoord newx=cp.x, newy=cp.y; // we only scroll in the direction of the scrollbox orientation if (scrolledBox->IsHorizontal()) { if ((rect.x - crect.x) + rect.width > cp.x + crect.width) { newx = cp.x + (((rect.x - crect.x) + rect.width)-(cp.x + crect.width)); } else if (rect.x - crect.x < cp.x) { newx = rect.x - crect.x; } } else { if ((rect.y - crect.y) + rect.height > cp.y + crect.height) { newy = cp.y + (((rect.y - crect.y) + rect.height)-(cp.y + crect.height)); } else if (rect.y - crect.y < cp.y) { newy = rect.y - crect.y; } } // scroll away return scrollableView->ScrollTo(newx, newy, 0); }
/* void scrollByIndex (in long dindexes); */ NS_IMETHODIMP nsScrollBoxObject::ScrollByIndex(PRInt32 dindexes) { nsIScrollableView* scrollableView = GetScrollableView(); if (!scrollableView) return NS_ERROR_FAILURE; nsIFrame* scrolledBox = GetScrolledBox(this); if (!scrolledBox) return NS_ERROR_FAILURE; nsRect rect; // now get the scrolled boxes first child. nsIFrame* child = scrolledBox->GetChildBox(); PRBool horiz = scrolledBox->IsHorizontal(); nsPoint cp; scrollableView->GetScrollPosition(cp.x,cp.y); nscoord diff = 0; PRInt32 curIndex = 0; PRBool isLTR = scrolledBox->IsNormalDirection(); PRInt32 frameWidth = 0; if (!isLTR && horiz) { GetWidth(&frameWidth); nsCOMPtr<nsIPresShell> shell = GetPresShell(PR_FALSE); if (!shell) { return NS_ERROR_UNEXPECTED; } frameWidth = nsPresContext::CSSPixelsToAppUnits(frameWidth); } // first find out what index we are currently at while(child) { rect = child->GetRect(); if (horiz) { // In the left-to-right case we break from the loop when the center of // the current child rect is greater than the scrolled position of // the left edge of the scrollbox // In the right-to-left case we break when the center of the current // child rect is less than the scrolled position of the right edge of // the scrollbox. diff = rect.x + rect.width/2; // use the center, to avoid rounding errors if ((isLTR && diff > cp.x) || (!isLTR && diff < cp.x + frameWidth)) { break; } } else { diff = rect.y + rect.height/2;// use the center, to avoid rounding errors if (diff > cp.y) { break; } } child = child->GetNextBox(); curIndex++; } PRInt32 count = 0; if (dindexes == 0) return NS_OK; if (dindexes > 0) { while(child) { child = child->GetNextBox(); if (child) rect = child->GetRect(); count++; if (count >= dindexes) break; } } else if (dindexes < 0) { child = scrolledBox->GetChildBox(); while(child) { rect = child->GetRect(); if (count >= curIndex + dindexes) break; count++; child = child->GetNextBox(); } } if (horiz) // In the left-to-right case we scroll so that the left edge of the // selected child is scrolled to the left edge of the scrollbox. // In the right-to-left case we scroll so that the right edge of the // selected child is scrolled to the right edge of the scrollbox. return scrollableView->ScrollTo((isLTR) ? rect.x : rect.x + rect.width - frameWidth, cp.y, 0); else return scrollableView->ScrollTo(cp.x, rect.y, 0); }