| Index: ui/views/layout/align_layout.cc
|
| diff --git a/ui/views/layout/align_layout.cc b/ui/views/layout/align_layout.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..917207f2d4f69f5f30fe64ca5358e2f322519f4e
|
| --- /dev/null
|
| +++ b/ui/views/layout/align_layout.cc
|
| @@ -0,0 +1,197 @@
|
| +// Copyright (c) 2011 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/align_layout.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "ui/views/anchor_attribute.h"
|
| +
|
| +namespace views {
|
| +
|
| +// This special value represents the absence of the align attribute.
|
| +static constexpr Fill Fill_None =
|
| + static_cast<Fill>(static_cast<int>(Fill::Content) + 1);
|
| +
|
| +AlignLayout::AlignLayout() {}
|
| +
|
| +AlignLayout::~AlignLayout() {}
|
| +
|
| +void AlignLayout::AlignViews(View* host,
|
| + views::Fill fill,
|
| + gfx::Rect& contents) {
|
| + View::Views fill_list;
|
| + for (int i = 0; i < host->child_count(); ++i) {
|
| + FillAttribute* fill_attr;
|
| + View* child = host->child_at(i);
|
| + if (child->visible() && child->attributes().Find(fill_attr)
|
| + ? fill_attr->fill() == fill
|
| + : fill == Fill_None) {
|
| + View::Views::iterator j = fill_list.begin();
|
| + while (j < fill_list.end() && !ShouldInsert(child, *j, fill))
|
| + j++;
|
| + fill_list.insert(j, child);
|
| + }
|
| + }
|
| + for (View* child : fill_list)
|
| + PlaceView(child, fill, contents);
|
| +}
|
| +
|
| +void AlignLayout::Layout(View* host) {
|
| + static const Fill fillstyles[] = {
|
| + views::Fill::Top, views::Fill::Bottom, views::Fill::Left,
|
| + views::Fill::Right, views::Fill::Content, Fill_None};
|
| + if (ShouldAlign(host)) {
|
| + gfx::Rect contents = host->GetContentsBounds();
|
| + for (std::size_t i = 0; i < sizeof(fillstyles) / sizeof(fillstyles[0]); i++)
|
| + AlignViews(host, fillstyles[i], contents);
|
| + }
|
| +}
|
| +
|
| +gfx::Size AlignLayout::GetPreferredSize(const View* host) const {
|
| + return gfx::Size();
|
| +}
|
| +
|
| +int AlignLayout::GetPreferredHeightForWidth(const View* host, int width) const {
|
| + return 0;
|
| +}
|
| +
|
| +static int MulDiv(int Number, int Numerator, int Denominator) {
|
| + return static_cast<int>((static_cast<int64_t>(Number) * Numerator) /
|
| + Denominator);
|
| +}
|
| +
|
| +void AlignLayout::PlaceView(View* view,
|
| + views::Fill fill,
|
| + gfx::Rect& contents) {
|
| + AnchorAttribute* anchor = nullptr;
|
| + AnchorContent local_content;
|
| + AnchorContent& content =
|
| + view->attributes().Find(anchor) ? anchor->GetContent() : local_content;
|
| + if (fill == Fill_None ||
|
| + content.anchors() != AnchorContent::AnchorFill(fill)) {
|
| + if (!content.LastParentSize().IsEmpty()) {
|
| + int new_left = view->x();
|
| + int new_top = view->y();
|
| + int new_width = view->width();
|
| + int new_height = view->height();
|
| + Anchors anchors = content.anchors();
|
| + gfx::Size parent_size = view->parent()->GetContentsBounds().size();
|
| + if (anchors.Contains(Anchor::Right))
|
| + if (anchors.Contains(Anchor::Left))
|
| + new_width = parent_size.width() - (content.LastParentSize().width() -
|
| + content.anchorBasis().x());
|
| + else
|
| + new_left = parent_size.width() - (content.LastParentSize().width() -
|
| + content.anchorBasis().x());
|
| + else if (!anchors.Contains(Anchor::Left))
|
| + new_left = MulDiv(content.anchorBasis().x(), parent_size.width(),
|
| + content.LastParentSize().width()) -
|
| + new_width / 2;
|
| + if (anchors.Contains(Anchor::Bottom))
|
| + if (anchors.Contains(Anchor::Top))
|
| + new_height =
|
| + parent_size.height() -
|
| + (content.LastParentSize().height() - content.anchorBasis().y());
|
| + else
|
| + new_top = parent_size.height() - (content.LastParentSize().height() -
|
| + content.anchorBasis().y());
|
| + else if (!anchors.Contains(Anchor::Top))
|
| + new_top = MulDiv(content.anchorBasis().y(), parent_size.height(),
|
| + content.LastParentSize().height()) -
|
| + new_height / 2;
|
| + view->SetBounds(new_left, new_top, new_width, new_height);
|
| + }
|
| + if (fill == Fill_None)
|
| + return;
|
| + }
|
| + int new_width = contents.size().width();
|
| + if (new_width < 0 || fill == views::Fill::Left ||
|
| + fill == views::Fill::Right)
|
| + new_width = view->width();
|
| + int new_height = contents.size().height();
|
| + if (new_height < 0 || fill == views::Fill::Top ||
|
| + fill == views::Fill::Bottom)
|
| + new_height = view->height();
|
| + int new_left = contents.x();
|
| + int new_top = contents.y();
|
| + switch (fill) {
|
| + case views::Fill::Top: {
|
| + contents.Inset(0, new_height, 0, 0);
|
| + break;
|
| + }
|
| + case views::Fill::Bottom: {
|
| + contents.Inset(0, 0, 0, new_height);
|
| + new_top = contents.bottom();
|
| + break;
|
| + }
|
| + case views::Fill::Left: {
|
| + contents.Inset(new_width, 0, 0, 0);
|
| + break;
|
| + }
|
| + case views::Fill::Right: {
|
| + contents.Inset(0, 0, new_width, 0);
|
| + new_left = contents.right();
|
| + // Fall through
|
| + }
|
| + default:
|
| + break;
|
| + }
|
| + view->SetBounds(new_left, new_top, new_width, new_height);
|
| + // If the view's bounds are constrained in some other manner, this
|
| + // will ensure the content rect is adjusted based on the actual
|
| + // size of the view.
|
| + if (view->width() != new_width || view->height() != new_height) {
|
| + switch (fill) {
|
| + case views::Fill::Top: {
|
| + contents.set_y(contents.y() - (new_height - view->height()));
|
| + break;
|
| + }
|
| + case views::Fill::Bottom: {
|
| + contents.set_height(contents.height() + (new_height - view->height()));
|
| + break;
|
| + }
|
| + case views::Fill::Left: {
|
| + contents.set_x(contents.x() - (new_width - view->width()));
|
| + break;
|
| + }
|
| + case views::Fill::Right: {
|
| + contents.set_width(contents.width() + (new_width - view->width()));
|
| + break;
|
| + }
|
| + case views::Fill::Content: {
|
| + contents.set_width(contents.width() + (new_width - view->width()));
|
| + contents.set_height(contents.height() + (new_height - view->width()));
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +bool AlignLayout::ShouldAlign(View* host) {
|
| + for (int i = 0; i < host->child_count(); ++i) {
|
| + FillAttribute* fill_attr;
|
| + AnchorAttribute* anchor_attr;
|
| + View* view = host->child_at(i);
|
| + if (view->visible() && (view->attributes().Find(fill_attr) ||
|
| + view->attributes().Find(anchor_attr)))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool AlignLayout::ShouldInsert(View* child1, View* child2, views::Fill fill) {
|
| + switch (fill) {
|
| + case views::Fill::Top:
|
| + return child1->y() < child2->y();
|
| + case views::Fill::Bottom:
|
| + return child1->bounds().bottom() >= child2->bounds().bottom();
|
| + case views::Fill::Left:
|
| + return child1->x() < child2->x();
|
| + case views::Fill::Right:
|
| + return child1->bounds().right() >= child2->bounds().right();
|
| + default:
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +} // namespace views
|
|
|