1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : //
39 : // Eric Vaughan
40 : // Netscape Communications
41 : //
42 : // See documentation in associated header file
43 : //
44 :
45 :
46 : /*
47 : * The nsGridRowGroupLayout implements the <rows> or <columns> tag in a grid.
48 : */
49 :
50 : #include "nsGridRowGroupLayout.h"
51 : #include "nsCOMPtr.h"
52 : #include "nsIScrollableFrame.h"
53 : #include "nsBoxLayoutState.h"
54 : #include "nsGridLayout2.h"
55 : #include "nsGridRow.h"
56 :
57 0 : already_AddRefed<nsBoxLayout> NS_NewGridRowGroupLayout()
58 : {
59 0 : nsBoxLayout* layout = new nsGridRowGroupLayout();
60 0 : NS_IF_ADDREF(layout);
61 0 : return layout;
62 : }
63 :
64 0 : nsGridRowGroupLayout::nsGridRowGroupLayout():nsGridRowLayout(), mRowCount(0)
65 : {
66 0 : }
67 :
68 0 : nsGridRowGroupLayout::~nsGridRowGroupLayout()
69 : {
70 0 : }
71 :
72 : void
73 0 : nsGridRowGroupLayout::ChildAddedOrRemoved(nsIBox* aBox, nsBoxLayoutState& aState)
74 : {
75 0 : PRInt32 index = 0;
76 0 : nsGrid* grid = GetGrid(aBox, &index);
77 0 : bool isHorizontal = IsHorizontal(aBox);
78 :
79 0 : if (grid)
80 0 : grid->RowAddedOrRemoved(aState, index, isHorizontal);
81 0 : }
82 :
83 : void
84 0 : nsGridRowGroupLayout::AddWidth(nsSize& aSize, nscoord aSize2, bool aIsHorizontal)
85 : {
86 0 : nscoord& size = GET_WIDTH(aSize, aIsHorizontal);
87 :
88 0 : if (size == NS_INTRINSICSIZE || aSize2 == NS_INTRINSICSIZE)
89 0 : size = NS_INTRINSICSIZE;
90 : else
91 0 : size += aSize2;
92 0 : }
93 :
94 : nsSize
95 0 : nsGridRowGroupLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState)
96 : {
97 0 : nsSize vpref = nsGridRowLayout::GetPrefSize(aBox, aState);
98 :
99 :
100 : /* It is possible that we could have some extra columns. This is when less columns in XUL were
101 : * defined that needed. And example might be a grid with 3 defined columns but a row with 4 cells in
102 : * it. We would need an extra column to make the grid work. But because that extra column does not
103 : * have a box associated with it we must add its size in manually. Remember we could have extra rows
104 : * as well.
105 : */
106 :
107 0 : PRInt32 index = 0;
108 0 : nsGrid* grid = GetGrid(aBox, &index);
109 :
110 0 : if (grid)
111 : {
112 : // make sure we add in extra columns sizes as well
113 0 : bool isHorizontal = IsHorizontal(aBox);
114 0 : PRInt32 extraColumns = grid->GetExtraColumnCount(isHorizontal);
115 0 : PRInt32 start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal);
116 0 : for (PRInt32 i=0; i < extraColumns; i++)
117 : {
118 : nscoord pref =
119 0 : grid->GetPrefRowHeight(aState, i+start, !isHorizontal); // GetPrefColumnWidth
120 :
121 0 : AddWidth(vpref, pref, isHorizontal);
122 : }
123 : }
124 :
125 : return vpref;
126 : }
127 :
128 : nsSize
129 0 : nsGridRowGroupLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState)
130 : {
131 0 : nsSize maxSize = nsGridRowLayout::GetMaxSize(aBox, aState);
132 :
133 0 : PRInt32 index = 0;
134 0 : nsGrid* grid = GetGrid(aBox, &index);
135 :
136 0 : if (grid)
137 : {
138 : // make sure we add in extra columns sizes as well
139 0 : bool isHorizontal = IsHorizontal(aBox);
140 0 : PRInt32 extraColumns = grid->GetExtraColumnCount(isHorizontal);
141 0 : PRInt32 start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal);
142 0 : for (PRInt32 i=0; i < extraColumns; i++)
143 : {
144 : nscoord max =
145 0 : grid->GetMaxRowHeight(aState, i+start, !isHorizontal); // GetMaxColumnWidth
146 :
147 0 : AddWidth(maxSize, max, isHorizontal);
148 : }
149 : }
150 :
151 : return maxSize;
152 : }
153 :
154 : nsSize
155 0 : nsGridRowGroupLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState)
156 : {
157 0 : nsSize minSize = nsGridRowLayout::GetMinSize(aBox, aState);
158 :
159 0 : PRInt32 index = 0;
160 0 : nsGrid* grid = GetGrid(aBox, &index);
161 :
162 0 : if (grid)
163 : {
164 : // make sure we add in extra columns sizes as well
165 0 : bool isHorizontal = IsHorizontal(aBox);
166 0 : PRInt32 extraColumns = grid->GetExtraColumnCount(isHorizontal);
167 0 : PRInt32 start = grid->GetColumnCount(isHorizontal) - grid->GetExtraColumnCount(isHorizontal);
168 0 : for (PRInt32 i=0; i < extraColumns; i++)
169 : {
170 : nscoord min =
171 0 : grid->GetMinRowHeight(aState, i+start, !isHorizontal); // GetMinColumnWidth
172 0 : AddWidth(minSize, min, isHorizontal);
173 : }
174 : }
175 :
176 : return minSize;
177 : }
178 :
179 : /*
180 : * Run down through our children dirtying them recursively.
181 : */
182 : void
183 0 : nsGridRowGroupLayout::DirtyRows(nsIBox* aBox, nsBoxLayoutState& aState)
184 : {
185 0 : if (aBox) {
186 : // mark us dirty
187 : // XXXldb We probably don't want to walk up the ancestor chain
188 : // calling MarkIntrinsicWidthsDirty for every row group.
189 0 : aState.PresShell()->FrameNeedsReflow(aBox, nsIPresShell::eTreeChange,
190 0 : NS_FRAME_IS_DIRTY);
191 0 : nsIBox* child = aBox->GetChildBox();
192 :
193 0 : while(child) {
194 :
195 : // walk into scrollframes
196 0 : nsIBox* deepChild = nsGrid::GetScrolledBox(child);
197 :
198 : // walk into other monuments
199 0 : nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild);
200 0 : if (monument)
201 0 : monument->DirtyRows(deepChild, aState);
202 :
203 0 : child = child->GetNextBox();
204 : }
205 : }
206 0 : }
207 :
208 :
209 : void
210 0 : nsGridRowGroupLayout::CountRowsColumns(nsIBox* aBox, PRInt32& aRowCount, PRInt32& aComputedColumnCount)
211 : {
212 0 : if (aBox) {
213 0 : PRInt32 startCount = aRowCount;
214 :
215 0 : nsIBox* child = aBox->GetChildBox();
216 :
217 0 : while(child) {
218 :
219 : // first see if it is a scrollframe. If so walk down into it and get the scrolled child
220 0 : nsIBox* deepChild = nsGrid::GetScrolledBox(child);
221 :
222 0 : nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild);
223 0 : if (monument) {
224 0 : monument->CountRowsColumns(deepChild, aRowCount, aComputedColumnCount);
225 0 : child = child->GetNextBox();
226 0 : deepChild = child;
227 0 : continue;
228 : }
229 :
230 0 : child = child->GetNextBox();
231 :
232 : // if not a monument. Then count it. It will be a bogus row
233 0 : aRowCount++;
234 : }
235 :
236 0 : mRowCount = aRowCount - startCount;
237 : }
238 0 : }
239 :
240 :
241 : /**
242 : * Fill out the given row structure recursively
243 : */
244 : PRInt32
245 0 : nsGridRowGroupLayout::BuildRows(nsIBox* aBox, nsGridRow* aRows)
246 : {
247 0 : PRInt32 rowCount = 0;
248 :
249 0 : if (aBox) {
250 0 : nsIBox* child = aBox->GetChildBox();
251 :
252 0 : while(child) {
253 :
254 : // first see if it is a scrollframe. If so walk down into it and get the scrolled child
255 0 : nsIBox* deepChild = nsGrid::GetScrolledBox(child);
256 :
257 0 : nsIGridPart* monument = nsGrid::GetPartFromBox(deepChild);
258 0 : if (monument) {
259 0 : rowCount += monument->BuildRows(deepChild, &aRows[rowCount]);
260 0 : child = child->GetNextBox();
261 0 : deepChild = child;
262 0 : continue;
263 : }
264 :
265 0 : aRows[rowCount].Init(child, true);
266 :
267 0 : child = child->GetNextBox();
268 :
269 : // if not a monument. Then count it. It will be a bogus row
270 0 : rowCount++;
271 : }
272 : }
273 :
274 0 : return rowCount;
275 : }
276 :
277 : nsMargin
278 0 : nsGridRowGroupLayout::GetTotalMargin(nsIBox* aBox, bool aIsHorizontal)
279 : {
280 : // group have border and padding added to the total margin
281 :
282 0 : nsMargin margin = nsGridRowLayout::GetTotalMargin(aBox, aIsHorizontal);
283 :
284 : // make sure we have the scrollframe on the outside if it has one.
285 : // that's where the border is.
286 0 : aBox = nsGrid::GetScrollBox(aBox);
287 :
288 : // add our border/padding to it
289 0 : nsMargin borderPadding(0,0,0,0);
290 0 : aBox->GetBorderAndPadding(borderPadding);
291 0 : margin += borderPadding;
292 :
293 : return margin;
294 : }
295 :
296 :
|