1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "testing/gtest/include/gtest/gtest.h"
6 #include "views/layout/grid_layout.h"
7 #include "views/view.h"
9 using views::ColumnSet
;
10 using views::GridLayout
;
13 static void ExpectViewBoundsEquals(int x
, int y
, int w
, int h
,
15 EXPECT_EQ(x
, view
->x());
16 EXPECT_EQ(y
, view
->y());
17 EXPECT_EQ(w
, view
->width());
18 EXPECT_EQ(h
, view
->height());
21 class SettableSizeView
: public View
{
23 explicit SettableSizeView(const gfx::Size
& pref
) {
27 virtual gfx::Size
GetPreferredSize() {
35 // A view with fixed circumference that trades height for width.
36 class FlexibleView
: public View
{
38 explicit FlexibleView(int circumference
) {
39 circumference_
= circumference
;
42 virtual gfx::Size
GetPreferredSize() {
43 return gfx::Size(0, circumference_
/ 2);
46 virtual int GetHeightForWidth(int width
) {
47 return std::max(0, circumference_
/ 2 - width
);
54 class GridLayoutTest
: public testing::Test
{
56 virtual void SetUp() {
57 layout
= new GridLayout(&host
);
60 virtual void TearDown() {
64 virtual void RemoveAll() {
65 for (int i
= host
.child_count() - 1; i
>= 0; i
--)
66 host
.RemoveChildView(host
.child_at(i
));
69 void GetPreferredSize() {
70 pref
= layout
->GetPreferredSize(&host
);
79 class GridLayoutAlignmentTest
: public testing::Test
{
81 GridLayoutAlignmentTest() :
83 v1(gfx::Size(10, 20)),
84 layout(new GridLayout(&host
)) {}
86 virtual void SetUp() {
89 virtual void TearDown() {
93 virtual void RemoveAll() {
94 for (int i
= host
.child_count() - 1; i
>= 0; i
--)
95 host
.RemoveChildView(host
.child_at(i
));
98 void TestAlignment(GridLayout::Alignment alignment
, gfx::Rect
* bounds
) {
99 ColumnSet
* c1
= layout
->AddColumnSet(0);
100 c1
->AddColumn(alignment
, alignment
, 1, GridLayout::USE_PREF
, 0, 0);
101 layout
->StartRow(1, 0);
102 layout
->AddView(&v1
);
103 gfx::Size pref
= layout
->GetPreferredSize(&host
);
104 EXPECT_EQ(gfx::Size(10, 20), pref
);
105 host
.SetBounds(0, 0, 100, 100);
106 layout
->Layout(&host
);
107 *bounds
= v1
.bounds();
116 TEST_F(GridLayoutAlignmentTest
, Fill
) {
118 TestAlignment(GridLayout::FILL
, &bounds
);
119 EXPECT_EQ(gfx::Rect(0, 0, 100, 100), bounds
);
122 TEST_F(GridLayoutAlignmentTest
, Leading
) {
124 TestAlignment(GridLayout::LEADING
, &bounds
);
125 EXPECT_EQ(gfx::Rect(0, 0, 10, 20), bounds
);
128 TEST_F(GridLayoutAlignmentTest
, Center
) {
130 TestAlignment(GridLayout::CENTER
, &bounds
);
131 EXPECT_EQ(gfx::Rect(45, 40, 10, 20), bounds
);
134 TEST_F(GridLayoutAlignmentTest
, Trailing
) {
136 TestAlignment(GridLayout::TRAILING
, &bounds
);
137 EXPECT_EQ(gfx::Rect(90, 80, 10, 20), bounds
);
140 TEST_F(GridLayoutTest
, TwoColumns
) {
141 SettableSizeView
v1(gfx::Size(10, 20));
142 SettableSizeView
v2(gfx::Size(20, 20));
143 ColumnSet
* c1
= layout
->AddColumnSet(0);
144 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
145 0, GridLayout::USE_PREF
, 0, 0);
146 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
147 0, GridLayout::USE_PREF
, 0, 0);
148 layout
->StartRow(0, 0);
149 layout
->AddView(&v1
);
150 layout
->AddView(&v2
);
153 EXPECT_EQ(gfx::Size(30, 20), pref
);
155 host
.SetBounds(0, 0, pref
.width(), pref
.height());
156 layout
->Layout(&host
);
157 ExpectViewBoundsEquals(0, 0, 10, 20, &v1
);
158 ExpectViewBoundsEquals(10, 0, 20, 20, &v2
);
163 TEST_F(GridLayoutTest
, ColSpan1
) {
164 SettableSizeView
v1(gfx::Size(100, 20));
165 SettableSizeView
v2(gfx::Size(10, 40));
166 ColumnSet
* c1
= layout
->AddColumnSet(0);
167 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
168 0, GridLayout::USE_PREF
, 0, 0);
169 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
170 1, GridLayout::USE_PREF
, 0, 0);
171 layout
->StartRow(0, 0);
172 layout
->AddView(&v1
, 2, 1);
173 layout
->StartRow(0, 0);
174 layout
->AddView(&v2
);
177 EXPECT_EQ(gfx::Size(100, 60), pref
);
179 host
.SetBounds(0, 0, pref
.width(), pref
.height());
180 layout
->Layout(&host
);
181 ExpectViewBoundsEquals(0, 0, 100, 20, &v1
);
182 ExpectViewBoundsEquals(0, 20, 10, 40, &v2
);
187 TEST_F(GridLayoutTest
, ColSpan2
) {
188 SettableSizeView
v1(gfx::Size(100, 20));
189 SettableSizeView
v2(gfx::Size(10, 20));
190 ColumnSet
* c1
= layout
->AddColumnSet(0);
191 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
192 1, GridLayout::USE_PREF
, 0, 0);
193 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
194 0, GridLayout::USE_PREF
, 0, 0);
195 layout
->StartRow(0, 0);
196 layout
->AddView(&v1
, 2, 1);
197 layout
->StartRow(0, 0);
198 layout
->SkipColumns(1);
199 layout
->AddView(&v2
);
202 EXPECT_EQ(gfx::Size(100, 40), pref
);
204 host
.SetBounds(0, 0, pref
.width(), pref
.height());
205 layout
->Layout(&host
);
206 ExpectViewBoundsEquals(0, 0, 100, 20, &v1
);
207 ExpectViewBoundsEquals(90, 20, 10, 20, &v2
);
212 TEST_F(GridLayoutTest
, ColSpan3
) {
213 SettableSizeView
v1(gfx::Size(100, 20));
214 SettableSizeView
v2(gfx::Size(10, 20));
215 SettableSizeView
v3(gfx::Size(10, 20));
216 ColumnSet
* c1
= layout
->AddColumnSet(0);
217 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
218 0, GridLayout::USE_PREF
, 0, 0);
219 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
220 0, GridLayout::USE_PREF
, 0, 0);
221 layout
->StartRow(0, 0);
222 layout
->AddView(&v1
, 2, 1);
223 layout
->StartRow(0, 0);
224 layout
->AddView(&v2
);
225 layout
->AddView(&v3
);
228 EXPECT_EQ(gfx::Size(100, 40), pref
);
230 host
.SetBounds(0, 0, pref
.width(), pref
.height());
231 layout
->Layout(&host
);
232 ExpectViewBoundsEquals(0, 0, 100, 20, &v1
);
233 ExpectViewBoundsEquals(0, 20, 10, 20, &v2
);
234 ExpectViewBoundsEquals(50, 20, 10, 20, &v3
);
240 TEST_F(GridLayoutTest
, ColSpan4
) {
241 views::ColumnSet
* set
= layout
->AddColumnSet(0);
243 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
, 0,
244 GridLayout::USE_PREF
, 0, 0);
245 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
, 0,
246 GridLayout::USE_PREF
, 0, 0);
248 SettableSizeView
v1(gfx::Size(10, 10));
249 SettableSizeView
v2(gfx::Size(10, 10));
250 SettableSizeView
v3(gfx::Size(25, 20));
251 layout
->StartRow(0, 0);
252 layout
->AddView(&v1
);
253 layout
->AddView(&v2
);
254 layout
->StartRow(0, 0);
255 layout
->AddView(&v3
, 2, 1);
258 EXPECT_EQ(gfx::Size(25, 30), pref
);
260 host
.SetBounds(0, 0, pref
.width(), pref
.height());
261 layout
->Layout(&host
);
262 ExpectViewBoundsEquals(0, 0, 10, 10, &v1
);
263 ExpectViewBoundsEquals(12, 0, 10, 10, &v2
);
264 ExpectViewBoundsEquals(0, 10, 25, 20, &v3
);
269 TEST_F(GridLayoutTest
, SameSizeColumns
) {
270 SettableSizeView
v1(gfx::Size(50, 20));
271 SettableSizeView
v2(gfx::Size(10, 10));
272 ColumnSet
* c1
= layout
->AddColumnSet(0);
273 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
274 0, GridLayout::USE_PREF
, 0, 0);
275 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
276 0, GridLayout::USE_PREF
, 0, 0);
277 c1
->LinkColumnSizes(0, 1, -1);
278 layout
->StartRow(0, 0);
279 layout
->AddView(&v1
);
280 layout
->AddView(&v2
);
282 gfx::Size pref
= layout
->GetPreferredSize(&host
);
283 EXPECT_EQ(gfx::Size(100, 20), pref
);
285 host
.SetBounds(0, 0, pref
.width(), pref
.height());
286 layout
->Layout(&host
);
287 ExpectViewBoundsEquals(0, 0, 50, 20, &v1
);
288 ExpectViewBoundsEquals(50, 0, 10, 10, &v2
);
293 TEST_F(GridLayoutTest
, HorizontalResizeTest1
) {
294 SettableSizeView
v1(gfx::Size(50, 20));
295 SettableSizeView
v2(gfx::Size(10, 10));
296 ColumnSet
* c1
= layout
->AddColumnSet(0);
297 c1
->AddColumn(GridLayout::FILL
, GridLayout::LEADING
,
298 1, GridLayout::USE_PREF
, 0, 0);
299 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
300 0, GridLayout::USE_PREF
, 0, 0);
301 layout
->StartRow(0, 0);
302 layout
->AddView(&v1
);
303 layout
->AddView(&v2
);
305 host
.SetBounds(0, 0, 110, 20);
306 layout
->Layout(&host
);
307 ExpectViewBoundsEquals(0, 0, 100, 20, &v1
);
308 ExpectViewBoundsEquals(100, 0, 10, 10, &v2
);
313 TEST_F(GridLayoutTest
, HorizontalResizeTest2
) {
314 SettableSizeView
v1(gfx::Size(50, 20));
315 SettableSizeView
v2(gfx::Size(10, 10));
316 ColumnSet
* c1
= layout
->AddColumnSet(0);
317 c1
->AddColumn(GridLayout::FILL
, GridLayout::LEADING
,
318 1, GridLayout::USE_PREF
, 0, 0);
319 c1
->AddColumn(GridLayout::TRAILING
, GridLayout::LEADING
,
320 1, GridLayout::USE_PREF
, 0, 0);
321 layout
->StartRow(0, 0);
322 layout
->AddView(&v1
);
323 layout
->AddView(&v2
);
325 host
.SetBounds(0, 0, 120, 20);
326 layout
->Layout(&host
);
327 ExpectViewBoundsEquals(0, 0, 80, 20, &v1
);
328 ExpectViewBoundsEquals(110, 0, 10, 10, &v2
);
333 TEST_F(GridLayoutTest
, TestVerticalResize1
) {
334 SettableSizeView
v1(gfx::Size(50, 20));
335 SettableSizeView
v2(gfx::Size(10, 10));
336 ColumnSet
* c1
= layout
->AddColumnSet(0);
337 c1
->AddColumn(GridLayout::FILL
, GridLayout::FILL
,
338 1, GridLayout::USE_PREF
, 0, 0);
339 layout
->StartRow(1, 0);
340 layout
->AddView(&v1
);
341 layout
->StartRow(0, 0);
342 layout
->AddView(&v2
);
345 EXPECT_EQ(gfx::Size(50, 30), pref
);
347 host
.SetBounds(0, 0, 50, 100);
348 layout
->Layout(&host
);
349 ExpectViewBoundsEquals(0, 0, 50, 90, &v1
);
350 ExpectViewBoundsEquals(0, 90, 50, 10, &v2
);
355 TEST_F(GridLayoutTest
, Insets
) {
356 SettableSizeView
v1(gfx::Size(10, 20));
357 ColumnSet
* c1
= layout
->AddColumnSet(0);
358 layout
->SetInsets(1, 2, 3, 4);
359 c1
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
360 0, GridLayout::USE_PREF
, 0, 0);
361 layout
->StartRow(0, 0);
362 layout
->AddView(&v1
);
365 EXPECT_EQ(gfx::Size(16, 24), pref
);
367 host
.SetBounds(0, 0, pref
.width(), pref
.height());
368 layout
->Layout(&host
);
369 ExpectViewBoundsEquals(2, 1, 10, 20, &v1
);
374 TEST_F(GridLayoutTest
, FixedSize
) {
375 layout
->SetInsets(2, 2, 2, 2);
377 views::ColumnSet
* set
= layout
->AddColumnSet(0);
379 int column_count
= 4;
380 int title_width
= 100;
383 int pref_height
= 20;
385 for (int i
= 0; i
< column_count
; ++i
) {
386 set
->AddColumn(views::GridLayout::CENTER
,
387 views::GridLayout::CENTER
,
389 views::GridLayout::FIXED
,
394 for (int row
= 0; row
< row_count
; ++row
) {
395 layout
->StartRow(0, 0);
396 for (int col
= 0; col
< column_count
; ++col
) {
397 layout
->AddView(new SettableSizeView(gfx::Size(pref_width
, pref_height
)));
401 layout
->Layout(&host
);
403 for (int i
= 0; i
< column_count
; ++i
) {
404 for (int row
= 0; row
< row_count
; ++row
) {
405 View
* view
= host
.child_at(row
* column_count
+ i
);
406 ExpectViewBoundsEquals(
407 2 + title_width
* i
+ (title_width
- pref_width
) / 2,
408 2 + pref_height
* row
,
415 EXPECT_EQ(gfx::Size(column_count
* title_width
+ 4,
416 row_count
* pref_height
+ 4), pref
);
419 TEST_F(GridLayoutTest
, RowSpanWithPaddingRow
) {
420 views::ColumnSet
* set
= layout
->AddColumnSet(0);
422 set
->AddColumn(views::GridLayout::CENTER
,
423 views::GridLayout::CENTER
,
425 views::GridLayout::FIXED
,
429 layout
->StartRow(0, 0);
430 layout
->AddView(new SettableSizeView(gfx::Size(10, 10)), 1, 2);
431 layout
->AddPaddingRow(0, 10);
434 TEST_F(GridLayoutTest
, RowSpan
) {
435 views::ColumnSet
* set
= layout
->AddColumnSet(0);
437 set
->AddColumn(views::GridLayout::LEADING
,
438 views::GridLayout::LEADING
,
440 views::GridLayout::USE_PREF
,
443 set
->AddColumn(views::GridLayout::LEADING
,
444 views::GridLayout::LEADING
,
446 views::GridLayout::USE_PREF
,
450 layout
->StartRow(0, 0);
451 layout
->AddView(new SettableSizeView(gfx::Size(20, 10)));
452 layout
->AddView(new SettableSizeView(gfx::Size(20, 40)), 1, 2);
453 layout
->StartRow(1, 0);
454 views::View
* s3
= new SettableSizeView(gfx::Size(20, 10));
458 EXPECT_EQ(gfx::Size(40, 40), pref
);
460 host
.SetBounds(0, 0, pref
.width(), pref
.height());
461 layout
->Layout(&host
);
462 ExpectViewBoundsEquals(0, 10, 20, 10, s3
);
465 TEST_F(GridLayoutTest
, RowSpan2
) {
466 views::ColumnSet
* set
= layout
->AddColumnSet(0);
468 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
469 0, GridLayout::USE_PREF
, 0, 0);
470 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
471 0,GridLayout::USE_PREF
, 0, 0);
473 layout
->StartRow(0, 0);
474 layout
->AddView(new SettableSizeView(gfx::Size(20, 20)));
475 views::View
* s3
= new SettableSizeView(gfx::Size(64, 64));
476 layout
->AddView(s3
, 1, 3);
478 layout
->AddPaddingRow(0, 10);
480 layout
->StartRow(0, 0);
481 layout
->AddView(new SettableSizeView(gfx::Size(10, 20)));
484 EXPECT_EQ(gfx::Size(84, 64), pref
);
486 host
.SetBounds(0, 0, pref
.width(), pref
.height());
487 layout
->Layout(&host
);
488 ExpectViewBoundsEquals(20, 0, 64, 64, s3
);
491 TEST_F(GridLayoutTest
, FixedViewWidth
) {
492 views::ColumnSet
* set
= layout
->AddColumnSet(0);
494 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
495 0, GridLayout::USE_PREF
, 0, 0);
496 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
497 0,GridLayout::USE_PREF
, 0, 0);
499 layout
->StartRow(0, 0);
500 View
* view
= new SettableSizeView(gfx::Size(30, 40));
501 layout
->AddView(view
, 1, 1, GridLayout::LEADING
, GridLayout::LEADING
, 10, 0);
504 EXPECT_EQ(10, pref
.width());
505 EXPECT_EQ(40, pref
.height());
507 host
.SetBounds(0, 0, pref
.width(), pref
.height());
508 layout
->Layout(&host
);
509 ExpectViewBoundsEquals(0, 0, 10, 40, view
);
512 TEST_F(GridLayoutTest
, FixedViewHeight
) {
513 views::ColumnSet
* set
= layout
->AddColumnSet(0);
515 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
516 0, GridLayout::USE_PREF
, 0, 0);
517 set
->AddColumn(GridLayout::LEADING
, GridLayout::LEADING
,
518 0,GridLayout::USE_PREF
, 0, 0);
520 layout
->StartRow(0, 0);
521 View
* view
= new SettableSizeView(gfx::Size(30, 40));
522 layout
->AddView(view
, 1, 1, GridLayout::LEADING
, GridLayout::LEADING
, 0, 10);
525 EXPECT_EQ(30, pref
.width());
526 EXPECT_EQ(10, pref
.height());
528 host
.SetBounds(0, 0, pref
.width(), pref
.height());
529 layout
->Layout(&host
);
530 ExpectViewBoundsEquals(0, 0, 30, 10, view
);
533 // Make sure that for views that span columns the underlying columns are resized
534 // based on the resize percent of the column.
535 TEST_F(GridLayoutTest
, ColumnSpanResizing
) {
536 views::ColumnSet
* set
= layout
->AddColumnSet(0);
538 set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::CENTER
,
539 2, views::GridLayout::USE_PREF
, 0, 0);
540 set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::CENTER
,
541 4, views::GridLayout::USE_PREF
, 0, 0);
543 layout
->StartRow(0, 0);
544 // span_view spans two columns and is twice as big the views added below.
545 View
* span_view
= new SettableSizeView(gfx::Size(12, 40));
546 layout
->AddView(span_view
, 2, 1, GridLayout::LEADING
, GridLayout::LEADING
);
548 layout
->StartRow(0, 0);
549 View
* view1
= new SettableSizeView(gfx::Size(2, 40));
550 View
* view2
= new SettableSizeView(gfx::Size(4, 40));
551 layout
->AddView(view1
);
552 layout
->AddView(view2
);
554 host
.SetBounds(0, 0, 12, 80);
555 layout
->Layout(&host
);
557 ExpectViewBoundsEquals(0, 0, 12, 40, span_view
);
559 // view1 should be 4 pixels wide
560 // column_pref + (remaining_width * column_resize / total_column_resize) =
562 ExpectViewBoundsEquals(0, 40, 4, 40, view1
);
564 // And view2 should be 8 pixels wide:
566 ExpectViewBoundsEquals(4, 40, 8, 40, view2
);
569 // Check that GetPreferredSize() takes resizing of columns into account when
570 // there is additional space in the case we have column sets of different
572 TEST_F(GridLayoutTest
, ColumnResizingOnGetPreferredSize
) {
573 views::ColumnSet
* set
= layout
->AddColumnSet(0);
574 set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::CENTER
,
575 1, views::GridLayout::USE_PREF
, 0, 0);
577 set
= layout
->AddColumnSet(1);
578 set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::CENTER
,
579 1, views::GridLayout::USE_PREF
, 0, 0);
581 set
= layout
->AddColumnSet(2);
582 set
->AddColumn(views::GridLayout::FILL
, views::GridLayout::CENTER
,
583 1, views::GridLayout::USE_PREF
, 0, 0);
585 // Make a row containing a flexible view that trades width for height.
586 layout
->StartRow(0, 0);
587 View
* view1
= new FlexibleView(100);
588 layout
->AddView(view1
, 1, 1, GridLayout::FILL
, GridLayout::LEADING
);
590 // The second row contains a view of fixed size that will enforce a column
591 // width of 20 pixels.
592 layout
->StartRow(0, 1);
593 View
* view2
= new SettableSizeView(gfx::Size(20, 20));
594 layout
->AddView(view2
, 1, 1, GridLayout::FILL
, GridLayout::LEADING
);
596 // Add another flexible view in row three in order to ensure column set
597 // ordering doesn't influence sizing behaviour.
598 layout
->StartRow(0, 2);
599 View
* view3
= new FlexibleView(40);
600 layout
->AddView(view3
, 1, 1, GridLayout::FILL
, GridLayout::LEADING
);
602 // We expect a height of 50: 30 from the variable width view in the first row
603 // plus 20 from the statically sized view in the second row. The flexible
604 // view in the third row should contribute no height.
605 EXPECT_EQ(gfx::Size(20, 50), layout
->GetPreferredSize(&host
));