| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/layout/box_layout.h" |
| |
| #include "ui/gfx/rect.h" |
| #include "ui/views/view.h" |
| |
| namespace views { |
| |
| BoxLayout::BoxLayout(BoxLayout::Orientation orientation, |
| int inside_border_horizontal_spacing, |
| int inside_border_vertical_spacing, |
| int between_child_spacing) |
| : orientation_(orientation), |
| inside_border_insets_(inside_border_vertical_spacing, |
| inside_border_horizontal_spacing, |
| inside_border_vertical_spacing, |
| inside_border_horizontal_spacing), |
| between_child_spacing_(between_child_spacing), |
| spread_blank_space_(false) { |
| } |
| |
| BoxLayout::~BoxLayout() { |
| } |
| |
| void BoxLayout::Layout(View* host) { |
| gfx::Rect child_area(host->GetLocalBounds()); |
| child_area.Inset(host->GetInsets()); |
| child_area.Inset(inside_border_insets_); |
| int x = child_area.x(); |
| int y = child_area.y(); |
| |
| int padding = 0; |
| if (spread_blank_space_) { |
| int total = 0; |
| int visible = 0; |
| for (int i = 0; i < host->child_count(); ++i) { |
| View* child = host->child_at(i); |
| if (!child->visible()) |
| continue; |
| if (orientation_ == kHorizontal) { |
| total += child->GetPreferredSize().width() + between_child_spacing_; |
| } else { |
| total += child->GetHeightForWidth(child_area.width()) + |
| between_child_spacing_; |
| } |
| ++visible; |
| } |
| |
| if (visible) { |
| total -= between_child_spacing_; |
| if (orientation_ == kHorizontal) |
| padding = (child_area.width() - total) / visible; |
| else |
| padding = (child_area.height() - total) / visible; |
| |
| if (padding < 0) |
| padding = 0; |
| } |
| } |
| |
| for (int i = 0; i < host->child_count(); ++i) { |
| View* child = host->child_at(i); |
| if (child->visible()) { |
| gfx::Rect bounds(x, y, child_area.width(), child_area.height()); |
| if (orientation_ == kHorizontal) { |
| bounds.set_width(child->GetPreferredSize().width() + padding); |
| if (bounds.width() > 0) |
| x += bounds.width() + between_child_spacing_; |
| } else { |
| bounds.set_height(child->GetHeightForWidth(bounds.width()) + padding); |
| if (bounds.height() > 0) |
| y += bounds.height() + between_child_spacing_; |
| } |
| // Clamp child view bounds to |child_area|. |
| bounds.Intersect(child_area); |
| child->SetBoundsRect(bounds); |
| } |
| } |
| } |
| |
| gfx::Size BoxLayout::GetPreferredSize(View* host) { |
| // Calculate the child views' preferred width. |
| int width = 0; |
| if (orientation_ == kVertical) { |
| for (int i = 0; i < host->child_count(); ++i) { |
| View* child = host->child_at(i); |
| if (!child->visible()) |
| continue; |
| |
| width = std::max(width, child->GetPreferredSize().width()); |
| } |
| } |
| |
| return GetPreferredSizeForChildWidth(host, width); |
| } |
| |
| int BoxLayout::GetPreferredHeightForWidth(View* host, int width) { |
| int child_width = width - NonChildSize(host).width(); |
| return GetPreferredSizeForChildWidth(host, child_width).height(); |
| } |
| |
| gfx::Size BoxLayout::GetPreferredSizeForChildWidth(View* host, |
| int child_area_width) { |
| gfx::Rect child_area_bounds; |
| |
| if (orientation_ == kHorizontal) { |
| // Horizontal layouts ignore |child_area_width|, meaning they mimic the |
| // default behavior of GridLayout::GetPreferredHeightForWidth(). |
| // TODO(estade): fix this if it ever becomes a problem. |
| int position = 0; |
| for (int i = 0; i < host->child_count(); ++i) { |
| View* child = host->child_at(i); |
| if (!child->visible()) |
| continue; |
| |
| gfx::Size size(child->GetPreferredSize()); |
| if (size.IsEmpty()) |
| continue; |
| |
| gfx::Rect child_bounds(position, 0, size.width(), size.height()); |
| child_area_bounds.Union(child_bounds); |
| position += size.width() + between_child_spacing_; |
| } |
| } else { |
| int height = 0; |
| for (int i = 0; i < host->child_count(); ++i) { |
| View* child = host->child_at(i); |
| if (!child->visible()) |
| continue; |
| |
| int extra_height = child->GetHeightForWidth(child_area_width); |
| // Only add |between_child_spacing_| if this is not the only child. |
| if (height != 0 && extra_height > 0) |
| height += between_child_spacing_; |
| height += extra_height; |
| } |
| |
| child_area_bounds.set_width(child_area_width); |
| child_area_bounds.set_height(height); |
| } |
| |
| gfx::Size non_child_size = NonChildSize(host); |
| return gfx::Size(child_area_bounds.width() + non_child_size.width(), |
| child_area_bounds.height() + non_child_size.height()); |
| } |
| |
| gfx::Size BoxLayout::NonChildSize(View* host) { |
| gfx::Insets insets(host->GetInsets()); |
| return gfx::Size(insets.width() + inside_border_insets_.width(), |
| insets.height() + inside_border_insets_.height()); |
| } |
| |
| } // namespace views |