summaryrefslogtreecommitdiffstats
path: root/layout/xul/nsListBoxLayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/xul/nsListBoxLayout.cpp')
-rw-r--r--layout/xul/nsListBoxLayout.cpp212
1 files changed, 212 insertions, 0 deletions
diff --git a/layout/xul/nsListBoxLayout.cpp b/layout/xul/nsListBoxLayout.cpp
new file mode 100644
index 000000000..a2f915191
--- /dev/null
+++ b/layout/xul/nsListBoxLayout.cpp
@@ -0,0 +1,212 @@
+/* -*- 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();
+}