Chromium Code Reviews| Index: ui/views/layout/box_layout.cc |
| diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc |
| index 91504ad3c3879050b0f0d400260ef2f5bf85f955..b7532c7725ab4989f63078dfd3692fe67ccdf119 100644 |
| --- a/ui/views/layout/box_layout.cc |
| +++ b/ui/views/layout/box_layout.cc |
| @@ -20,59 +20,79 @@ BoxLayout::BoxLayout(BoxLayout::Orientation orientation, |
| inside_border_horizontal_spacing), |
| between_child_spacing_(between_child_spacing), |
| main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START), |
| - cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH) { |
| + cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH), |
| + default_flex_(0) { |
| } |
| BoxLayout::~BoxLayout() { |
| } |
| +void BoxLayout::SetFlexForViewAt(int index, int flex_weight) { |
| + DCHECK(index >= 0); |
| + DCHECK(flex_weight >= 0); |
| + flex_map_[index] = flex_weight; |
| +} |
| + |
| +void BoxLayout::ClearFlexForViewAt(int index) { |
| + DCHECK(index >= 0); |
| + flex_map_.erase(index); |
| +} |
| + |
| +void BoxLayout::SetDefaultFlex(int default_flex) { |
| + DCHECK(default_flex >= 0); |
| + default_flex_ = default_flex; |
| +} |
| + |
| void BoxLayout::Layout(View* host) { |
| gfx::Rect child_area(host->GetLocalBounds()); |
| child_area.Inset(host->GetInsets()); |
| child_area.Inset(inside_border_insets_); |
| - int padding = 0; |
| - if (main_axis_alignment_ != MAIN_AXIS_ALIGNMENT_START) { |
| - int total_main_axis_size = 0; |
| - int num_visible = 0; |
| - for (int i = 0; i < host->child_count(); ++i) { |
| - View* child = host->child_at(i); |
| - if (!child->visible()) |
| - continue; |
| - total_main_axis_size += MainAxisSizeForView(child, child_area.width()) + |
| - between_child_spacing_; |
| - ++num_visible; |
| - } |
| + int main_free_space = 0; |
|
benwells
2014/07/03 07:29:59
Nit: move this to just before it is used (line 65
calamity
2014/07/03 08:31:24
Done.
|
| + int total_main_axis_size = 0; |
| + int num_visible = 0; |
| + int flex_sum = 0; |
| + for (int i = 0; i < host->child_count(); ++i) { |
| + View* child = host->child_at(i); |
| + if (!child->visible()) |
| + continue; |
| + total_main_axis_size += |
| + MainAxisSizeForView(child, child_area.width()) + between_child_spacing_; |
| + ++num_visible; |
| + flex_sum += GetFlexForViewAt(i); |
| + } |
| - if (num_visible) { |
| - total_main_axis_size -= between_child_spacing_; |
| - int free_space = MainAxisSize(child_area) - total_main_axis_size; |
| - int position = MainAxisPosition(child_area); |
| - int size = MainAxisSize(child_area); |
| + if (num_visible) { |
|
benwells
2014/07/03 07:29:59
Can you return here if !num_visible?
calamity
2014/07/03 08:31:24
Done.
|
| + total_main_axis_size -= between_child_spacing_; |
| + // Free space can be negative indicating that the views want to overflow. |
| + main_free_space = MainAxisSize(child_area) - total_main_axis_size; |
| + int position = MainAxisPosition(child_area); |
| + int size = MainAxisSize(child_area); |
| + if (!flex_sum) { |
| switch (main_axis_alignment_) { |
| - case MAIN_AXIS_ALIGNMENT_FILL: |
| - padding = std::max(free_space / num_visible, 0); |
| + case MAIN_AXIS_ALIGNMENT_START: |
| break; |
| case MAIN_AXIS_ALIGNMENT_CENTER: |
| - position += free_space / 2; |
| + position += main_free_space / 2; |
| size = total_main_axis_size; |
| break; |
| case MAIN_AXIS_ALIGNMENT_END: |
| - position += free_space; |
| + position += main_free_space; |
| size = total_main_axis_size; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| - gfx::Rect new_child_area(child_area); |
| - SetMainAxisPosition(position, &new_child_area); |
| - SetMainAxisSize(size, &new_child_area); |
| - child_area.Intersect(new_child_area); |
| } |
| + gfx::Rect new_child_area(child_area); |
| + SetMainAxisPosition(position, &new_child_area); |
| + SetMainAxisSize(size, &new_child_area); |
| + child_area.Intersect(new_child_area); |
| } |
| int main_position = MainAxisPosition(child_area); |
| + int current_remainder = 0; |
| for (int i = 0; i < host->child_count(); ++i) { |
| View* child = host->child_at(i); |
| if (child->visible()) { |
| @@ -89,9 +109,20 @@ void BoxLayout::Layout(View* host) { |
| SetCrossAxisPosition(position, &bounds); |
| SetCrossAxisSize(CrossAxisSizeForView(child), &bounds); |
| } |
| + |
| + int current_padding = 0; |
| + if (GetFlexForViewAt(i) > 0) { |
| + current_padding = main_free_space * GetFlexForViewAt(i) / flex_sum; |
| + current_remainder += main_free_space * GetFlexForViewAt(i); |
| + current_remainder %= flex_sum; |
| + // Use the current remainder to round to the nearest pixel. |
| + if (std::abs(current_remainder) * 2 >= flex_sum) |
|
benwells
2014/07/03 07:29:59
It feels magical that this works and doesn't ever
|
| + current_padding += main_free_space > 0 ? 1 : -1; |
| + } |
| + |
| int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); |
| - SetMainAxisSize(child_main_axis_size + padding, &bounds); |
| - if (MainAxisSize(bounds) > 0) |
| + SetMainAxisSize(child_main_axis_size + current_padding, &bounds); |
| + if (MainAxisSize(bounds) > 0 || GetFlexForViewAt(i) > 0) |
| main_position += MainAxisSize(bounds) + between_child_spacing_; |
| // Clamp child view bounds to |child_area|. |
| @@ -99,6 +130,7 @@ void BoxLayout::Layout(View* host) { |
| child->SetBoundsRect(bounds); |
| } |
| } |
| + DCHECK_EQ(0, current_remainder); |
| } |
| gfx::Size BoxLayout::GetPreferredSize(const View* host) const { |
| @@ -122,6 +154,14 @@ int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const { |
| return GetPreferredSizeForChildWidth(host, child_width).height(); |
| } |
| +int BoxLayout::GetFlexForViewAt(int index) { |
| + std::map<int, int>::const_iterator it = flex_map_.find(index); |
| + if (it == flex_map_.end()) |
| + return default_flex_; |
| + |
| + return it->second; |
| +} |
| + |
| int BoxLayout::MainAxisSize(const gfx::Rect& rect) const { |
| return orientation_ == kHorizontal ? rect.width() : rect.height(); |
| } |