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

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

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

Powered by Google App Engine
This is Rietveld 408576698