Chromium Code Reviews| 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 if (orientation_ == Orientation::kHorizontal) { | |
| 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)); |
|
sky
2017/05/25 19:16:51
move after visible check.
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 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 Loading... | |
| 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)); |
|
sky
2017/05/25 19:16:51
move after visible check.
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 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 Loading... | |
| 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 gfx::Insets BoxLayout::MaxAxisInsets(Axis axis, |
| 330 const gfx::Insets& left1, | |
| 331 const gfx::Insets& left2, | |
| 332 const gfx::Insets& right1, | |
| 333 const gfx::Insets& right2) const { | |
| 334 if (axis == HORIZONTAL_AXIS) | |
| 335 return gfx::Insets(0, std::max(left1.left(), left2.left()), 0, | |
| 336 std::max(right1.right(), right2.right())); | |
| 337 return gfx::Insets(std::max(left1.top(), left2.top()), 0, | |
| 338 std::max(right1.bottom(), right2.bottom()), 0); | |
| 339 } | |
| 340 | |
| 341 int BoxLayout::MainAxisLeadingInset(const gfx::Insets& insets) const { | |
| 342 return orientation_ == kHorizontal ? insets.left() : insets.top(); | |
|
sky
2017/05/25 19:16:51
Much easier to read, thank you!
| |
| 343 } | |
| 344 | |
| 345 int BoxLayout::MainAxisTrailingInset(const gfx::Insets& insets) const { | |
| 346 return orientation_ == kHorizontal ? insets.right() : insets.bottom(); | |
| 347 } | |
| 348 | |
| 349 int BoxLayout::CrossAxisLeadingInset(const gfx::Insets& insets) const { | |
| 350 return orientation_ == kVertical ? insets.left() : insets.top(); | |
| 351 } | |
| 352 | |
| 353 int BoxLayout::CrossAxisTrailingInset(const gfx::Insets& insets) const { | |
| 354 return orientation_ == kVertical ? insets.right() : insets.bottom(); | |
| 355 } | |
| 356 | |
| 357 int BoxLayout::MainAxisMarginBetweenViews(const ViewWrapper& left, | |
|
sky
2017/05/25 19:16:51
leading/trailing
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 358 const ViewWrapper& right) const { | |
| 359 if (!collapse_margins_spacing_ || !left.view() || !right.view()) | |
| 360 return between_child_spacing_; | |
| 361 return std::max(between_child_spacing_, | |
| 362 std::max(MainAxisLeadingInset(left.margins()), | |
| 363 MainAxisTrailingInset(right.margins()))); | |
| 364 } | |
| 365 | |
| 366 gfx::Insets BoxLayout::MainAxisOuterMargin() const { | |
| 367 if (collapse_margins_spacing_) { | |
| 368 const ViewWrapper first(this, FirstVisibleView()); | |
| 369 const ViewWrapper last(this, LastVisibleView()); | |
| 370 return MaxAxisInsets( | |
| 371 orientation_ == kHorizontal ? HORIZONTAL_AXIS : VERTICAL_AXIS, | |
| 372 inside_border_insets_, first.margins(), inside_border_insets_, | |
| 373 last.margins()); | |
| 374 } | |
| 375 return MaxAxisInsets( | |
| 376 orientation_ == kHorizontal ? HORIZONTAL_AXIS : VERTICAL_AXIS, | |
| 377 inside_border_insets_, gfx::Insets(), inside_border_insets_, | |
| 378 gfx::Insets()); | |
| 379 } | |
| 380 | |
| 381 gfx::Insets BoxLayout::CrossAxisMaxViewMargin() const { | |
| 382 int top_or_left = 0; | |
|
sky
2017/05/25 19:16:51
leading
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 383 int bottom_or_right = 0; | |
|
sky
2017/05/25 19:16:51
trailing
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 384 for (int i = 0; i < host_->child_count(); ++i) { | |
| 385 const ViewWrapper child(this, host_->child_at(i)); | |
| 386 if (!child.visible()) | |
| 387 continue; | |
| 388 top_or_left = std::max(top_or_left, CrossAxisLeadingInset(child.margins())); | |
| 389 | |
| 390 bottom_or_right = | |
| 391 std::max(bottom_or_right, CrossAxisTrailingInset(child.margins())); | |
| 392 } | |
| 393 if (orientation_ == Orientation::kVertical) | |
| 394 return gfx::Insets(0, top_or_left, 0, bottom_or_right); | |
| 395 return gfx::Insets(top_or_left, 0, bottom_or_right, 0); | |
| 396 } | |
| 397 | |
| 398 gfx::Insets BoxLayout::CrossAxisOuterMargin() const { | |
| 399 gfx::Insets max_margin = CrossAxisMaxViewMargin(); | |
| 400 bool is_vertical = orientation_ == Orientation::kVertical; | |
| 401 int top_or_left = CrossAxisLeadingInset(inside_border_insets_); | |
|
sky
2017/05/25 19:16:51
leading
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 402 int bottom_or_right = CrossAxisTrailingInset(inside_border_insets_); | |
|
sky
2017/05/25 19:16:51
trailing
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 403 if (collapse_margins_spacing_) { | |
| 404 return MaxAxisInsets(is_vertical ? HORIZONTAL_AXIS : VERTICAL_AXIS, | |
|
sky
2017/05/25 19:16:51
optional: is_vertical is *super* confusing here. L
kylix_rd
2017/05/25 20:11:19
Understandable. It's certainly a little more confu
| |
| 405 gfx::Insets(top_or_left, bottom_or_right), max_margin, | |
| 406 gfx::Insets(top_or_left, bottom_or_right), max_margin); | |
| 407 } | |
| 408 if (is_vertical) | |
| 409 return gfx::Insets(0, top_or_left + max_margin.left(), 0, | |
| 410 bottom_or_right + max_margin.right()); | |
| 411 return gfx::Insets(top_or_left + max_margin.top(), 0, | |
| 412 bottom_or_right + max_margin.bottom(), 0); | |
| 413 } | |
| 414 | |
| 415 void BoxLayout::AdjustMainAxisForMargin(gfx::Rect* rect) const { | |
| 416 rect->Inset(MainAxisOuterMargin()); | |
| 417 } | |
| 418 | |
| 419 void BoxLayout::AdjustCrossAxisForInsets(gfx::Rect* rect) const { | |
| 420 rect->Inset(orientation_ == Orientation::kVertical | |
| 421 ? gfx::Insets(0, inside_border_insets_.left(), 0, | |
| 422 inside_border_insets_.right()) | |
| 423 : gfx::Insets(inside_border_insets_.top(), 0, | |
| 424 inside_border_insets_.bottom(), 0)); | |
| 425 } | |
| 426 | |
| 427 int BoxLayout::CrossAxisSizeForView(const ViewWrapper& view) const { | |
| 259 // TODO(bruthig): For horizontal case use the available width and not the | 428 // TODO(bruthig): For horizontal case use the available width and not the |
| 260 // preferred width. See https://crbug.com/682266. | 429 // preferred width. See https://crbug.com/682266. |
| 261 return orientation_ == kVertical | 430 return orientation_ == kVertical |
| 262 ? view->GetPreferredSize().width() | 431 ? view.GetPreferredSize().width() |
| 263 : view->GetHeightForWidth(view->GetPreferredSize().width()); | 432 : view.GetHeightForWidth(view.GetPreferredSize().width()); |
| 433 } | |
| 434 | |
| 435 int BoxLayout::CrossAxisMarginSizeForView(const ViewWrapper& view) const { | |
| 436 return collapse_margins_spacing_ | |
| 437 ? 0 | |
| 438 : (orientation_ == kVertical ? view.margins().width() | |
| 439 : view.margins().height()); | |
| 440 } | |
| 441 | |
| 442 int BoxLayout::CrossAxisMarginTopLeftForView(const ViewWrapper& view) const { | |
| 443 return collapse_margins_spacing_ ? 0 : CrossAxisLeadingInset(view.margins()); | |
| 264 } | 444 } |
| 265 | 445 |
| 266 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, | 446 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, |
| 267 int child_area_width) const { | 447 int child_area_width) const { |
| 448 DCHECK_EQ(host, host_); | |
| 268 gfx::Rect child_area_bounds; | 449 gfx::Rect child_area_bounds; |
| 269 | 450 |
| 270 if (orientation_ == kHorizontal) { | 451 if (orientation_ == kHorizontal) { |
| 271 // Horizontal layouts ignore |child_area_width|, meaning they mimic the | 452 // Horizontal layouts ignore |child_area_width|, meaning they mimic the |
| 272 // default behavior of GridLayout::GetPreferredHeightForWidth(). | 453 // default behavior of GridLayout::GetPreferredHeightForWidth(). |
| 273 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266. | 454 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266. |
| 274 int position = 0; | 455 int position = 0; |
| 275 for (int i = 0; i < host->child_count(); ++i) { | 456 for (int i = 0; i < host_->child_count(); ++i) { |
| 276 const View* child = host->child_at(i); | 457 const ViewWrapper child(this, host_->child_at(i)); |
| 277 if (!child->visible()) | 458 const ViewWrapper next(this, NextVisibleView(i)); |
|
sky
2017/05/25 19:16:51
Move after visible and preferred size checks? Same
kylix_rd
2017/05/25 20:11:19
Done.
| |
| 459 if (!child.visible()) | |
| 278 continue; | 460 continue; |
| 279 | 461 |
| 280 gfx::Size size(child->GetPreferredSize()); | 462 gfx::Size size(child.GetPreferredSize()); |
| 281 if (size.IsEmpty()) | 463 if (size.IsEmpty()) |
| 282 continue; | 464 continue; |
| 283 | 465 |
| 284 gfx::Rect child_bounds(position, 0, size.width(), size.height()); | 466 gfx::Rect child_bounds(position, 0, size.width(), size.height()); |
| 285 child_area_bounds.Union(child_bounds); | 467 child_area_bounds.Union(child_bounds); |
| 286 position += size.width() + between_child_spacing_; | 468 position += size.width() + MainAxisMarginBetweenViews(child, next); |
| 287 } | 469 } |
| 288 child_area_bounds.set_height( | 470 child_area_bounds.set_height( |
| 289 std::max(child_area_bounds.height(), minimum_cross_axis_size_)); | 471 std::max(child_area_bounds.height(), minimum_cross_axis_size_)); |
| 290 } else { | 472 } else { |
| 291 int height = 0; | 473 int height = 0; |
| 292 for (int i = 0; i < host->child_count(); ++i) { | 474 for (int i = 0; i < host_->child_count(); ++i) { |
| 293 const View* child = host->child_at(i); | 475 const ViewWrapper child(this, host_->child_at(i)); |
| 294 if (!child->visible()) | 476 const ViewWrapper next(this, NextVisibleView(i)); |
| 477 if (!child.visible()) | |
| 295 continue; | 478 continue; |
| 296 | 479 |
| 297 // Use the child area width for getting the height if the child is | 480 // Use the child area width for getting the height if the child is |
| 298 // supposed to stretch. Use its preferred size otherwise. | 481 // supposed to stretch. Use its preferred size otherwise. |
| 299 int extra_height = MainAxisSizeForView(child, child_area_width); | 482 int extra_height = MainAxisSizeForView(child, child_area_width); |
| 300 // Only add |between_child_spacing_| if this is not the only child. | 483 // Only add |between_child_spacing_| if this is not the only child. |
| 301 if (height != 0 && extra_height > 0) | 484 if (next.view() && extra_height > 0) |
| 302 height += between_child_spacing_; | 485 height += MainAxisMarginBetweenViews(child, next); |
| 303 height += extra_height; | 486 height += extra_height; |
| 304 } | 487 } |
| 305 | 488 |
| 306 child_area_bounds.set_width(child_area_width); | 489 child_area_bounds.set_width(child_area_width); |
| 307 child_area_bounds.set_height(height); | 490 child_area_bounds.set_height(height); |
| 308 } | 491 } |
| 309 | 492 |
| 310 gfx::Size non_child_size = NonChildSize(host); | 493 gfx::Size non_child_size = NonChildSize(host_); |
|
sky
2017/05/25 19:16:51
Won't this result in a layout like option (3). Are
kylix_rd
2017/05/25 20:11:19
If the margins aren't collapsed, this will only be
sky
2017/05/25 22:37:27
I think I'm still confused. I left a diagram on th
| |
| 311 return gfx::Size(child_area_bounds.width() + non_child_size.width(), | 494 return gfx::Size(child_area_bounds.width() + non_child_size.width(), |
| 312 child_area_bounds.height() + non_child_size.height()); | 495 child_area_bounds.height() + non_child_size.height()); |
| 313 } | 496 } |
| 314 | 497 |
| 315 gfx::Size BoxLayout::NonChildSize(const View* host) const { | 498 gfx::Size BoxLayout::NonChildSize(const View* host) const { |
| 316 gfx::Insets insets(host->GetInsets()); | 499 gfx::Insets insets(host->GetInsets()); |
| 317 return gfx::Size(insets.width() + inside_border_insets_.width(), | 500 if (!collapse_margins_spacing_) |
| 318 insets.height() + inside_border_insets_.height()); | 501 return gfx::Size(insets.width() + inside_border_insets_.width(), |
| 502 insets.height() + inside_border_insets_.height()); | |
| 503 gfx::Insets main_axis = MainAxisOuterMargin(); | |
| 504 gfx::Insets cross_axis = CrossAxisOuterMargin(); | |
| 505 return gfx::Size(insets.width() + main_axis.width() + cross_axis.width(), | |
| 506 insets.height() + main_axis.height() + cross_axis.height()); | |
| 507 } | |
| 508 | |
| 509 View* BoxLayout::NextVisibleView(int index) const { | |
| 510 for (int i = index + 1; i < host_->child_count(); ++i) { | |
| 511 View* result = host_->child_at(i); | |
| 512 if (result->visible()) | |
| 513 return result; | |
| 514 } | |
| 515 return nullptr; | |
| 516 } | |
| 517 | |
| 518 View* BoxLayout::FirstVisibleView() const { | |
| 519 return NextVisibleView(-1); | |
| 520 } | |
| 521 | |
| 522 View* BoxLayout::LastVisibleView() const { | |
| 523 for (int i = host_->child_count() - 1; i >= 0; --i) { | |
| 524 View* result = host_->child_at(i); | |
| 525 if (result->visible()) | |
| 526 return result; | |
| 527 } | |
| 528 return nullptr; | |
| 319 } | 529 } |
| 320 | 530 |
| 321 } // namespace views | 531 } // namespace views |
| OLD | NEW |