Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(314)

Unified Diff: ui/views/layout/align_layout.cc

Issue 2230913003: Experimental alignment layout manager using a property on the views Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Renamed AlignAttribute and associated types to FillAttribute Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/views/layout/align_layout.h ('k') | ui/views/layout/align_layout_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « ui/views/layout/align_layout.h ('k') | ui/views/layout/align_layout_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698