123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsListBoxLayout.h"
- #include "nsListBoxBodyFrame.h"
- #include "nsBox.h"
- #include "nsBoxLayoutState.h"
- #include "nsIScrollableFrame.h"
- #include "nsIReflowCallback.h"
- #include "mozilla/dom/NameSpaceConstants.h"
- #include "nsGkAtoms.h"
- #include "nsContentUtils.h"
- nsListBoxLayout::nsListBoxLayout() : nsGridRowGroupLayout()
- {
- }
- ////////// nsBoxLayout //////////////
- nsSize
- nsListBoxLayout::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
- {
- nsSize pref = nsGridRowGroupLayout::GetXULPrefSize(aBox, aBoxLayoutState);
- nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
- if (frame) {
- nscoord rowheight = frame->GetRowHeightAppUnits();
- pref.height = frame->GetRowCount() * rowheight;
- // Pad the height.
- nscoord y = frame->GetAvailableHeight();
- if (pref.height > y && y > 0 && rowheight > 0) {
- nscoord m = (pref.height-y)%rowheight;
- nscoord remainder = m == 0 ? 0 : rowheight - m;
- pref.height += remainder;
- }
- if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
- nsGkAtoms::sizemode)) {
- nscoord width = frame->ComputeIntrinsicISize(aBoxLayoutState);
- if (width > pref.width)
- pref.width = width;
- }
- }
- return pref;
- }
- nsSize
- nsListBoxLayout::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
- {
- nsSize minSize = nsGridRowGroupLayout::GetXULMinSize(aBox, aBoxLayoutState);
- nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
- if (frame) {
- nscoord rowheight = frame->GetRowHeightAppUnits();
- minSize.height = frame->GetRowCount() * rowheight;
- // Pad the height.
- nscoord y = frame->GetAvailableHeight();
- if (minSize.height > y && y > 0 && rowheight > 0) {
- nscoord m = (minSize.height-y)%rowheight;
- nscoord remainder = m == 0 ? 0 : rowheight - m;
- minSize.height += remainder;
- }
- if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
- nsGkAtoms::sizemode)) {
- nscoord width = frame->ComputeIntrinsicISize(aBoxLayoutState);
- if (width > minSize.width)
- minSize.width = width;
- }
- }
- return minSize;
- }
- nsSize
- nsListBoxLayout::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
- {
- nsSize maxSize = nsGridRowGroupLayout::GetXULMaxSize(aBox, aBoxLayoutState);
- nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
- if (frame) {
- nscoord rowheight = frame->GetRowHeightAppUnits();
- maxSize.height = frame->GetRowCount() * rowheight;
- // Pad the height.
- nscoord y = frame->GetAvailableHeight();
- if (maxSize.height > y && y > 0 && rowheight > 0) {
- nscoord m = (maxSize.height-y)%rowheight;
- nscoord remainder = m == 0 ? 0 : rowheight - m;
- maxSize.height += remainder;
- }
- }
- return maxSize;
- }
- NS_IMETHODIMP
- nsListBoxLayout::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aState)
- {
- return LayoutInternal(aBox, aState);
- }
- /////////// nsListBoxLayout /////////////////////////
- /**
- * Called to layout our our children. Does no frame construction
- */
- NS_IMETHODIMP
- nsListBoxLayout::LayoutInternal(nsIFrame* aBox, nsBoxLayoutState& aState)
- {
- int32_t redrawStart = -1;
- // Get the start y position.
- nsListBoxBodyFrame* body = static_cast<nsListBoxBodyFrame*>(aBox);
- if (!body) {
- NS_ERROR("Frame encountered that isn't a listboxbody!");
- return NS_ERROR_FAILURE;
- }
- nsMargin margin;
- // Get our client rect.
- nsRect clientRect;
- aBox->GetXULClientRect(clientRect);
- // Get the starting y position and the remaining available
- // height.
- nscoord availableHeight = body->GetAvailableHeight();
- nscoord yOffset = body->GetYPosition();
-
- if (availableHeight <= 0) {
- bool fixed = (body->GetFixedRowSize() != -1);
- if (fixed)
- availableHeight = 10;
- else
- return NS_OK;
- }
- // run through all our currently created children
- nsIFrame* box = nsBox::GetChildXULBox(body);
- // if the reason is resize or initial we must relayout.
- nscoord rowHeight = body->GetRowHeightAppUnits();
- while (box) {
- // If this box is dirty or if it has dirty children, we
- // call layout on it.
- nsRect childRect(box->GetRect());
- box->GetXULMargin(margin);
-
- // relayout if we must or we are dirty or some of our children are dirty
- // or the client area is wider than us
- // XXXldb There should probably be a resize check here too!
- if (NS_SUBTREE_DIRTY(box) || childRect.width < clientRect.width) {
- childRect.x = 0;
- childRect.y = yOffset;
- childRect.width = clientRect.width;
-
- nsSize size = box->GetXULPrefSize(aState);
- body->SetRowHeight(size.height);
-
- childRect.height = rowHeight;
- childRect.Deflate(margin);
- box->SetXULBounds(aState, childRect);
- box->XULLayout(aState);
- } else {
- // if the child did not need to be relayed out. Then its easy.
- // Place the child by just grabbing its rect and adjusting the y.
- int32_t newPos = yOffset+margin.top;
- // are we pushing down or pulling up any rows?
- // Then we may have to redraw everything below the moved
- // rows.
- if (redrawStart == -1 && childRect.y != newPos)
- redrawStart = newPos;
- childRect.y = newPos;
- box->SetXULBounds(aState, childRect);
- }
- // Ok now the available size gets smaller and we move the
- // starting position of the next child down some.
- nscoord size = childRect.height + margin.top + margin.bottom;
- yOffset += size;
- availableHeight -= size;
-
- box = nsBox::GetNextXULBox(box);
- }
-
- // We have enough available height left to add some more rows
- // Since we can't do this during layout, we post a callback
- // that will be processed after the reflow completes.
- body->PostReflowCallback();
-
- // if rows were pushed down or pulled up because some rows were added
- // before them then redraw everything under the inserted rows. The inserted
- // rows will automatically be redrawn because the were marked dirty on insertion.
- if (redrawStart > -1) {
- aBox->XULRedraw(aState);
- }
- return NS_OK;
- }
- // Creation Routines ///////////////////////////////////////////////////////////////////////
- already_AddRefed<nsBoxLayout> NS_NewListBoxLayout()
- {
- RefPtr<nsBoxLayout> layout = new nsListBoxLayout();
- return layout.forget();
- }
|