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

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

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

Powered by Google App Engine
This is Rietveld 408576698