layout/xul/nsListBoxLayout.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsListBoxLayout.h"
michael@0 7
michael@0 8 #include "nsListBoxBodyFrame.h"
michael@0 9 #include "nsBox.h"
michael@0 10 #include "nsBoxLayoutState.h"
michael@0 11 #include "nsIScrollableFrame.h"
michael@0 12 #include "nsIReflowCallback.h"
michael@0 13 #include "nsNameSpaceManager.h"
michael@0 14 #include "nsGkAtoms.h"
michael@0 15 #include "nsContentUtils.h"
michael@0 16
michael@0 17 nsListBoxLayout::nsListBoxLayout() : nsGridRowGroupLayout()
michael@0 18 {
michael@0 19 }
michael@0 20
michael@0 21 ////////// nsBoxLayout //////////////
michael@0 22
michael@0 23 nsSize
michael@0 24 nsListBoxLayout::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
michael@0 25 {
michael@0 26 nsSize pref = nsGridRowGroupLayout::GetPrefSize(aBox, aBoxLayoutState);
michael@0 27
michael@0 28 nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
michael@0 29 if (frame) {
michael@0 30 nscoord rowheight = frame->GetRowHeightAppUnits();
michael@0 31 pref.height = frame->GetRowCount() * rowheight;
michael@0 32 // Pad the height.
michael@0 33 nscoord y = frame->GetAvailableHeight();
michael@0 34 if (pref.height > y && y > 0 && rowheight > 0) {
michael@0 35 nscoord m = (pref.height-y)%rowheight;
michael@0 36 nscoord remainder = m == 0 ? 0 : rowheight - m;
michael@0 37 pref.height += remainder;
michael@0 38 }
michael@0 39 if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
michael@0 40 nsGkAtoms::sizemode)) {
michael@0 41 nscoord width = frame->ComputeIntrinsicWidth(aBoxLayoutState);
michael@0 42 if (width > pref.width)
michael@0 43 pref.width = width;
michael@0 44 }
michael@0 45 }
michael@0 46 return pref;
michael@0 47 }
michael@0 48
michael@0 49 nsSize
michael@0 50 nsListBoxLayout::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
michael@0 51 {
michael@0 52 nsSize minSize = nsGridRowGroupLayout::GetMinSize(aBox, aBoxLayoutState);
michael@0 53
michael@0 54 nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
michael@0 55 if (frame) {
michael@0 56 nscoord rowheight = frame->GetRowHeightAppUnits();
michael@0 57 minSize.height = frame->GetRowCount() * rowheight;
michael@0 58 // Pad the height.
michael@0 59 nscoord y = frame->GetAvailableHeight();
michael@0 60 if (minSize.height > y && y > 0 && rowheight > 0) {
michael@0 61 nscoord m = (minSize.height-y)%rowheight;
michael@0 62 nscoord remainder = m == 0 ? 0 : rowheight - m;
michael@0 63 minSize.height += remainder;
michael@0 64 }
michael@0 65 if (nsContentUtils::HasNonEmptyAttr(frame->GetContent(), kNameSpaceID_None,
michael@0 66 nsGkAtoms::sizemode)) {
michael@0 67 nscoord width = frame->ComputeIntrinsicWidth(aBoxLayoutState);
michael@0 68 if (width > minSize.width)
michael@0 69 minSize.width = width;
michael@0 70 }
michael@0 71 }
michael@0 72 return minSize;
michael@0 73 }
michael@0 74
michael@0 75 nsSize
michael@0 76 nsListBoxLayout::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
michael@0 77 {
michael@0 78 nsSize maxSize = nsGridRowGroupLayout::GetMaxSize(aBox, aBoxLayoutState);
michael@0 79
michael@0 80 nsListBoxBodyFrame* frame = static_cast<nsListBoxBodyFrame*>(aBox);
michael@0 81 if (frame) {
michael@0 82 nscoord rowheight = frame->GetRowHeightAppUnits();
michael@0 83 maxSize.height = frame->GetRowCount() * rowheight;
michael@0 84 // Pad the height.
michael@0 85 nscoord y = frame->GetAvailableHeight();
michael@0 86 if (maxSize.height > y && y > 0 && rowheight > 0) {
michael@0 87 nscoord m = (maxSize.height-y)%rowheight;
michael@0 88 nscoord remainder = m == 0 ? 0 : rowheight - m;
michael@0 89 maxSize.height += remainder;
michael@0 90 }
michael@0 91 }
michael@0 92 return maxSize;
michael@0 93 }
michael@0 94
michael@0 95 NS_IMETHODIMP
michael@0 96 nsListBoxLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aState)
michael@0 97 {
michael@0 98 return LayoutInternal(aBox, aState);
michael@0 99 }
michael@0 100
michael@0 101
michael@0 102 /////////// nsListBoxLayout /////////////////////////
michael@0 103
michael@0 104 /**
michael@0 105 * Called to layout our our children. Does no frame construction
michael@0 106 */
michael@0 107 NS_IMETHODIMP
michael@0 108 nsListBoxLayout::LayoutInternal(nsIFrame* aBox, nsBoxLayoutState& aState)
michael@0 109 {
michael@0 110 int32_t redrawStart = -1;
michael@0 111
michael@0 112 // Get the start y position.
michael@0 113 nsListBoxBodyFrame* body = static_cast<nsListBoxBodyFrame*>(aBox);
michael@0 114 if (!body) {
michael@0 115 NS_ERROR("Frame encountered that isn't a listboxbody!");
michael@0 116 return NS_ERROR_FAILURE;
michael@0 117 }
michael@0 118
michael@0 119 nsMargin margin;
michael@0 120
michael@0 121 // Get our client rect.
michael@0 122 nsRect clientRect;
michael@0 123 aBox->GetClientRect(clientRect);
michael@0 124
michael@0 125 // Get the starting y position and the remaining available
michael@0 126 // height.
michael@0 127 nscoord availableHeight = body->GetAvailableHeight();
michael@0 128 nscoord yOffset = body->GetYPosition();
michael@0 129
michael@0 130 if (availableHeight <= 0) {
michael@0 131 bool fixed = (body->GetFixedRowSize() != -1);
michael@0 132 if (fixed)
michael@0 133 availableHeight = 10;
michael@0 134 else
michael@0 135 return NS_OK;
michael@0 136 }
michael@0 137
michael@0 138 // run through all our currently created children
michael@0 139 nsIFrame* box = body->GetChildBox();
michael@0 140
michael@0 141 // if the reason is resize or initial we must relayout.
michael@0 142 nscoord rowHeight = body->GetRowHeightAppUnits();
michael@0 143
michael@0 144 while (box) {
michael@0 145 // If this box is dirty or if it has dirty children, we
michael@0 146 // call layout on it.
michael@0 147 nsRect childRect(box->GetRect());
michael@0 148 box->GetMargin(margin);
michael@0 149
michael@0 150 // relayout if we must or we are dirty or some of our children are dirty
michael@0 151 // or the client area is wider than us
michael@0 152 // XXXldb There should probably be a resize check here too!
michael@0 153 if (NS_SUBTREE_DIRTY(box) || childRect.width < clientRect.width) {
michael@0 154 childRect.x = 0;
michael@0 155 childRect.y = yOffset;
michael@0 156 childRect.width = clientRect.width;
michael@0 157
michael@0 158 nsSize size = box->GetPrefSize(aState);
michael@0 159 body->SetRowHeight(size.height);
michael@0 160
michael@0 161 childRect.height = rowHeight;
michael@0 162
michael@0 163 childRect.Deflate(margin);
michael@0 164 box->SetBounds(aState, childRect);
michael@0 165 box->Layout(aState);
michael@0 166 } else {
michael@0 167 // if the child did not need to be relayed out. Then its easy.
michael@0 168 // Place the child by just grabbing its rect and adjusting the y.
michael@0 169 int32_t newPos = yOffset+margin.top;
michael@0 170
michael@0 171 // are we pushing down or pulling up any rows?
michael@0 172 // Then we may have to redraw everything below the moved
michael@0 173 // rows.
michael@0 174 if (redrawStart == -1 && childRect.y != newPos)
michael@0 175 redrawStart = newPos;
michael@0 176
michael@0 177 childRect.y = newPos;
michael@0 178 box->SetBounds(aState, childRect);
michael@0 179 }
michael@0 180
michael@0 181 // Ok now the available size gets smaller and we move the
michael@0 182 // starting position of the next child down some.
michael@0 183 nscoord size = childRect.height + margin.top + margin.bottom;
michael@0 184
michael@0 185 yOffset += size;
michael@0 186 availableHeight -= size;
michael@0 187
michael@0 188 box = box->GetNextBox();
michael@0 189 }
michael@0 190
michael@0 191 // We have enough available height left to add some more rows
michael@0 192 // Since we can't do this during layout, we post a callback
michael@0 193 // that will be processed after the reflow completes.
michael@0 194 body->PostReflowCallback();
michael@0 195
michael@0 196 // if rows were pushed down or pulled up because some rows were added
michael@0 197 // before them then redraw everything under the inserted rows. The inserted
michael@0 198 // rows will automatically be redrawn because the were marked dirty on insertion.
michael@0 199 if (redrawStart > -1) {
michael@0 200 aBox->Redraw(aState);
michael@0 201 }
michael@0 202
michael@0 203 return NS_OK;
michael@0 204 }
michael@0 205
michael@0 206 // Creation Routines ///////////////////////////////////////////////////////////////////////
michael@0 207
michael@0 208 already_AddRefed<nsBoxLayout> NS_NewListBoxLayout()
michael@0 209 {
michael@0 210 nsRefPtr<nsBoxLayout> layout = new nsListBoxLayout();
michael@0 211 return layout.forget();
michael@0 212 }

mercurial