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