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