| 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..59c21c52f4a8c9c89eae094a1af48d8f562fcc7b 100644
|
| --- a/ui/views/layout/box_layout.cc
|
| +++ b/ui/views/layout/box_layout.cc
|
| @@ -20,88 +20,138 @@ 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),
|
| + host_(NULL) {
|
| }
|
|
|
| BoxLayout::~BoxLayout() {
|
| }
|
|
|
| +void BoxLayout::SetFlexForView(const View* view, int flex_weight) {
|
| + DCHECK(host_);
|
| + DCHECK(view);
|
| + DCHECK_EQ(host_, view->parent());
|
| + DCHECK_GE(flex_weight, 0);
|
| + flex_map_[view] = flex_weight;
|
| +}
|
| +
|
| +void BoxLayout::ClearFlexForView(const View* view) {
|
| + DCHECK(view);
|
| + flex_map_.erase(view);
|
| +}
|
| +
|
| +void BoxLayout::SetDefaultFlex(int default_flex) {
|
| + DCHECK_GE(default_flex, 0);
|
| + default_flex_ = default_flex;
|
| +}
|
| +
|
| void BoxLayout::Layout(View* host) {
|
| + DCHECK_EQ(host_, 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 total_main_axis_size = 0;
|
| + int num_visible = 0;
|
| + int flex_sum = 0;
|
| + // Calculate the total size of children in the main axis.
|
| + 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 += GetFlexForView(child);
|
| + }
|
| +
|
| + if (!num_visible)
|
| + return;
|
|
|
| - 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);
|
| + total_main_axis_size -= between_child_spacing_;
|
| + // Free space can be negative indicating that the views want to overflow.
|
| + int 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 total_padding = 0;
|
| + int current_flex = 0;
|
| for (int i = 0; i < host->child_count(); ++i) {
|
| View* child = host->child_at(i);
|
| - if (child->visible()) {
|
| - gfx::Rect bounds(child_area);
|
| - SetMainAxisPosition(main_position, &bounds);
|
| - if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) {
|
| - int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child);
|
| - int position = CrossAxisPosition(bounds);
|
| - if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
|
| - position += free_space / 2;
|
| - } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
|
| - position += free_space;
|
| - }
|
| - SetCrossAxisPosition(position, &bounds);
|
| - SetCrossAxisSize(CrossAxisSizeForView(child), &bounds);
|
| + if (!child->visible())
|
| + continue;
|
| +
|
| + // Calculate cross axis size.
|
| + gfx::Rect bounds(child_area);
|
| + SetMainAxisPosition(main_position, &bounds);
|
| + if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) {
|
| + int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child);
|
| + int position = CrossAxisPosition(bounds);
|
| + if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
|
| + position += free_space / 2;
|
| + } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
|
| + position += free_space;
|
| }
|
| - int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
|
| - SetMainAxisSize(child_main_axis_size + padding, &bounds);
|
| - if (MainAxisSize(bounds) > 0)
|
| - main_position += MainAxisSize(bounds) + between_child_spacing_;
|
| -
|
| - // Clamp child view bounds to |child_area|.
|
| - bounds.Intersect(child_area);
|
| - child->SetBoundsRect(bounds);
|
| + SetCrossAxisPosition(position, &bounds);
|
| + SetCrossAxisSize(CrossAxisSizeForView(child), &bounds);
|
| }
|
| +
|
| + // Calculate flex padding.
|
| + int current_padding = 0;
|
| + if (GetFlexForView(child) > 0) {
|
| + current_flex += GetFlexForView(child);
|
| + int quot = (main_free_space * current_flex) / flex_sum;
|
| + int rem = (main_free_space * current_flex) % flex_sum;
|
| + current_padding = quot - total_padding;
|
| + // Use the current remainder to round to the nearest pixel.
|
| + if (std::abs(rem) * 2 >= flex_sum)
|
| + current_padding += main_free_space > 0 ? 1 : -1;
|
| + total_padding += current_padding;
|
| + }
|
| +
|
| + // Set main axis size.
|
| + int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
|
| + SetMainAxisSize(child_main_axis_size + current_padding, &bounds);
|
| + if (MainAxisSize(bounds) > 0 || GetFlexForView(child) > 0)
|
| + main_position += MainAxisSize(bounds) + between_child_spacing_;
|
| +
|
| + // Clamp child view bounds to |child_area|.
|
| + bounds.Intersect(child_area);
|
| + child->SetBoundsRect(bounds);
|
| }
|
| +
|
| + // Flex views should have grown/shrunk to consume all free space.
|
| + if (flex_sum)
|
| + DCHECK_EQ(total_padding, main_free_space);
|
| }
|
|
|
| gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
|
| + DCHECK_EQ(host_, host);
|
| // Calculate the child views' preferred width.
|
| int width = 0;
|
| if (orientation_ == kVertical) {
|
| @@ -118,10 +168,34 @@ gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
|
| }
|
|
|
| int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const {
|
| + DCHECK_EQ(host_, host);
|
| int child_width = width - NonChildSize(host).width();
|
| return GetPreferredSizeForChildWidth(host, child_width).height();
|
| }
|
|
|
| +void BoxLayout::Installed(View* host) {
|
| + DCHECK(!host_);
|
| + host_ = host;
|
| +}
|
| +
|
| +void BoxLayout::Uninstalled(View* host) {
|
| + DCHECK_EQ(host_, host);
|
| + host_ = NULL;
|
| + flex_map_.clear();
|
| +}
|
| +
|
| +void BoxLayout::ViewRemoved(View* host, View* view) {
|
| + ClearFlexForView(view);
|
| +}
|
| +
|
| +int BoxLayout::GetFlexForView(const View* view) const {
|
| + std::map<const View*, int>::const_iterator it = flex_map_.find(view);
|
| + 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();
|
| }
|
|
|