Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: ui/views/layout/box_layout.cc

Issue 2836313002: BoxLayout now suports per-view margins. (Closed)
Patch Set: Fixed BoxLayout for unit tests Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/views/layout/box_layout.h ('k') | ui/views/layout/box_layout_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/layout/box_layout.h" 5 #include "ui/views/layout/box_layout.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "ui/gfx/geometry/rect.h" 9 #include "ui/gfx/geometry/rect.h"
10 #include "ui/views/view.h" 10 #include "ui/views/view.h"
11 #include "ui/views/view_properties.h"
11 12
12 namespace views { 13 namespace views {
13 14
15 BoxLayout::ViewWrapper::ViewWrapper()
16 : view_(nullptr), layout_(nullptr), orientation_(kHorizontal) {}
17
18 BoxLayout::ViewWrapper::ViewWrapper(const BoxLayout* layout, View* view)
19 : view_(view), layout_(layout), orientation_(layout_->orientation_) {
20 gfx::Insets* margins = view_ ? view_->GetProperty(kMarginsKey) : nullptr;
21 if (margins)
22 margins_ = *margins;
23 }
24
25 BoxLayout::ViewWrapper::~ViewWrapper() {}
26
27 int BoxLayout::ViewWrapper::GetHeightForWidth(int width) const {
28 if (layout_->collapse_margins_spacing_) {
29 return view_->GetHeightForWidth(width);
30 } else if (orientation_ == Orientation::kHorizontal) {
31 return view_->GetHeightForWidth(std::max(0, width - margins_.width()));
32 } else {
33 return view_->GetHeightForWidth(width) + margins_.height();
34 }
35 }
36
37 gfx::Size BoxLayout::ViewWrapper::GetPreferredSize() const {
38 gfx::Size preferred_size = view_->GetPreferredSize();
39 if (!layout_->collapse_margins_spacing_)
40 preferred_size.Enlarge(
41 orientation_ == Orientation::kHorizontal ? margins_.width() : 0,
42 orientation_ == Orientation::kVertical ? margins_.height() : 0);
43 return preferred_size;
44 }
45
46 void BoxLayout::ViewWrapper::SetBoundsRect(const gfx::Rect& bounds) {
47 if (layout_->collapse_margins_spacing_) {
48 view_->SetBoundsRect(bounds);
49 } else if (orientation_ == Orientation::kHorizontal) {
50 view_->SetBounds(bounds.x() + margins_.left(), bounds.y(),
51 std::max(0, bounds.width() - margins_.width()),
52 bounds.height());
53 } else {
54 view_->SetBounds(bounds.x(), bounds.y() + margins_.top(), bounds.width(),
55 std::max(0, bounds.height() - margins_.height()));
56 }
57 }
58
59 bool BoxLayout::ViewWrapper::visible() const {
60 return view_->visible();
61 }
62
14 BoxLayout::BoxLayout(BoxLayout::Orientation orientation, 63 BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
15 int inside_border_horizontal_spacing, 64 int inside_border_horizontal_spacing,
16 int inside_border_vertical_spacing, 65 int inside_border_vertical_spacing,
17 int between_child_spacing) 66 int between_child_spacing,
67 bool collapse_margins_spacing)
18 : orientation_(orientation), 68 : orientation_(orientation),
19 inside_border_insets_(inside_border_vertical_spacing, 69 inside_border_insets_(inside_border_vertical_spacing,
20 inside_border_horizontal_spacing), 70 inside_border_horizontal_spacing),
21 between_child_spacing_(between_child_spacing), 71 between_child_spacing_(between_child_spacing),
22 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START), 72 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START),
23 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH), 73 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH),
24 default_flex_(0), 74 default_flex_(0),
25 minimum_cross_axis_size_(0), 75 minimum_cross_axis_size_(0),
26 host_(NULL) { 76 collapse_margins_spacing_(collapse_margins_spacing),
27 } 77 host_(NULL) {}
28 78
29 BoxLayout::~BoxLayout() { 79 BoxLayout::~BoxLayout() {
30 } 80 }
31 81
32 void BoxLayout::SetFlexForView(const View* view, int flex_weight) { 82 void BoxLayout::SetFlexForView(const View* view, int flex_weight) {
33 DCHECK(host_); 83 DCHECK(host_);
34 DCHECK(view); 84 DCHECK(view);
35 DCHECK_EQ(host_, view->parent()); 85 DCHECK_EQ(host_, view->parent());
36 DCHECK_GE(flex_weight, 0); 86 DCHECK_GE(flex_weight, 0);
37 flex_map_[view] = flex_weight; 87 flex_map_[view] = flex_weight;
38 } 88 }
39 89
40 void BoxLayout::ClearFlexForView(const View* view) { 90 void BoxLayout::ClearFlexForView(const View* view) {
41 DCHECK(view); 91 DCHECK(view);
42 flex_map_.erase(view); 92 flex_map_.erase(view);
43 } 93 }
44 94
45 void BoxLayout::SetDefaultFlex(int default_flex) { 95 void BoxLayout::SetDefaultFlex(int default_flex) {
46 DCHECK_GE(default_flex, 0); 96 DCHECK_GE(default_flex, 0);
47 default_flex_ = default_flex; 97 default_flex_ = default_flex;
48 } 98 }
49 99
50 void BoxLayout::Layout(View* host) { 100 void BoxLayout::Layout(View* host) {
51 DCHECK_EQ(host_, host); 101 DCHECK_EQ(host_, host);
52 gfx::Rect child_area(host->GetLocalBounds()); 102 gfx::Rect child_area(host->GetContentsBounds());
53 child_area.Inset(host->GetInsets()); 103
54 child_area.Inset(inside_border_insets_); 104 AdjustMainAxisForMargin(&child_area);
105 AdjustCrossAxisForMargin(&child_area);
55 106
56 int total_main_axis_size = 0; 107 int total_main_axis_size = 0;
57 int num_visible = 0; 108 int num_visible = 0;
58 int flex_sum = 0; 109 int flex_sum = 0;
59 // Calculate the total size of children in the main axis. 110 // Calculate the total size of children in the main axis.
60 for (int i = 0; i < host->child_count(); ++i) { 111 for (int i = 0; i < host->child_count(); ++i) {
61 View* child = host->child_at(i); 112 ViewWrapper child(this, host->child_at(i));
62 if (!child->visible()) 113 ViewWrapper next(this, NextVisibleView(i));
114 if (!child.visible())
63 continue; 115 continue;
64 int flex = GetFlexForView(child); 116 int flex = GetFlexForView(child.view());
65 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 117 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
66 if (child_main_axis_size == 0 && flex == 0) 118 if (child_main_axis_size == 0 && flex == 0)
67 continue; 119 continue;
68 total_main_axis_size += child_main_axis_size + between_child_spacing_; 120 total_main_axis_size +=
121 child_main_axis_size + MainAxisMarginBetweenViews(child, next);
69 ++num_visible; 122 ++num_visible;
70 flex_sum += flex; 123 flex_sum += flex;
71 } 124 }
72 125
73 if (!num_visible) 126 if (!num_visible)
74 return; 127 return;
75 128
76 total_main_axis_size -= between_child_spacing_; 129 total_main_axis_size -= between_child_spacing_;
77 // Free space can be negative indicating that the views want to overflow. 130 // Free space can be negative indicating that the views want to overflow.
78 int main_free_space = MainAxisSize(child_area) - total_main_axis_size; 131 int main_free_space = MainAxisSize(child_area) - total_main_axis_size;
(...skipping 20 matching lines...) Expand all
99 gfx::Rect new_child_area(child_area); 152 gfx::Rect new_child_area(child_area);
100 SetMainAxisPosition(position, &new_child_area); 153 SetMainAxisPosition(position, &new_child_area);
101 SetMainAxisSize(size, &new_child_area); 154 SetMainAxisSize(size, &new_child_area);
102 child_area.Intersect(new_child_area); 155 child_area.Intersect(new_child_area);
103 } 156 }
104 157
105 int main_position = MainAxisPosition(child_area); 158 int main_position = MainAxisPosition(child_area);
106 int total_padding = 0; 159 int total_padding = 0;
107 int current_flex = 0; 160 int current_flex = 0;
108 for (int i = 0; i < host->child_count(); ++i) { 161 for (int i = 0; i < host->child_count(); ++i) {
109 View* child = host->child_at(i); 162 ViewWrapper child(this, host->child_at(i));
110 if (!child->visible()) 163 ViewWrapper next(this, NextVisibleView(i));
164 if (!child.visible())
111 continue; 165 continue;
112 166
113 // TODO(bruthig): Fix this. The main axis should be calculated before 167 // TODO(bruthig): Fix this. The main axis should be calculated before
114 // the cross axis size because child Views may calculate their cross axis 168 // the cross axis size because child Views may calculate their cross axis
115 // size based on their main axis size. See https://crbug.com/682266. 169 // size based on their main axis size. See https://crbug.com/682266.
116 170
117 // Calculate cross axis size. 171 // Calculate cross axis size.
118 gfx::Rect bounds(child_area); 172 gfx::Rect bounds(child_area);
119 SetMainAxisPosition(main_position, &bounds); 173 SetMainAxisPosition(main_position, &bounds);
120 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) { 174 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) {
121 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child); 175 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child);
122 int position = CrossAxisPosition(bounds); 176 int position = CrossAxisPosition(bounds);
123 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) { 177 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
124 position += free_space / 2; 178 position += free_space / 2;
125 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { 179 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
126 position += free_space; 180 position += free_space;
127 } 181 }
128 SetCrossAxisPosition(position, &bounds); 182 SetCrossAxisPosition(position, &bounds);
129 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds); 183 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds);
130 } 184 }
131 185
132 // Calculate flex padding. 186 // Calculate flex padding.
133 int current_padding = 0; 187 int current_padding = 0;
134 if (GetFlexForView(child) > 0) { 188 if (GetFlexForView(child.view()) > 0) {
135 current_flex += GetFlexForView(child); 189 current_flex += GetFlexForView(child.view());
136 int quot = (main_free_space * current_flex) / flex_sum; 190 int quot = (main_free_space * current_flex) / flex_sum;
137 int rem = (main_free_space * current_flex) % flex_sum; 191 int rem = (main_free_space * current_flex) % flex_sum;
138 current_padding = quot - total_padding; 192 current_padding = quot - total_padding;
139 // Use the current remainder to round to the nearest pixel. 193 // Use the current remainder to round to the nearest pixel.
140 if (std::abs(rem) * 2 >= flex_sum) 194 if (std::abs(rem) * 2 >= flex_sum)
141 current_padding += main_free_space > 0 ? 1 : -1; 195 current_padding += main_free_space > 0 ? 1 : -1;
142 total_padding += current_padding; 196 total_padding += current_padding;
143 } 197 }
144 198
145 // Set main axis size. 199 // Set main axis size.
146 // TODO(bruthig): Use the allocated width to determine the cross axis size. 200 // TODO(bruthig): Use the allocated width to determine the cross axis size.
147 // See https://crbug.com/682266. 201 // See https://crbug.com/682266.
148 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 202 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
149 SetMainAxisSize(child_main_axis_size + current_padding, &bounds); 203 SetMainAxisSize(child_main_axis_size + current_padding, &bounds);
150 if (MainAxisSize(bounds) > 0 || GetFlexForView(child) > 0) 204 if (MainAxisSize(bounds) > 0 || GetFlexForView(child.view()) > 0)
151 main_position += MainAxisSize(bounds) + between_child_spacing_; 205 main_position +=
206 MainAxisSize(bounds) + MainAxisMarginBetweenViews(child, next);
152 207
153 // Clamp child view bounds to |child_area|. 208 // Clamp child view bounds to |child_area|.
154 bounds.Intersect(child_area); 209 bounds.Intersect(child_area);
155 child->SetBoundsRect(bounds); 210 child.SetBoundsRect(bounds);
156 } 211 }
157 212
158 // Flex views should have grown/shrunk to consume all free space. 213 // Flex views should have grown/shrunk to consume all free space.
159 if (flex_sum) 214 if (flex_sum)
160 DCHECK_EQ(total_padding, main_free_space); 215 DCHECK_EQ(total_padding, main_free_space);
161 } 216 }
162 217
163 gfx::Size BoxLayout::GetPreferredSize(const View* host) const { 218 gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
164 DCHECK_EQ(host_, host); 219 DCHECK_EQ(host_, host);
165 // Calculate the child views' preferred width. 220 // Calculate the child views' preferred width.
166 int width = 0; 221 int width = 0;
167 if (orientation_ == kVertical) { 222 if (orientation_ == kVertical) {
168 for (int i = 0; i < host->child_count(); ++i) { 223 for (int i = 0; i < host_->child_count(); ++i) {
169 const View* child = host->child_at(i); 224 const ViewWrapper child(this, host_->child_at(i));
170 if (!child->visible()) 225 if (!child.visible())
171 continue; 226 continue;
172 227
173 width = std::max(width, child->GetPreferredSize().width()); 228 gfx::Size child_size = child.GetPreferredSize();
229 width = std::max(width, child_size.width());
174 } 230 }
175 width = std::max(width, minimum_cross_axis_size_); 231 width = std::max(width, minimum_cross_axis_size_);
176 } 232 }
177 233
178 return GetPreferredSizeForChildWidth(host, width); 234 return GetPreferredSizeForChildWidth(host, width);
179 } 235 }
180 236
181 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const { 237 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const {
182 DCHECK_EQ(host_, host); 238 DCHECK_EQ(host_, host);
183 int child_width = width - NonChildSize(host).width(); 239 int child_width = width - NonChildSize(host).width();
184 return GetPreferredSizeForChildWidth(host, child_width).height(); 240 return GetPreferredSizeForChildWidth(host, child_width).height();
185 } 241 }
186 242
187 void BoxLayout::Installed(View* host) { 243 void BoxLayout::Installed(View* host) {
188 DCHECK(!host_); 244 DCHECK(!host_);
189 host_ = host; 245 host_ = host;
190 } 246 }
191 247
192 void BoxLayout::ViewRemoved(View* host, View* view) { 248 void BoxLayout::ViewRemoved(View* host, View* view) {
193 ClearFlexForView(view); 249 ClearFlexForView(view);
194 } 250 }
195 251
196 int BoxLayout::GetFlexForView(const View* view) const { 252 int BoxLayout::GetFlexForView(const View* view) const {
197 std::map<const View*, int>::const_iterator it = flex_map_.find(view); 253 FlexMap::const_iterator it = flex_map_.find(view);
198 if (it == flex_map_.end()) 254 if (it == flex_map_.end())
199 return default_flex_; 255 return default_flex_;
200 256
201 return it->second; 257 return it->second;
202 } 258 }
203 259
204 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const { 260 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const {
205 return orientation_ == kHorizontal ? rect.width() : rect.height(); 261 return orientation_ == kHorizontal ? rect.width() : rect.height();
206 } 262 }
207 263
(...skipping 30 matching lines...) Expand all
238 rect->set_height(size); 294 rect->set_height(size);
239 } 295 }
240 296
241 void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const { 297 void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const {
242 if (orientation_ == kVertical) 298 if (orientation_ == kVertical)
243 rect->set_x(position); 299 rect->set_x(position);
244 else 300 else
245 rect->set_y(position); 301 rect->set_y(position);
246 } 302 }
247 303
248 int BoxLayout::MainAxisSizeForView(const View* view, 304 int BoxLayout::MainAxisSizeForView(const ViewWrapper& view,
249 int child_area_width) const { 305 int child_area_width) const {
250 return orientation_ == kHorizontal 306 return orientation_ == kHorizontal
251 ? view->GetPreferredSize().width() 307 ? view.GetPreferredSize().width()
252 : view->GetHeightForWidth(cross_axis_alignment_ == 308 : view.GetHeightForWidth(cross_axis_alignment_ ==
253 CROSS_AXIS_ALIGNMENT_STRETCH 309 CROSS_AXIS_ALIGNMENT_STRETCH
254 ? child_area_width 310 ? child_area_width
255 : view->GetPreferredSize().width()); 311 : view.GetPreferredSize().width());
256 } 312 }
257 313
258 int BoxLayout::CrossAxisSizeForView(const View* view) const { 314 int BoxLayout::MainAxisMarginBetweenViews(const ViewWrapper& left,
315 const ViewWrapper& right) const {
316 if (!collapse_margins_spacing_ || !left.view() || !right.view()) {
317 return between_child_spacing_;
318 } else if (orientation_ == Orientation::kHorizontal) {
319 return std::max(between_child_spacing_,
320 std::max(left.margins().right(), right.margins().left()));
321 } else {
322 return std::max(between_child_spacing_,
323 std::max(left.margins().bottom(), right.margins().top()));
324 }
325 }
326
327 gfx::Insets BoxLayout::MainAxisOuterMargin() const {
328 if (collapse_margins_spacing_) {
329 const ViewWrapper first(this, FirstVisibleView());
330 const ViewWrapper last(this, LastVisibleView());
331 if (orientation_ == Orientation::kHorizontal) {
332 return gfx::Insets(
333 0, std::max(inside_border_insets_.left(), first.margins().left()), 0,
334 std::max(inside_border_insets_.right(), last.margins().right()));
335 } else {
336 return gfx::Insets(
337 std::max(inside_border_insets_.top(), first.margins().top()), 0,
338 std::max(inside_border_insets_.bottom(), last.margins().bottom()), 0);
339 }
340 } else {
341 if (orientation_ == Orientation::kHorizontal) {
342 return gfx::Insets(0, inside_border_insets_.left(), 0,
343 inside_border_insets_.right());
344 } else {
345 return gfx::Insets(inside_border_insets_.top(), 0,
346 inside_border_insets_.bottom(), 0);
347 }
348 }
349 }
350
351 gfx::Insets BoxLayout::CrossAxisMaxViewMargin() const {
352 bool is_vertical = orientation_ == Orientation::kVertical;
353 int top_or_left = 0;
354 int bottom_or_right = 0;
355 for (int i = 0; i < host_->child_count(); ++i) {
356 const ViewWrapper child(this, host_->child_at(i));
357 if (!child.visible())
358 continue;
359 top_or_left = std::max(top_or_left, is_vertical ? child.margins().left()
360 : child.margins().top());
361 bottom_or_right =
362 std::max(bottom_or_right, is_vertical ? child.margins().right()
363 : child.margins().bottom());
364 }
365 if (is_vertical)
366 return gfx::Insets(0, top_or_left, 0, bottom_or_right);
367 else
368 return gfx::Insets(top_or_left, 0, bottom_or_right, 0);
369 }
370
371 gfx::Insets BoxLayout::CrossAxisOuterMargin() const {
372 gfx::Insets max_margin = CrossAxisMaxViewMargin();
373 bool is_vertical = orientation_ == Orientation::kVertical;
374 int top_or_left =
375 is_vertical ? inside_border_insets_.left() : inside_border_insets_.top();
376 int bottom_or_right = is_vertical ? inside_border_insets_.right()
377 : inside_border_insets_.bottom();
378 if (collapse_margins_spacing_) {
379 if (is_vertical)
380 return gfx::Insets(0, std::max(top_or_left, max_margin.left()), 0,
381 std::max(bottom_or_right, max_margin.right()));
382 else
383 return gfx::Insets(std::max(top_or_left, max_margin.top()), 0,
384 std::max(bottom_or_right, max_margin.bottom()), 0);
385 } else {
386 if (is_vertical)
387 return gfx::Insets(0, top_or_left + max_margin.left(), 0,
388 bottom_or_right + max_margin.right());
389 else
390 return gfx::Insets(top_or_left + max_margin.top(), 0,
391 bottom_or_right + max_margin.bottom(), 0);
392 }
393 }
394
395 void BoxLayout::AdjustMainAxisForMargin(gfx::Rect* rect) const {
396 rect->Inset(MainAxisOuterMargin());
397 }
398
399 void BoxLayout::AdjustCrossAxisForMargin(gfx::Rect* rect) const {
400 rect->Inset(CrossAxisOuterMargin());
401 }
402
403 int BoxLayout::CrossAxisSizeForView(const ViewWrapper& view) const {
259 // TODO(bruthig): For horizontal case use the available width and not the 404 // TODO(bruthig): For horizontal case use the available width and not the
260 // preferred width. See https://crbug.com/682266. 405 // preferred width. See https://crbug.com/682266.
261 return orientation_ == kVertical 406 return orientation_ == kVertical
262 ? view->GetPreferredSize().width() 407 ? view.GetPreferredSize().width()
263 : view->GetHeightForWidth(view->GetPreferredSize().width()); 408 : view.GetHeightForWidth(view.GetPreferredSize().width());
264 } 409 }
265 410
266 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, 411 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host,
267 int child_area_width) const { 412 int child_area_width) const {
413 DCHECK_EQ(host, host_);
268 gfx::Rect child_area_bounds; 414 gfx::Rect child_area_bounds;
269 415
270 if (orientation_ == kHorizontal) { 416 if (orientation_ == kHorizontal) {
271 // Horizontal layouts ignore |child_area_width|, meaning they mimic the 417 // Horizontal layouts ignore |child_area_width|, meaning they mimic the
272 // default behavior of GridLayout::GetPreferredHeightForWidth(). 418 // default behavior of GridLayout::GetPreferredHeightForWidth().
273 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266. 419 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266.
274 int position = 0; 420 int position = 0;
275 for (int i = 0; i < host->child_count(); ++i) { 421 for (int i = 0; i < host_->child_count(); ++i) {
276 const View* child = host->child_at(i); 422 const ViewWrapper child(this, host_->child_at(i));
277 if (!child->visible()) 423 const ViewWrapper next(this, NextVisibleView(i));
424 if (!child.visible())
278 continue; 425 continue;
279 426
280 gfx::Size size(child->GetPreferredSize()); 427 gfx::Size size(child.GetPreferredSize());
281 if (size.IsEmpty()) 428 if (size.IsEmpty())
282 continue; 429 continue;
283 430
284 gfx::Rect child_bounds(position, 0, size.width(), size.height()); 431 gfx::Rect child_bounds(position, 0, size.width(), size.height());
285 child_area_bounds.Union(child_bounds); 432 child_area_bounds.Union(child_bounds);
286 position += size.width() + between_child_spacing_; 433 position += size.width() + MainAxisMarginBetweenViews(child, next);
287 } 434 }
288 child_area_bounds.set_height( 435 child_area_bounds.set_height(
289 std::max(child_area_bounds.height(), minimum_cross_axis_size_)); 436 std::max(child_area_bounds.height(), minimum_cross_axis_size_));
290 } else { 437 } else {
291 int height = 0; 438 int height = 0;
292 for (int i = 0; i < host->child_count(); ++i) { 439 for (int i = 0; i < host_->child_count(); ++i) {
293 const View* child = host->child_at(i); 440 const ViewWrapper child(this, host_->child_at(i));
294 if (!child->visible()) 441 const ViewWrapper next(this, NextVisibleView(i));
442 if (!child.visible())
295 continue; 443 continue;
296 444
297 // Use the child area width for getting the height if the child is 445 // Use the child area width for getting the height if the child is
298 // supposed to stretch. Use its preferred size otherwise. 446 // supposed to stretch. Use its preferred size otherwise.
299 int extra_height = MainAxisSizeForView(child, child_area_width); 447 int extra_height = MainAxisSizeForView(child, child_area_width);
300 // Only add |between_child_spacing_| if this is not the only child. 448 // Only add |between_child_spacing_| if this is not the only child.
301 if (height != 0 && extra_height > 0) 449 if (next.view() && extra_height > 0)
302 height += between_child_spacing_; 450 height += MainAxisMarginBetweenViews(child, next);
303 height += extra_height; 451 height += extra_height;
304 } 452 }
305 453
306 child_area_bounds.set_width(child_area_width); 454 child_area_bounds.set_width(child_area_width);
307 child_area_bounds.set_height(height); 455 child_area_bounds.set_height(height);
308 } 456 }
309 457
310 gfx::Size non_child_size = NonChildSize(host); 458 gfx::Size non_child_size = NonChildSize(host_);
311 return gfx::Size(child_area_bounds.width() + non_child_size.width(), 459 return gfx::Size(child_area_bounds.width() + non_child_size.width(),
312 child_area_bounds.height() + non_child_size.height()); 460 child_area_bounds.height() + non_child_size.height());
313 } 461 }
314 462
315 gfx::Size BoxLayout::NonChildSize(const View* host) const { 463 gfx::Size BoxLayout::NonChildSize(const View* host) const {
316 gfx::Insets insets(host->GetInsets()); 464 gfx::Insets insets(host->GetInsets());
317 return gfx::Size(insets.width() + inside_border_insets_.width(), 465 if (!collapse_margins_spacing_) {
318 insets.height() + inside_border_insets_.height()); 466 gfx::Insets max_margin = CrossAxisMaxViewMargin();
467 return gfx::Size(
468 insets.width() + inside_border_insets_.width() + max_margin.width(),
469 insets.height() + inside_border_insets_.height() + max_margin.height());
470 } else {
471 gfx::Insets main_axis = MainAxisOuterMargin();
472 gfx::Insets cross_axis = CrossAxisOuterMargin();
473 return gfx::Size(
474 insets.width() + main_axis.width() + cross_axis.width(),
475 insets.height() + main_axis.height() + cross_axis.height());
476 }
477 }
478
479 View* BoxLayout::NextVisibleView(int index) const {
480 for (int i = index + 1; i < host_->child_count(); ++i) {
481 View* result = host_->child_at(i);
482 if (result->visible())
483 return result;
484 }
485 return nullptr;
486 }
487
488 View* BoxLayout::FirstVisibleView() const {
489 return NextVisibleView(-1);
490 }
491
492 View* BoxLayout::LastVisibleView() const {
493 for (int i = host_->child_count() - 1; i >= 0; --i) {
494 View* result = host_->child_at(i);
495 if (result->visible())
496 return result;
497 }
498 return nullptr;
319 } 499 }
320 500
321 } // namespace views 501 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/layout/box_layout.h ('k') | ui/views/layout/box_layout_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698