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 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 |