1// Copyright (c) 2012 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.
4
5#include "ui/views/layout/box_layout.h"
6
7#include "testing/gtest/include/gtest/gtest.h"
8#include "ui/views/test/test_views.h"
9#include "ui/views/view.h"
10
11namespace views {
12
13namespace {
14
15class BoxLayoutTest : public testing::Test {
16 public:
17  virtual void SetUp() OVERRIDE {
18    host_.reset(new View);
19  }
20
21  scoped_ptr<View> host_;
22};
23
24}  // namespace
25
26TEST_F(BoxLayoutTest, Empty) {
27  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 20);
28  host_->SetLayoutManager(layout);
29  EXPECT_EQ(gfx::Size(20, 20), layout->GetPreferredSize(host_.get()));
30}
31
32TEST_F(BoxLayoutTest, AlignmentHorizontal) {
33  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 0, 0, 0);
34  host_->SetLayoutManager(layout);
35  View* v1 = new StaticSizedView(gfx::Size(10, 20));
36  host_->AddChildView(v1);
37  View* v2 = new StaticSizedView(gfx::Size(10, 10));
38  host_->AddChildView(v2);
39  EXPECT_EQ(gfx::Size(20, 20), layout->GetPreferredSize(host_.get()));
40  host_->SetBounds(0, 0, 20, 20);
41  host_->Layout();
42  EXPECT_EQ(gfx::Rect(0, 0, 10, 20), v1->bounds());
43  EXPECT_EQ(gfx::Rect(10, 0, 10, 20), v2->bounds());
44}
45
46TEST_F(BoxLayoutTest, AlignmentVertical) {
47  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 0, 0, 0);
48  host_->SetLayoutManager(layout);
49  View* v1 = new StaticSizedView(gfx::Size(20, 10));
50  host_->AddChildView(v1);
51  View* v2 = new StaticSizedView(gfx::Size(10, 10));
52  host_->AddChildView(v2);
53  EXPECT_EQ(gfx::Size(20, 20), layout->GetPreferredSize(host_.get()));
54  host_->SetBounds(0, 0, 20, 20);
55  host_->Layout();
56  EXPECT_EQ(gfx::Rect(0, 0, 20, 10), v1->bounds());
57  EXPECT_EQ(gfx::Rect(0, 10, 20, 10), v2->bounds());
58}
59
60TEST_F(BoxLayoutTest, SetInsideBorderInsets) {
61  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 20, 0);
62  host_->SetLayoutManager(layout);
63  View* v1 = new StaticSizedView(gfx::Size(10, 20));
64  host_->AddChildView(v1);
65  View* v2 = new StaticSizedView(gfx::Size(10, 10));
66  host_->AddChildView(v2);
67  EXPECT_EQ(gfx::Size(40, 60), layout->GetPreferredSize(host_.get()));
68  host_->SetBounds(0, 0, 40, 60);
69  host_->Layout();
70  EXPECT_EQ(gfx::Rect(10, 20, 10, 20), v1->bounds());
71  EXPECT_EQ(gfx::Rect(20, 20, 10, 20), v2->bounds());
72
73  layout->set_inside_border_insets(
74      gfx::Insets(5, 10, 15, 20));
75  EXPECT_EQ(gfx::Size(50, 40), layout->GetPreferredSize(host_.get()));
76  host_->SetBounds(0, 0, 50, 40);
77  host_->Layout();
78  EXPECT_EQ(gfx::Rect(10, 5, 10, 20), v1->bounds());
79  EXPECT_EQ(gfx::Rect(20, 5, 10, 20), v2->bounds());
80}
81
82TEST_F(BoxLayoutTest, Spacing) {
83  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 7, 7, 8);
84  host_->SetLayoutManager(layout);
85  View* v1 = new StaticSizedView(gfx::Size(10, 20));
86  host_->AddChildView(v1);
87  View* v2 = new StaticSizedView(gfx::Size(10, 20));
88  host_->AddChildView(v2);
89  EXPECT_EQ(gfx::Size(42, 34), layout->GetPreferredSize(host_.get()));
90  host_->SetBounds(0, 0, 100, 100);
91  host_->Layout();
92  EXPECT_EQ(gfx::Rect(7, 7, 10, 86), v1->bounds());
93  EXPECT_EQ(gfx::Rect(25, 7, 10, 86), v2->bounds());
94}
95
96TEST_F(BoxLayoutTest, Overflow) {
97  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 0, 0, 0);
98  host_->SetLayoutManager(layout);
99  View* v1 = new StaticSizedView(gfx::Size(20, 20));
100  host_->AddChildView(v1);
101  View* v2 = new StaticSizedView(gfx::Size(10, 20));
102  host_->AddChildView(v2);
103  host_->SetBounds(0, 0, 10, 10);
104
105  // Overflows by positioning views at the start and truncating anything that
106  // doesn't fit.
107  host_->Layout();
108  EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
109  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
110
111  // All values of main axis alignment should overflow in the same manner.
112  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
113  host_->Layout();
114  EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
115  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
116
117  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
118  host_->Layout();
119  EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
120  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
121
122  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
123  host_->Layout();
124  EXPECT_EQ(gfx::Rect(0, 0, 10, 10), v1->bounds());
125  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), v2->bounds());
126}
127
128TEST_F(BoxLayoutTest, NoSpace) {
129  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10);
130  host_->SetLayoutManager(layout);
131  View* childView = new StaticSizedView(gfx::Size(20, 20));
132  host_->AddChildView(childView);
133  host_->SetBounds(0, 0, 10, 10);
134  host_->Layout();
135  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), childView->bounds());
136}
137
138TEST_F(BoxLayoutTest, InvisibleChild) {
139  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10);
140  host_->SetLayoutManager(layout);
141  View* v1 = new StaticSizedView(gfx::Size(20, 20));
142  v1->SetVisible(false);
143  host_->AddChildView(v1);
144  View* v2 = new StaticSizedView(gfx::Size(10, 10));
145  host_->AddChildView(v2);
146  EXPECT_EQ(gfx::Size(30, 30), layout->GetPreferredSize(host_.get()));
147  host_->SetBounds(0, 0, 30, 30);
148  host_->Layout();
149  EXPECT_EQ(gfx::Rect(10, 10, 10, 10), v2->bounds());
150}
151
152TEST_F(BoxLayoutTest, UseHeightForWidth) {
153  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 0, 0, 0);
154  host_->SetLayoutManager(layout);
155  View* v1 = new StaticSizedView(gfx::Size(20, 10));
156  host_->AddChildView(v1);
157  ProportionallySizedView* v2 = new ProportionallySizedView(2);
158  v2->set_preferred_width(10);
159  host_->AddChildView(v2);
160  EXPECT_EQ(gfx::Size(20, 50), layout->GetPreferredSize(host_.get()));
161
162  host_->SetBounds(0, 0, 20, 50);
163  host_->Layout();
164  EXPECT_EQ(gfx::Rect(0, 0, 20, 10), v1->bounds());
165  EXPECT_EQ(gfx::Rect(0, 10, 20, 40), v2->bounds());
166
167  EXPECT_EQ(110, layout->GetPreferredHeightForWidth(host_.get(), 50));
168
169  // Test without horizontal stretching of the views.
170  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END);
171  EXPECT_EQ(gfx::Size(20, 30).ToString(),
172            layout->GetPreferredSize(host_.get()).ToString());
173
174  host_->SetBounds(0, 0, 20, 30);
175  host_->Layout();
176  EXPECT_EQ(gfx::Rect(0, 0, 20, 10), v1->bounds());
177  EXPECT_EQ(gfx::Rect(10, 10, 10, 20), v2->bounds());
178
179  EXPECT_EQ(30, layout->GetPreferredHeightForWidth(host_.get(), 50));
180}
181
182TEST_F(BoxLayoutTest, EmptyPreferredSize) {
183  for (size_t i = 0; i < 2; i++) {
184    BoxLayout::Orientation orientation = i == 0 ? BoxLayout::kHorizontal :
185                                                  BoxLayout::kVertical;
186    host_->RemoveAllChildViews(true);
187    host_->SetLayoutManager(new BoxLayout(orientation, 0, 0, 5));
188    View* v1 = new StaticSizedView(gfx::Size());
189    host_->AddChildView(v1);
190    View* v2 = new StaticSizedView(gfx::Size(10, 10));
191    host_->AddChildView(v2);
192    host_->SizeToPreferredSize();
193    host_->Layout();
194
195    EXPECT_EQ(v2->GetPreferredSize().width(), host_->bounds().width()) << i;
196    EXPECT_EQ(v2->GetPreferredSize().height(), host_->bounds().height()) << i;
197    EXPECT_EQ(v1->GetPreferredSize().width(), v1->bounds().width()) << i;
198    EXPECT_EQ(v1->GetPreferredSize().height(), v1->bounds().height()) << i;
199    EXPECT_EQ(v2->GetPreferredSize().width(), v2->bounds().width()) << i;
200    EXPECT_EQ(v2->GetPreferredSize().height(), v2->bounds().height()) << i;
201  }
202}
203
204TEST_F(BoxLayoutTest, MainAxisAlignmentHorizontal) {
205  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10);
206  host_->SetLayoutManager(layout);
207
208  View* v1 = new StaticSizedView(gfx::Size(20, 20));
209  host_->AddChildView(v1);
210  View* v2 = new StaticSizedView(gfx::Size(10, 10));
211  host_->AddChildView(v2);
212
213  host_->SetBounds(0, 0, 100, 40);
214
215  // Align children to the horizontal start by default.
216  host_->Layout();
217  EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
218  EXPECT_EQ(gfx::Rect(40, 10, 10, 20).ToString(), v2->bounds().ToString());
219
220  // Ensure same results for MAIN_AXIS_ALIGNMENT_START.
221  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
222  host_->Layout();
223  EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
224  EXPECT_EQ(gfx::Rect(40, 10, 10, 20).ToString(), v2->bounds().ToString());
225
226  // Aligns children to the center horizontally.
227  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
228  host_->Layout();
229  EXPECT_EQ(gfx::Rect(30, 10, 20, 20).ToString(), v1->bounds().ToString());
230  EXPECT_EQ(gfx::Rect(60, 10, 10, 20).ToString(), v2->bounds().ToString());
231
232  // Aligns children to the end of the host horizontally, accounting for the
233  // inside border spacing.
234  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
235  host_->Layout();
236  EXPECT_EQ(gfx::Rect(50, 10, 20, 20).ToString(), v1->bounds().ToString());
237  EXPECT_EQ(gfx::Rect(80, 10, 10, 20).ToString(), v2->bounds().ToString());
238}
239
240TEST_F(BoxLayoutTest, MainAxisAlignmentVertical) {
241  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 10, 10, 10);
242  host_->SetLayoutManager(layout);
243
244  View* v1 = new StaticSizedView(gfx::Size(20, 20));
245  host_->AddChildView(v1);
246  View* v2 = new StaticSizedView(gfx::Size(10, 10));
247  host_->AddChildView(v2);
248
249  host_->SetBounds(0, 0, 40, 100);
250
251  // Align children to the vertical start by default.
252  host_->Layout();
253  EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
254  EXPECT_EQ(gfx::Rect(10, 40, 20, 10).ToString(), v2->bounds().ToString());
255
256  // Ensure same results for MAIN_AXIS_ALIGNMENT_START.
257  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
258  host_->Layout();
259  EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
260  EXPECT_EQ(gfx::Rect(10, 40, 20, 10).ToString(), v2->bounds().ToString());
261
262  // Aligns children to the center vertically.
263  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
264  host_->Layout();
265  EXPECT_EQ(gfx::Rect(10, 30, 20, 20).ToString(), v1->bounds().ToString());
266  EXPECT_EQ(gfx::Rect(10, 60, 20, 10).ToString(), v2->bounds().ToString());
267
268  // Aligns children to the end of the host vertically, accounting for the
269  // inside border spacing.
270  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
271  host_->Layout();
272  EXPECT_EQ(gfx::Rect(10, 50, 20, 20).ToString(), v1->bounds().ToString());
273  EXPECT_EQ(gfx::Rect(10, 80, 20, 10).ToString(), v2->bounds().ToString());
274}
275
276TEST_F(BoxLayoutTest, CrossAxisAlignmentHorizontal) {
277  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10);
278  host_->SetLayoutManager(layout);
279
280  View* v1 = new StaticSizedView(gfx::Size(20, 20));
281  host_->AddChildView(v1);
282  View* v2 = new StaticSizedView(gfx::Size(10, 10));
283  host_->AddChildView(v2);
284
285  host_->SetBounds(0, 0, 100, 60);
286
287  // Stretch children to fill the available height by default.
288  host_->Layout();
289  EXPECT_EQ(gfx::Rect(10, 10, 20, 40).ToString(), v1->bounds().ToString());
290  EXPECT_EQ(gfx::Rect(40, 10, 10, 40).ToString(), v2->bounds().ToString());
291
292  // Ensure same results for CROSS_AXIS_ALIGNMENT_STRETCH.
293  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
294  host_->Layout();
295  EXPECT_EQ(gfx::Rect(10, 10, 20, 40).ToString(), v1->bounds().ToString());
296  EXPECT_EQ(gfx::Rect(40, 10, 10, 40).ToString(), v2->bounds().ToString());
297
298  // Aligns children to the start vertically.
299  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_START);
300  host_->Layout();
301  EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
302  EXPECT_EQ(gfx::Rect(40, 10, 10, 10).ToString(), v2->bounds().ToString());
303
304  // Aligns children to the center vertically.
305  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
306  host_->Layout();
307  EXPECT_EQ(gfx::Rect(10, 20, 20, 20).ToString(), v1->bounds().ToString());
308  EXPECT_EQ(gfx::Rect(40, 25, 10, 10).ToString(), v2->bounds().ToString());
309
310  // Aligns children to the end of the host vertically, accounting for the
311  // inside border spacing.
312  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END);
313  host_->Layout();
314  EXPECT_EQ(gfx::Rect(10, 30, 20, 20).ToString(), v1->bounds().ToString());
315  EXPECT_EQ(gfx::Rect(40, 40, 10, 10).ToString(), v2->bounds().ToString());
316}
317
318TEST_F(BoxLayoutTest, CrossAxisAlignmentVertical) {
319  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 10, 10, 10);
320  host_->SetLayoutManager(layout);
321
322  View* v1 = new StaticSizedView(gfx::Size(20, 20));
323  host_->AddChildView(v1);
324  View* v2 = new StaticSizedView(gfx::Size(10, 10));
325  host_->AddChildView(v2);
326
327  host_->SetBounds(0, 0, 60, 100);
328
329  // Stretch children to fill the available width by default.
330  host_->Layout();
331  EXPECT_EQ(gfx::Rect(10, 10, 40, 20).ToString(), v1->bounds().ToString());
332  EXPECT_EQ(gfx::Rect(10, 40, 40, 10).ToString(), v2->bounds().ToString());
333
334  // Ensure same results for CROSS_AXIS_ALIGNMENT_STRETCH.
335  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
336  host_->Layout();
337  EXPECT_EQ(gfx::Rect(10, 10, 40, 20).ToString(), v1->bounds().ToString());
338  EXPECT_EQ(gfx::Rect(10, 40, 40, 10).ToString(), v2->bounds().ToString());
339
340  // Aligns children to the start horizontally.
341  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_START);
342  host_->Layout();
343  EXPECT_EQ(gfx::Rect(10, 10, 20, 20).ToString(), v1->bounds().ToString());
344  EXPECT_EQ(gfx::Rect(10, 40, 10, 10).ToString(), v2->bounds().ToString());
345
346  // Aligns children to the center horizontally.
347  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
348  host_->Layout();
349  EXPECT_EQ(gfx::Rect(20, 10, 20, 20).ToString(), v1->bounds().ToString());
350  EXPECT_EQ(gfx::Rect(25, 40, 10, 10).ToString(), v2->bounds().ToString());
351
352  // Aligns children to the end of the host horizontally, accounting for the
353  // inside border spacing.
354  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END);
355  host_->Layout();
356  EXPECT_EQ(gfx::Rect(30, 10, 20, 20).ToString(), v1->bounds().ToString());
357  EXPECT_EQ(gfx::Rect(40, 40, 10, 10).ToString(), v2->bounds().ToString());
358}
359
360TEST_F(BoxLayoutTest, FlexAll) {
361  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10);
362  host_->SetLayoutManager(layout);
363  layout->SetDefaultFlex(1);
364
365  View* v1 = new StaticSizedView(gfx::Size(20, 20));
366  host_->AddChildView(v1);
367  View* v2 = new StaticSizedView(gfx::Size(10, 10));
368  host_->AddChildView(v2);
369  View* v3 = new StaticSizedView(gfx::Size(30, 30));
370  host_->AddChildView(v3);
371  EXPECT_EQ(gfx::Size(100, 50), layout->GetPreferredSize(host_.get()));
372
373  host_->SetBounds(0, 0, 120, 50);
374  host_->Layout();
375  EXPECT_EQ(gfx::Rect(10, 10, 27, 30).ToString(), v1->bounds().ToString());
376  EXPECT_EQ(gfx::Rect(47, 10, 16, 30).ToString(), v2->bounds().ToString());
377  EXPECT_EQ(gfx::Rect(73, 10, 37, 30).ToString(), v3->bounds().ToString());
378}
379
380TEST_F(BoxLayoutTest, FlexGrowVertical) {
381  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 10, 10, 10);
382  host_->SetLayoutManager(layout);
383
384  View* v1 = new StaticSizedView(gfx::Size(20, 20));
385  host_->AddChildView(v1);
386  View* v2 = new StaticSizedView(gfx::Size(10, 10));
387  host_->AddChildView(v2);
388  View* v3 = new StaticSizedView(gfx::Size(30, 30));
389  host_->AddChildView(v3);
390
391  host_->SetBounds(0, 0, 50, 130);
392
393  // Views don't fill the available space by default.
394  host_->Layout();
395  EXPECT_EQ(gfx::Rect(10, 10, 30, 20).ToString(), v1->bounds().ToString());
396  EXPECT_EQ(gfx::Rect(10, 40, 30, 10).ToString(), v2->bounds().ToString());
397  EXPECT_EQ(gfx::Rect(10, 60, 30, 30).ToString(), v3->bounds().ToString());
398
399  std::vector<BoxLayout::MainAxisAlignment> main_alignments;
400  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
401  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
402  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
403
404  for (size_t i = 0; i < main_alignments.size(); ++i) {
405    layout->set_main_axis_alignment(main_alignments[i]);
406
407    // Set the first view to consume all free space.
408    layout->SetFlexForView(v1, 1);
409    layout->ClearFlexForView(v2);
410    layout->ClearFlexForView(v3);
411    host_->Layout();
412    EXPECT_EQ(gfx::Rect(10, 10, 30, 50).ToString(), v1->bounds().ToString());
413    EXPECT_EQ(gfx::Rect(10, 70, 30, 10).ToString(), v2->bounds().ToString());
414    EXPECT_EQ(gfx::Rect(10, 90, 30, 30).ToString(), v3->bounds().ToString());
415
416    // Set the third view to take 2/3s of the free space and leave the first
417    // view
418    // with 1/3.
419    layout->SetFlexForView(v3, 2);
420    host_->Layout();
421    EXPECT_EQ(gfx::Rect(10, 10, 30, 30).ToString(), v1->bounds().ToString());
422    EXPECT_EQ(gfx::Rect(10, 50, 30, 10).ToString(), v2->bounds().ToString());
423    EXPECT_EQ(gfx::Rect(10, 70, 30, 50).ToString(), v3->bounds().ToString());
424
425    // Clear the previously set flex values and set the second view to take all
426    // the free space.
427    layout->ClearFlexForView(v1);
428    layout->SetFlexForView(v2, 1);
429    layout->ClearFlexForView(v3);
430    host_->Layout();
431    EXPECT_EQ(gfx::Rect(10, 10, 30, 20).ToString(), v1->bounds().ToString());
432    EXPECT_EQ(gfx::Rect(10, 40, 30, 40).ToString(), v2->bounds().ToString());
433    EXPECT_EQ(gfx::Rect(10, 90, 30, 30).ToString(), v3->bounds().ToString());
434  }
435}
436
437TEST_F(BoxLayoutTest, FlexGrowHorizontalWithRemainder) {
438  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 0, 0, 0);
439  host_->SetLayoutManager(layout);
440  layout->SetDefaultFlex(1);
441  std::vector<View*> views;
442  for (int i = 0; i < 5; ++i) {
443    View* view = new StaticSizedView(gfx::Size(10, 10));
444    views.push_back(view);
445    host_->AddChildView(view);
446  }
447
448  EXPECT_EQ(gfx::Size(50, 10), layout->GetPreferredSize(host_.get()));
449
450  host_->SetBounds(0, 0, 52, 10);
451  host_->Layout();
452  // The 2nd and 4th views should have an extra pixel as they correspond to 20.8
453  // and 41.6 which round up.
454  EXPECT_EQ(gfx::Rect(0, 0, 10, 10).ToString(), views[0]->bounds().ToString());
455  EXPECT_EQ(gfx::Rect(10, 0, 11, 10).ToString(), views[1]->bounds().ToString());
456  EXPECT_EQ(gfx::Rect(21, 0, 10, 10).ToString(), views[2]->bounds().ToString());
457  EXPECT_EQ(gfx::Rect(31, 0, 11, 10).ToString(), views[3]->bounds().ToString());
458  EXPECT_EQ(gfx::Rect(42, 0, 10, 10).ToString(), views[4]->bounds().ToString());
459}
460
461TEST_F(BoxLayoutTest, FlexGrowHorizontalWithRemainder2) {
462  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 0, 0, 0);
463  host_->SetLayoutManager(layout);
464  layout->SetDefaultFlex(1);
465  std::vector<View*> views;
466  for (int i = 0; i < 4; ++i) {
467    View* view = new StaticSizedView(gfx::Size(1, 10));
468    views.push_back(view);
469    host_->AddChildView(view);
470  }
471
472  EXPECT_EQ(gfx::Size(4, 10), layout->GetPreferredSize(host_.get()));
473
474  host_->SetBounds(0, 0, 10, 10);
475  host_->Layout();
476  // The 1st and 3rd views should have an extra pixel as they correspond to 2.5
477  // and 7.5 which round up.
478  EXPECT_EQ(gfx::Rect(0, 0, 3, 10).ToString(), views[0]->bounds().ToString());
479  EXPECT_EQ(gfx::Rect(3, 0, 2, 10).ToString(), views[1]->bounds().ToString());
480  EXPECT_EQ(gfx::Rect(5, 0, 3, 10).ToString(), views[2]->bounds().ToString());
481  EXPECT_EQ(gfx::Rect(8, 0, 2, 10).ToString(), views[3]->bounds().ToString());
482}
483
484TEST_F(BoxLayoutTest, FlexShrinkHorizontal) {
485  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 10, 10, 10);
486  host_->SetLayoutManager(layout);
487
488  View* v1 = new StaticSizedView(gfx::Size(20, 20));
489  host_->AddChildView(v1);
490  View* v2 = new StaticSizedView(gfx::Size(10, 10));
491  host_->AddChildView(v2);
492  View* v3 = new StaticSizedView(gfx::Size(30, 30));
493  host_->AddChildView(v3);
494
495  host_->SetBounds(0, 0, 85, 50);
496
497  // Truncate width by default.
498  host_->Layout();
499  EXPECT_EQ(gfx::Rect(10, 10, 20, 30).ToString(), v1->bounds().ToString());
500  EXPECT_EQ(gfx::Rect(40, 10, 10, 30).ToString(), v2->bounds().ToString());
501  EXPECT_EQ(gfx::Rect(60, 10, 15, 30).ToString(), v3->bounds().ToString());
502
503  std::vector<BoxLayout::MainAxisAlignment> main_alignments;
504  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
505  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
506  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
507
508  for (size_t i = 0; i < main_alignments.size(); ++i) {
509    layout->set_main_axis_alignment(main_alignments[i]);
510
511    // Set the first view to shrink as much as necessary.
512    layout->SetFlexForView(v1, 1);
513    layout->ClearFlexForView(v2);
514    layout->ClearFlexForView(v3);
515    host_->Layout();
516    EXPECT_EQ(gfx::Rect(10, 10, 5, 30).ToString(), v1->bounds().ToString());
517    EXPECT_EQ(gfx::Rect(25, 10, 10, 30).ToString(), v2->bounds().ToString());
518    EXPECT_EQ(gfx::Rect(45, 10, 30, 30).ToString(), v3->bounds().ToString());
519
520    // Set the third view to shrink 2/3s of the free space and leave the first
521    // view with 1/3.
522    layout->SetFlexForView(v3, 2);
523    host_->Layout();
524    EXPECT_EQ(gfx::Rect(10, 10, 15, 30).ToString(), v1->bounds().ToString());
525    EXPECT_EQ(gfx::Rect(35, 10, 10, 30).ToString(), v2->bounds().ToString());
526    EXPECT_EQ(gfx::Rect(55, 10, 20, 30).ToString(), v3->bounds().ToString());
527
528    // Clear the previously set flex values and set the second view to take all
529    // the free space with MAIN_AXIS_ALIGNMENT_END set. This causes the second
530    // view to shrink to zero and the third view still doesn't fit so it
531    // overflows.
532    layout->ClearFlexForView(v1);
533    layout->SetFlexForView(v2, 2);
534    layout->ClearFlexForView(v3);
535    host_->Layout();
536    EXPECT_EQ(gfx::Rect(10, 10, 20, 30).ToString(), v1->bounds().ToString());
537    // Conceptually this view is at 10, 40, 0, 0.
538    EXPECT_EQ(gfx::Rect(0, 0, 0, 0).ToString(), v2->bounds().ToString());
539    EXPECT_EQ(gfx::Rect(50, 10, 25, 30).ToString(), v3->bounds().ToString());
540  }
541}
542
543TEST_F(BoxLayoutTest, FlexShrinkVerticalWithRemainder) {
544  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 0, 0, 0);
545  host_->SetLayoutManager(layout);
546  View* v1 = new StaticSizedView(gfx::Size(20, 10));
547  host_->AddChildView(v1);
548  View* v2 = new StaticSizedView(gfx::Size(20, 20));
549  host_->AddChildView(v2);
550  View* v3 = new StaticSizedView(gfx::Size(20, 10));
551  host_->AddChildView(v3);
552  host_->SetBounds(0, 0, 20, 20);
553
554  std::vector<BoxLayout::MainAxisAlignment> main_alignments;
555  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
556  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
557  main_alignments.push_back(BoxLayout::MAIN_AXIS_ALIGNMENT_END);
558
559  for (size_t i = 0; i < main_alignments.size(); ++i) {
560    layout->set_main_axis_alignment(main_alignments[i]);
561
562    // The first view shrinks by 1/3 of the excess, the second view shrinks by
563    // 2/3 of the excess and the third view should maintain its preferred size.
564    layout->SetFlexForView(v1, 1);
565    layout->SetFlexForView(v2, 2);
566    layout->ClearFlexForView(v3);
567    host_->Layout();
568    EXPECT_EQ(gfx::Rect(0, 0, 20, 3).ToString(), v1->bounds().ToString());
569    EXPECT_EQ(gfx::Rect(0, 3, 20, 7).ToString(), v2->bounds().ToString());
570    EXPECT_EQ(gfx::Rect(0, 10, 20, 10).ToString(), v3->bounds().ToString());
571
572    // The second view shrinks to 2/3 of the excess, the third view shrinks to
573    // 1/3 of the excess and the first view should maintain its preferred size.
574    layout->ClearFlexForView(v1);
575    layout->SetFlexForView(v2, 2);
576    layout->SetFlexForView(v3, 1);
577    host_->Layout();
578    EXPECT_EQ(gfx::Rect(0, 0, 20, 10).ToString(), v1->bounds().ToString());
579    EXPECT_EQ(gfx::Rect(0, 10, 20, 7).ToString(), v2->bounds().ToString());
580    EXPECT_EQ(gfx::Rect(0, 17, 20, 3).ToString(), v3->bounds().ToString());
581
582    // Each view shrinks equally to fit within the available space.
583    layout->SetFlexForView(v1, 1);
584    layout->SetFlexForView(v2, 1);
585    layout->SetFlexForView(v3, 1);
586    host_->Layout();
587    EXPECT_EQ(gfx::Rect(0, 0, 20, 3).ToString(), v1->bounds().ToString());
588    EXPECT_EQ(gfx::Rect(0, 3, 20, 14).ToString(), v2->bounds().ToString());
589    EXPECT_EQ(gfx::Rect(0, 17, 20, 3).ToString(), v3->bounds().ToString());
590  }
591}
592
593TEST_F(BoxLayoutTest, MinimumCrossAxisVertical) {
594  BoxLayout* layout = new BoxLayout(BoxLayout::kVertical, 0, 0, 0);
595  host_->SetLayoutManager(layout);
596  View* v1 = new StaticSizedView(gfx::Size(20, 10));
597  host_->AddChildView(v1);
598  layout->set_minimum_cross_axis_size(30);
599
600  EXPECT_EQ(gfx::Size(30, 10), layout->GetPreferredSize(host_.get()));
601}
602
603TEST_F(BoxLayoutTest, MinimumCrossAxisHorizontal) {
604  BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 0, 0, 0);
605  host_->SetLayoutManager(layout);
606  View* v1 = new StaticSizedView(gfx::Size(20, 10));
607  host_->AddChildView(v1);
608  layout->set_minimum_cross_axis_size(30);
609
610  EXPECT_EQ(gfx::Size(20, 30), layout->GetPreferredSize(host_.get()));
611}
612
613}  // namespace views
614