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

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

Issue 2836313002: BoxLayout now suports per-view margins. (Closed)
Patch Set: Fixed comment describing the BoxLayout behavior. 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 namespace {
16
17 // Returns the maximum of the given insets along the given |axis|.
18 // NOTE: |axis| is different from |orientation_|; it specifies the actual
19 // desired axis.
20 enum Axis { HORIZONTAL_AXIS, VERTICAL_AXIS };
21
22 gfx::Insets MaxAxisInsets(Axis axis,
23 const gfx::Insets& leading1,
24 const gfx::Insets& leading2,
25 const gfx::Insets& trailing1,
26 const gfx::Insets& trailing2) {
27 if (axis == HORIZONTAL_AXIS)
sky 2017/06/05 21:04:10 use {}
kylix_rd 2017/06/06 18:22:34 Done.
28 return gfx::Insets(0, std::max(leading1.left(), leading2.left()), 0,
29 std::max(trailing1.right(), trailing2.right()));
30 return gfx::Insets(std::max(leading1.top(), leading2.top()), 0,
31 std::max(trailing1.bottom(), trailing2.bottom()), 0);
32 }
33 }
sky 2017/06/05 21:04:10 Newline between 32/33 and // namespace (with two s
kylix_rd 2017/06/06 18:22:35 Done.
34
35 BoxLayout::ViewWrapper::ViewWrapper()
36 : view_(nullptr), layout_(nullptr), orientation_(kHorizontal) {}
37
38 BoxLayout::ViewWrapper::ViewWrapper(const BoxLayout* layout, View* view)
39 : view_(view), layout_(layout), orientation_(layout_->orientation_) {
40 gfx::Insets* margins = view_ ? view_->GetProperty(kMarginsKey) : nullptr;
41 if (margins)
42 margins_ = *margins;
43 }
44
45 BoxLayout::ViewWrapper::~ViewWrapper() {}
46
47 int BoxLayout::ViewWrapper::GetHeightForWidth(int width) const {
48 if (layout_->collapse_margins_spacing_)
sky 2017/06/05 21:04:10 This is subtle and worth a comment. In particular
kylix_rd 2017/06/06 18:22:34 Done.
49 return view_->GetHeightForWidth(width);
50 if (orientation_ == Orientation::kHorizontal) {
51 return view_->GetHeightForWidth(std::max(0, width - margins_.width())) +
52 margins_.height();
53 } else {
sky 2017/06/05 21:04:10 no else after early return.
kylix_rd 2017/06/06 18:22:34 Done.
54 return view_->GetHeightForWidth(width) + margins_.height();
55 }
56 }
57
58 gfx::Size BoxLayout::ViewWrapper::GetPreferredSize() const {
59 gfx::Size preferred_size = view_->GetPreferredSize();
60 if (!layout_->collapse_margins_spacing_)
61 preferred_size.Enlarge(margins_.width(), margins_.height());
62 return preferred_size;
63 }
64
65 void BoxLayout::ViewWrapper::SetBoundsRect(const gfx::Rect& bounds) {
66 gfx::Rect new_bounds = bounds;
67 if (!layout_->collapse_margins_spacing_) {
68 if (orientation_ == Orientation::kHorizontal) {
69 new_bounds.set_x(bounds.x() + margins_.left());
70 new_bounds.set_width(std::max(0, bounds.width() - margins_.width()));
71 }
72 if (orientation_ == Orientation::kVertical) {
sky 2017/06/05 21:04:10 Replace this if with an else.
kylix_rd 2017/06/06 18:22:34 Done.
73 new_bounds.set_y(bounds.y() + margins_.top());
74 new_bounds.set_height(std::max(0, bounds.height() - margins_.height()));
75 }
76 }
77 view_->SetBoundsRect(new_bounds);
78 }
79
80 bool BoxLayout::ViewWrapper::visible() const {
81 return view_->visible();
82 }
83
14 BoxLayout::BoxLayout(BoxLayout::Orientation orientation, 84 BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
15 int inside_border_horizontal_spacing, 85 int inside_border_horizontal_spacing,
16 int inside_border_vertical_spacing, 86 int inside_border_vertical_spacing,
17 int between_child_spacing) 87 int between_child_spacing,
88 bool collapse_margins_spacing)
18 : orientation_(orientation), 89 : orientation_(orientation),
19 inside_border_insets_(inside_border_vertical_spacing, 90 inside_border_insets_(inside_border_vertical_spacing,
20 inside_border_horizontal_spacing), 91 inside_border_horizontal_spacing),
21 between_child_spacing_(between_child_spacing), 92 between_child_spacing_(between_child_spacing),
22 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START), 93 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START),
23 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH), 94 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH),
24 default_flex_(0), 95 default_flex_(0),
25 minimum_cross_axis_size_(0), 96 minimum_cross_axis_size_(0),
26 host_(NULL) { 97 collapse_margins_spacing_(collapse_margins_spacing),
27 } 98 host_(NULL) {}
28 99
29 BoxLayout::~BoxLayout() { 100 BoxLayout::~BoxLayout() {
30 } 101 }
31 102
32 void BoxLayout::SetFlexForView(const View* view, int flex_weight) { 103 void BoxLayout::SetFlexForView(const View* view, int flex_weight) {
33 DCHECK(host_); 104 DCHECK(host_);
34 DCHECK(view); 105 DCHECK(view);
35 DCHECK_EQ(host_, view->parent()); 106 DCHECK_EQ(host_, view->parent());
36 DCHECK_GE(flex_weight, 0); 107 DCHECK_GE(flex_weight, 0);
37 flex_map_[view] = flex_weight; 108 flex_map_[view] = flex_weight;
38 } 109 }
39 110
40 void BoxLayout::ClearFlexForView(const View* view) { 111 void BoxLayout::ClearFlexForView(const View* view) {
41 DCHECK(view); 112 DCHECK(view);
42 flex_map_.erase(view); 113 flex_map_.erase(view);
43 } 114 }
44 115
45 void BoxLayout::SetDefaultFlex(int default_flex) { 116 void BoxLayout::SetDefaultFlex(int default_flex) {
46 DCHECK_GE(default_flex, 0); 117 DCHECK_GE(default_flex, 0);
47 default_flex_ = default_flex; 118 default_flex_ = default_flex;
48 } 119 }
49 120
50 void BoxLayout::Layout(View* host) { 121 void BoxLayout::Layout(View* host) {
51 DCHECK_EQ(host_, host); 122 DCHECK_EQ(host_, host);
52 gfx::Rect child_area(host->GetLocalBounds()); 123 gfx::Rect child_area(host->GetContentsBounds());
53 child_area.Inset(host->GetInsets()); 124
54 child_area.Inset(inside_border_insets_); 125 AdjustMainAxisForMargin(&child_area);
126 gfx::Insets max_cross_axis_margin;
sky 2017/06/05 21:04:10 Early out if child_area empty?
kylix_rd 2017/06/06 18:22:34 Done.
127 if (!collapse_margins_spacing_) {
128 AdjustCrossAxisForInsets(&child_area);
129 max_cross_axis_margin = CrossAxisMaxViewMargin();
130 }
55 131
56 int total_main_axis_size = 0; 132 int total_main_axis_size = 0;
57 int num_visible = 0; 133 int num_visible = 0;
58 int flex_sum = 0; 134 int flex_sum = 0;
59 // Calculate the total size of children in the main axis. 135 // Calculate the total size of children in the main axis.
60 for (int i = 0; i < host->child_count(); ++i) { 136 for (int i = 0; i < host->child_count(); ++i) {
61 View* child = host->child_at(i); 137 const ViewWrapper child(this, host->child_at(i));
62 if (!child->visible()) 138 if (!child.visible())
63 continue; 139 continue;
64 int flex = GetFlexForView(child); 140 int flex = GetFlexForView(child.view());
65 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 141 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
66 if (child_main_axis_size == 0 && flex == 0) 142 if (child_main_axis_size == 0 && flex == 0)
67 continue; 143 continue;
68 total_main_axis_size += child_main_axis_size + between_child_spacing_; 144 total_main_axis_size += child_main_axis_size +
145 MainAxisMarginBetweenViews(
146 child, ViewWrapper(this, NextVisibleView(i)));
69 ++num_visible; 147 ++num_visible;
70 flex_sum += flex; 148 flex_sum += flex;
71 } 149 }
72 150
73 if (!num_visible) 151 if (!num_visible)
74 return; 152 return;
75 153
76 total_main_axis_size -= between_child_spacing_; 154 total_main_axis_size -= between_child_spacing_;
77 // Free space can be negative indicating that the views want to overflow. 155 // Free space can be negative indicating that the views want to overflow.
78 int main_free_space = MainAxisSize(child_area) - total_main_axis_size; 156 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); 177 gfx::Rect new_child_area(child_area);
100 SetMainAxisPosition(position, &new_child_area); 178 SetMainAxisPosition(position, &new_child_area);
101 SetMainAxisSize(size, &new_child_area); 179 SetMainAxisSize(size, &new_child_area);
102 child_area.Intersect(new_child_area); 180 child_area.Intersect(new_child_area);
103 } 181 }
104 182
105 int main_position = MainAxisPosition(child_area); 183 int main_position = MainAxisPosition(child_area);
106 int total_padding = 0; 184 int total_padding = 0;
107 int current_flex = 0; 185 int current_flex = 0;
108 for (int i = 0; i < host->child_count(); ++i) { 186 for (int i = 0; i < host->child_count(); ++i) {
109 View* child = host->child_at(i); 187 ViewWrapper child(this, host->child_at(i));
110 if (!child->visible()) 188 if (!child.visible())
111 continue; 189 continue;
112 190
113 // TODO(bruthig): Fix this. The main axis should be calculated before 191 // TODO(bruthig): Fix this. The main axis should be calculated before
114 // the cross axis size because child Views may calculate their cross axis 192 // 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. 193 // size based on their main axis size. See https://crbug.com/682266.
116 194
117 // Calculate cross axis size. 195 // Calculate cross axis size.
118 gfx::Rect bounds(child_area); 196 gfx::Rect bounds(child_area);
197 gfx::Rect min_child_area(child_area);
198 gfx::Insets child_margins;
199 if (collapse_margins_spacing_)
200 child_margins = MaxAxisInsets(
sky 2017/06/05 21:04:10 {}
kylix_rd 2017/06/06 18:22:35 Done.
201 orientation_ == kVertical ? HORIZONTAL_AXIS : VERTICAL_AXIS,
202 child.margins(), inside_border_insets_, child.margins(),
203 inside_border_insets_);
204 else
205 child_margins = child.margins();
206 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_STRETCH ||
207 cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
208 InsetCrossAxis(&min_child_area, CrossAxisLeadingInset(child_margins),
209 CrossAxisTrailingInset(child_margins));
210 }
211
119 SetMainAxisPosition(main_position, &bounds); 212 SetMainAxisPosition(main_position, &bounds);
120 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) { 213 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) {
121 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child); 214 int cross_axis_margin_size = CrossAxisMarginSizeForView(child);
215 int view_cross_axis_size =
216 CrossAxisSizeForView(child) - cross_axis_margin_size;
217 int free_space = CrossAxisSize(bounds) - view_cross_axis_size;
122 int position = CrossAxisPosition(bounds); 218 int position = CrossAxisPosition(bounds);
123 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) { 219 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
220 if (view_cross_axis_size > CrossAxisSize(min_child_area))
221 view_cross_axis_size = CrossAxisSize(min_child_area);
124 position += free_space / 2; 222 position += free_space / 2;
223 position = std::max(position, CrossAxisLeadingEdge(min_child_area));
125 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { 224 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
126 position += free_space; 225 position += free_space - CrossAxisTrailingInset(max_cross_axis_margin);
226 if (!collapse_margins_spacing_)
227 InsetCrossAxis(&min_child_area,
228 CrossAxisLeadingInset(child.margins()),
229 CrossAxisTrailingInset(max_cross_axis_margin));
230 } else {
231 position += CrossAxisLeadingInset(max_cross_axis_margin);
232 if (!collapse_margins_spacing_)
233 InsetCrossAxis(&min_child_area,
234 CrossAxisLeadingInset(max_cross_axis_margin),
235 CrossAxisTrailingInset(child.margins()));
127 } 236 }
128 SetCrossAxisPosition(position, &bounds); 237 SetCrossAxisPosition(position, &bounds);
129 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds); 238 SetCrossAxisSize(view_cross_axis_size, &bounds);
130 } 239 }
131 240
132 // Calculate flex padding. 241 // Calculate flex padding.
133 int current_padding = 0; 242 int current_padding = 0;
134 if (GetFlexForView(child) > 0) { 243 if (GetFlexForView(child.view()) > 0) {
135 current_flex += GetFlexForView(child); 244 current_flex += GetFlexForView(child.view());
136 int quot = (main_free_space * current_flex) / flex_sum; 245 int quot = (main_free_space * current_flex) / flex_sum;
137 int rem = (main_free_space * current_flex) % flex_sum; 246 int rem = (main_free_space * current_flex) % flex_sum;
138 current_padding = quot - total_padding; 247 current_padding = quot - total_padding;
139 // Use the current remainder to round to the nearest pixel. 248 // Use the current remainder to round to the nearest pixel.
140 if (std::abs(rem) * 2 >= flex_sum) 249 if (std::abs(rem) * 2 >= flex_sum)
141 current_padding += main_free_space > 0 ? 1 : -1; 250 current_padding += main_free_space > 0 ? 1 : -1;
142 total_padding += current_padding; 251 total_padding += current_padding;
143 } 252 }
144 253
145 // Set main axis size. 254 // Set main axis size.
146 // TODO(bruthig): Use the allocated width to determine the cross axis size. 255 // TODO(bruthig): Use the allocated width to determine the cross axis size.
147 // See https://crbug.com/682266. 256 // See https://crbug.com/682266.
148 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 257 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
149 SetMainAxisSize(child_main_axis_size + current_padding, &bounds); 258 SetMainAxisSize(child_main_axis_size + current_padding, &bounds);
150 if (MainAxisSize(bounds) > 0 || GetFlexForView(child) > 0) 259 if (MainAxisSize(bounds) > 0 || GetFlexForView(child.view()) > 0)
151 main_position += MainAxisSize(bounds) + between_child_spacing_; 260 main_position += MainAxisSize(bounds) +
261 MainAxisMarginBetweenViews(
262 child, ViewWrapper(this, NextVisibleView(i)));
152 263
153 // Clamp child view bounds to |child_area|. 264 // Clamp child view bounds to |child_area|.
154 bounds.Intersect(child_area); 265 bounds.Intersect(min_child_area);
155 child->SetBoundsRect(bounds); 266 child.SetBoundsRect(bounds);
156 } 267 }
157 268
158 // Flex views should have grown/shrunk to consume all free space. 269 // Flex views should have grown/shrunk to consume all free space.
159 if (flex_sum) 270 if (flex_sum)
160 DCHECK_EQ(total_padding, main_free_space); 271 DCHECK_EQ(total_padding, main_free_space);
161 } 272 }
162 273
163 gfx::Size BoxLayout::GetPreferredSize(const View* host) const { 274 gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
164 DCHECK_EQ(host_, host); 275 DCHECK_EQ(host_, host);
165 // Calculate the child views' preferred width. 276 // Calculate the child views' preferred width.
166 int width = 0; 277 int width = 0;
167 if (orientation_ == kVertical) { 278 if (orientation_ == kVertical) {
168 for (int i = 0; i < host->child_count(); ++i) { 279 int leading = 0;
sky 2017/06/05 21:04:10 This whole block could use a comment.
kylix_rd 2017/06/06 18:22:34 Done.
169 const View* child = host->child_at(i); 280 int trailing = 0;
170 if (!child->visible()) 281 gfx::Rect child_view_area;
282 for (int i = 0; i < host_->child_count(); ++i) {
283 const ViewWrapper child(this, host_->child_at(i));
284 if (!child.visible())
171 continue; 285 continue;
172 286
173 width = std::max(width, child->GetPreferredSize().width()); 287 gfx::Size child_size = child.view()->GetPreferredSize();
sky 2017/06/05 21:04:10 This is worth a comment as to why you don't use th
kylix_rd 2017/06/06 18:22:34 Done.
288 gfx::Insets child_margins;
289 if (collapse_margins_spacing_)
sky 2017/06/05 21:04:10 use {} as body spans multiple lines.
kylix_rd 2017/06/06 18:22:34 Done.
290 child_margins = MaxAxisInsets(HORIZONTAL_AXIS, child.margins(),
291 inside_border_insets_, child.margins(),
292 inside_border_insets_);
293 else
294 child_margins = child.margins();
295 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_START) {
296 leading = std::max(leading, CrossAxisLeadingInset(child_margins));
297 width = std::max(
298 width, child_size.width() + CrossAxisTrailingInset(child_margins));
299 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
300 trailing = std::max(trailing, CrossAxisTrailingInset(child_margins));
301 width = std::max(
302 width, child_size.width() + CrossAxisLeadingInset(child_margins));
303 } else {
304 gfx::Rect child_bounds =
305 gfx::Rect(-(child_size.width() / 2), 0, child_size.width(),
sky 2017/06/05 21:04:10 Shouldn't you use the margins in this code path?
kylix_rd 2017/06/06 18:22:34 No. This code is "centering" the view horizontally
306 child_size.height());
307 child_bounds.Inset(-child.margins().left(), 0, -child.margins().right(),
308 0);
309 child_view_area.Union(child_bounds);
310 width = std::max(width, child_view_area.width());
311 }
174 } 312 }
175 width = std::max(width, minimum_cross_axis_size_); 313 width = std::max(width + leading + trailing, minimum_cross_axis_size_);
176 } 314 }
177 315
178 return GetPreferredSizeForChildWidth(host, width); 316 return GetPreferredSizeForChildWidth(host, width);
179 } 317 }
180 318
181 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const { 319 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const {
182 DCHECK_EQ(host_, host); 320 DCHECK_EQ(host_, host);
183 int child_width = width - NonChildSize(host).width(); 321 int child_width = width - NonChildSize(host).width();
184 return GetPreferredSizeForChildWidth(host, child_width).height(); 322 return GetPreferredSizeForChildWidth(host, child_width).height();
185 } 323 }
186 324
187 void BoxLayout::Installed(View* host) { 325 void BoxLayout::Installed(View* host) {
188 DCHECK(!host_); 326 DCHECK(!host_);
189 host_ = host; 327 host_ = host;
190 } 328 }
191 329
192 void BoxLayout::ViewRemoved(View* host, View* view) { 330 void BoxLayout::ViewRemoved(View* host, View* view) {
193 ClearFlexForView(view); 331 ClearFlexForView(view);
194 } 332 }
195 333
196 int BoxLayout::GetFlexForView(const View* view) const { 334 int BoxLayout::GetFlexForView(const View* view) const {
197 std::map<const View*, int>::const_iterator it = flex_map_.find(view); 335 FlexMap::const_iterator it = flex_map_.find(view);
198 if (it == flex_map_.end()) 336 if (it == flex_map_.end())
199 return default_flex_; 337 return default_flex_;
200 338
201 return it->second; 339 return it->second;
202 } 340 }
203 341
204 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const { 342 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const {
205 return orientation_ == kHorizontal ? rect.width() : rect.height(); 343 return orientation_ == kHorizontal ? rect.width() : rect.height();
206 } 344 }
207 345
(...skipping 30 matching lines...) Expand all
238 rect->set_height(size); 376 rect->set_height(size);
239 } 377 }
240 378
241 void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const { 379 void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const {
242 if (orientation_ == kVertical) 380 if (orientation_ == kVertical)
243 rect->set_x(position); 381 rect->set_x(position);
244 else 382 else
245 rect->set_y(position); 383 rect->set_y(position);
246 } 384 }
247 385
248 int BoxLayout::MainAxisSizeForView(const View* view, 386 int BoxLayout::MainAxisSizeForView(const ViewWrapper& view,
249 int child_area_width) const { 387 int child_area_width) const {
250 return orientation_ == kHorizontal 388 return orientation_ == kHorizontal
251 ? view->GetPreferredSize().width() 389 ? view.GetPreferredSize().width()
252 : view->GetHeightForWidth(cross_axis_alignment_ == 390 : view.GetHeightForWidth(cross_axis_alignment_ ==
253 CROSS_AXIS_ALIGNMENT_STRETCH 391 CROSS_AXIS_ALIGNMENT_STRETCH
254 ? child_area_width 392 ? child_area_width
255 : view->GetPreferredSize().width()); 393 : view.GetPreferredSize().width());
256 } 394 }
257 395
258 int BoxLayout::CrossAxisSizeForView(const View* view) const { 396 int BoxLayout::MainAxisLeadingInset(const gfx::Insets& insets) const {
397 return orientation_ == kHorizontal ? insets.left() : insets.top();
398 }
399
400 int BoxLayout::MainAxisTrailingInset(const gfx::Insets& insets) const {
401 return orientation_ == kHorizontal ? insets.right() : insets.bottom();
402 }
403
404 int BoxLayout::CrossAxisLeadingEdge(const gfx::Rect& rect) const {
405 return orientation_ == kVertical ? rect.x() : rect.y();
406 }
407
408 int BoxLayout::CrossAxisLeadingInset(const gfx::Insets& insets) const {
409 return orientation_ == kVertical ? insets.left() : insets.top();
410 }
411
412 int BoxLayout::CrossAxisTrailingInset(const gfx::Insets& insets) const {
413 return orientation_ == kVertical ? insets.right() : insets.bottom();
414 }
415
416 int BoxLayout::MainAxisMarginBetweenViews(const ViewWrapper& leading,
417 const ViewWrapper& trailing) const {
418 if (!collapse_margins_spacing_ || !leading.view() || !trailing.view())
419 return between_child_spacing_;
420 return std::max(between_child_spacing_,
421 std::max(MainAxisTrailingInset(leading.margins()),
422 MainAxisLeadingInset(trailing.margins())));
423 }
424
425 gfx::Insets BoxLayout::MainAxisOuterMargin() const {
426 if (collapse_margins_spacing_) {
427 const ViewWrapper first(this, FirstVisibleView());
428 const ViewWrapper last(this, LastVisibleView());
429 return MaxAxisInsets(
430 orientation_ == kHorizontal ? HORIZONTAL_AXIS : VERTICAL_AXIS,
431 inside_border_insets_, first.margins(), inside_border_insets_,
432 last.margins());
433 }
434 return MaxAxisInsets(
435 orientation_ == kHorizontal ? HORIZONTAL_AXIS : VERTICAL_AXIS,
436 inside_border_insets_, gfx::Insets(), inside_border_insets_,
437 gfx::Insets());
438 }
439
440 gfx::Insets BoxLayout::CrossAxisMaxViewMargin() const {
441 int leading = 0;
442 int trailing = 0;
443 for (int i = 0; i < host_->child_count(); ++i) {
444 const ViewWrapper child(this, host_->child_at(i));
445 if (!child.visible())
446 continue;
447 leading = std::max(leading, CrossAxisLeadingInset(child.margins()));
448 trailing = std::max(trailing, CrossAxisTrailingInset(child.margins()));
449 }
450 if (orientation_ == Orientation::kVertical)
451 return gfx::Insets(0, leading, 0, trailing);
452 return gfx::Insets(leading, 0, trailing, 0);
453 }
454
455 void BoxLayout::AdjustMainAxisForMargin(gfx::Rect* rect) const {
456 rect->Inset(MainAxisOuterMargin());
457 }
458
459 void BoxLayout::AdjustCrossAxisForInsets(gfx::Rect* rect) const {
460 rect->Inset(orientation_ == Orientation::kVertical
461 ? gfx::Insets(0, inside_border_insets_.left(), 0,
462 inside_border_insets_.right())
463 : gfx::Insets(inside_border_insets_.top(), 0,
464 inside_border_insets_.bottom(), 0));
465 }
466
467 int BoxLayout::CrossAxisSizeForView(const ViewWrapper& view) const {
259 // TODO(bruthig): For horizontal case use the available width and not the 468 // TODO(bruthig): For horizontal case use the available width and not the
260 // preferred width. See https://crbug.com/682266. 469 // preferred width. See https://crbug.com/682266.
261 return orientation_ == kVertical 470 return orientation_ == kVertical
262 ? view->GetPreferredSize().width() 471 ? view.GetPreferredSize().width()
263 : view->GetHeightForWidth(view->GetPreferredSize().width()); 472 : view.GetHeightForWidth(view.GetPreferredSize().width());
473 }
474
475 int BoxLayout::CrossAxisMarginSizeForView(const ViewWrapper& view) const {
476 return collapse_margins_spacing_
477 ? 0
478 : (orientation_ == kVertical ? view.margins().width()
479 : view.margins().height());
480 }
481
482 int BoxLayout::CrossAxisLeadingMarginForView(const ViewWrapper& view) const {
483 return collapse_margins_spacing_ ? 0 : CrossAxisLeadingInset(view.margins());
484 }
485
486 void BoxLayout::InsetCrossAxis(gfx::Rect* rect,
487 int leading,
488 int trailing) const {
489 if (orientation_ == kVertical)
490 rect->Inset(leading, 0, trailing, 0);
491 else
492 rect->Inset(0, leading, 0, trailing);
264 } 493 }
265 494
266 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, 495 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host,
267 int child_area_width) const { 496 int child_area_width) const {
497 DCHECK_EQ(host, host_);
268 gfx::Rect child_area_bounds; 498 gfx::Rect child_area_bounds;
269 499
270 if (orientation_ == kHorizontal) { 500 if (orientation_ == kHorizontal) {
271 // Horizontal layouts ignore |child_area_width|, meaning they mimic the 501 // Horizontal layouts ignore |child_area_width|, meaning they mimic the
272 // default behavior of GridLayout::GetPreferredHeightForWidth(). 502 // default behavior of GridLayout::GetPreferredHeightForWidth().
273 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266. 503 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266.
274 int position = 0; 504 int position = 0;
275 for (int i = 0; i < host->child_count(); ++i) { 505 gfx::Insets max_margins = CrossAxisMaxViewMargin();
276 const View* child = host->child_at(i); 506 for (int i = 0; i < host_->child_count(); ++i) {
277 if (!child->visible()) 507 const ViewWrapper child(this, host_->child_at(i));
508 if (!child.visible())
278 continue; 509 continue;
279 510
280 gfx::Size size(child->GetPreferredSize()); 511 gfx::Size size(child.view()->GetPreferredSize());
281 if (size.IsEmpty()) 512 if (size.IsEmpty())
282 continue; 513 continue;
283 514
284 gfx::Rect child_bounds(position, 0, size.width(), size.height()); 515 gfx::Rect child_bounds = gfx::Rect(
516 position, 0,
517 size.width() +
518 (!collapse_margins_spacing_ ? child.margins().width() : 0),
519 size.height());
520 gfx::Insets child_margins;
521 if (collapse_margins_spacing_)
522 child_margins =
523 MaxAxisInsets(VERTICAL_AXIS, child.margins(), inside_border_insets_,
524 child.margins(), inside_border_insets_);
525 else
526 child_margins = child.margins();
527
528 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_START) {
529 child_bounds.Inset(0, -CrossAxisLeadingInset(max_margins), 0,
530 -child_margins.bottom());
531 child_bounds.set_origin(gfx::Point(position, 0));
532 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
533 child_bounds.Inset(0, -child_margins.top(), 0,
534 -CrossAxisTrailingInset(max_margins));
535 child_bounds.set_origin(gfx::Point(position, 0));
536 } else {
537 child_bounds.set_origin(
538 gfx::Point(position, -(child_bounds.height() / 2)));
539 child_bounds.Inset(0, -child_margins.top(), 0, -child_margins.bottom());
540 }
541
285 child_area_bounds.Union(child_bounds); 542 child_area_bounds.Union(child_bounds);
286 position += size.width() + between_child_spacing_; 543 position += child_bounds.width() +
544 MainAxisMarginBetweenViews(
545 child, ViewWrapper(this, NextVisibleView(i)));
sky 2017/06/05 21:04:10 optional: I have to admit I'm mildly bothered that
kylix_rd 2017/06/06 18:22:34 Understandable. It could be incorporated into the
287 } 546 }
288 child_area_bounds.set_height( 547 child_area_bounds.set_height(
289 std::max(child_area_bounds.height(), minimum_cross_axis_size_)); 548 std::max(child_area_bounds.height(), minimum_cross_axis_size_));
290 } else { 549 } else {
291 int height = 0; 550 int height = 0;
292 for (int i = 0; i < host->child_count(); ++i) { 551 for (int i = 0; i < host_->child_count(); ++i) {
293 const View* child = host->child_at(i); 552 const ViewWrapper child(this, host_->child_at(i));
294 if (!child->visible()) 553 if (!child.visible())
295 continue; 554 continue;
296 555
556 const ViewWrapper next(this, NextVisibleView(i));
297 // Use the child area width for getting the height if the child is 557 // Use the child area width for getting the height if the child is
298 // supposed to stretch. Use its preferred size otherwise. 558 // supposed to stretch. Use its preferred size otherwise.
299 int extra_height = MainAxisSizeForView(child, child_area_width); 559 int extra_height = MainAxisSizeForView(child, child_area_width);
300 // Only add |between_child_spacing_| if this is not the only child. 560 // Only add |between_child_spacing_| if this is not the only child.
301 if (height != 0 && extra_height > 0) 561 if (next.view() && extra_height > 0)
302 height += between_child_spacing_; 562 height += MainAxisMarginBetweenViews(child, next);
303 height += extra_height; 563 height += extra_height;
304 } 564 }
305 565
306 child_area_bounds.set_width(child_area_width); 566 child_area_bounds.set_width(child_area_width);
307 child_area_bounds.set_height(height); 567 child_area_bounds.set_height(height);
308 } 568 }
309 569
310 gfx::Size non_child_size = NonChildSize(host); 570 gfx::Size non_child_size = NonChildSize(host_);
311 return gfx::Size(child_area_bounds.width() + non_child_size.width(), 571 return gfx::Size(child_area_bounds.width() + non_child_size.width(),
312 child_area_bounds.height() + non_child_size.height()); 572 child_area_bounds.height() + non_child_size.height());
313 } 573 }
314 574
315 gfx::Size BoxLayout::NonChildSize(const View* host) const { 575 gfx::Size BoxLayout::NonChildSize(const View* host) const {
316 gfx::Insets insets(host->GetInsets()); 576 gfx::Insets insets(host->GetInsets());
317 return gfx::Size(insets.width() + inside_border_insets_.width(), 577 if (!collapse_margins_spacing_)
318 insets.height() + inside_border_insets_.height()); 578 return gfx::Size(insets.width() + inside_border_insets_.width(),
579 insets.height() + inside_border_insets_.height());
580 gfx::Insets main_axis = MainAxisOuterMargin();
581 gfx::Insets cross_axis = inside_border_insets_;
582 return gfx::Size(insets.width() + main_axis.width() + cross_axis.width(),
583 insets.height() + main_axis.height() + cross_axis.height());
584 }
585
586 View* BoxLayout::NextVisibleView(int index) const {
587 for (int i = index + 1; i < host_->child_count(); ++i) {
588 View* result = host_->child_at(i);
589 if (result->visible())
590 return result;
591 }
592 return nullptr;
593 }
594
595 View* BoxLayout::FirstVisibleView() const {
596 return NextVisibleView(-1);
597 }
598
599 View* BoxLayout::LastVisibleView() const {
600 for (int i = host_->child_count() - 1; i >= 0; --i) {
601 View* result = host_->child_at(i);
602 if (result->visible())
603 return result;
604 }
605 return nullptr;
319 } 606 }
320 607
321 } // namespace views 608 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698