OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |