OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ui/views/layout/align_layout.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "ui/views/anchor_attribute.h" |
| 9 |
| 10 namespace views { |
| 11 |
| 12 // This special value represents the absence of the align attribute. |
| 13 static constexpr Fill Fill_None = |
| 14 static_cast<Fill>(static_cast<int>(Fill::Content) + 1); |
| 15 |
| 16 AlignLayout::AlignLayout() {} |
| 17 |
| 18 AlignLayout::~AlignLayout() {} |
| 19 |
| 20 void AlignLayout::AlignViews(View* host, |
| 21 views::Fill fill, |
| 22 gfx::Rect& contents) { |
| 23 View::Views fill_list; |
| 24 for (int i = 0; i < host->child_count(); ++i) { |
| 25 FillAttribute* fill_attr; |
| 26 View* child = host->child_at(i); |
| 27 if (child->visible() && child->attributes().Find(fill_attr) |
| 28 ? fill_attr->fill() == fill |
| 29 : fill == Fill_None) { |
| 30 View::Views::iterator j = fill_list.begin(); |
| 31 while (j < fill_list.end() && !ShouldInsert(child, *j, fill)) |
| 32 j++; |
| 33 fill_list.insert(j, child); |
| 34 } |
| 35 } |
| 36 for (View* child : fill_list) |
| 37 PlaceView(child, fill, contents); |
| 38 } |
| 39 |
| 40 void AlignLayout::Layout(View* host) { |
| 41 static const Fill fillstyles[] = { |
| 42 views::Fill::Top, views::Fill::Bottom, views::Fill::Left, |
| 43 views::Fill::Right, views::Fill::Content, Fill_None}; |
| 44 if (ShouldAlign(host)) { |
| 45 gfx::Rect contents = host->GetContentsBounds(); |
| 46 for (std::size_t i = 0; i < sizeof(fillstyles) / sizeof(fillstyles[0]); i++) |
| 47 AlignViews(host, fillstyles[i], contents); |
| 48 } |
| 49 } |
| 50 |
| 51 gfx::Size AlignLayout::GetPreferredSize(const View* host) const { |
| 52 return gfx::Size(); |
| 53 } |
| 54 |
| 55 int AlignLayout::GetPreferredHeightForWidth(const View* host, int width) const { |
| 56 return 0; |
| 57 } |
| 58 |
| 59 static int MulDiv(int Number, int Numerator, int Denominator) { |
| 60 return static_cast<int>((static_cast<int64_t>(Number) * Numerator) / |
| 61 Denominator); |
| 62 } |
| 63 |
| 64 void AlignLayout::PlaceView(View* view, |
| 65 views::Fill fill, |
| 66 gfx::Rect& contents) { |
| 67 AnchorAttribute* anchor = nullptr; |
| 68 AnchorContent local_content; |
| 69 AnchorContent& content = |
| 70 view->attributes().Find(anchor) ? anchor->GetContent() : local_content; |
| 71 if (fill == Fill_None || |
| 72 content.anchors() != AnchorContent::AnchorFill(fill)) { |
| 73 if (!content.LastParentSize().IsEmpty()) { |
| 74 int new_left = view->x(); |
| 75 int new_top = view->y(); |
| 76 int new_width = view->width(); |
| 77 int new_height = view->height(); |
| 78 Anchors anchors = content.anchors(); |
| 79 gfx::Size parent_size = view->parent()->GetContentsBounds().size(); |
| 80 if (anchors.Contains(Anchor::Right)) |
| 81 if (anchors.Contains(Anchor::Left)) |
| 82 new_width = parent_size.width() - (content.LastParentSize().width() - |
| 83 content.anchorBasis().x()); |
| 84 else |
| 85 new_left = parent_size.width() - (content.LastParentSize().width() - |
| 86 content.anchorBasis().x()); |
| 87 else if (!anchors.Contains(Anchor::Left)) |
| 88 new_left = MulDiv(content.anchorBasis().x(), parent_size.width(), |
| 89 content.LastParentSize().width()) - |
| 90 new_width / 2; |
| 91 if (anchors.Contains(Anchor::Bottom)) |
| 92 if (anchors.Contains(Anchor::Top)) |
| 93 new_height = |
| 94 parent_size.height() - |
| 95 (content.LastParentSize().height() - content.anchorBasis().y()); |
| 96 else |
| 97 new_top = parent_size.height() - (content.LastParentSize().height() - |
| 98 content.anchorBasis().y()); |
| 99 else if (!anchors.Contains(Anchor::Top)) |
| 100 new_top = MulDiv(content.anchorBasis().y(), parent_size.height(), |
| 101 content.LastParentSize().height()) - |
| 102 new_height / 2; |
| 103 view->SetBounds(new_left, new_top, new_width, new_height); |
| 104 } |
| 105 if (fill == Fill_None) |
| 106 return; |
| 107 } |
| 108 int new_width = contents.size().width(); |
| 109 if (new_width < 0 || fill == views::Fill::Left || |
| 110 fill == views::Fill::Right) |
| 111 new_width = view->width(); |
| 112 int new_height = contents.size().height(); |
| 113 if (new_height < 0 || fill == views::Fill::Top || |
| 114 fill == views::Fill::Bottom) |
| 115 new_height = view->height(); |
| 116 int new_left = contents.x(); |
| 117 int new_top = contents.y(); |
| 118 switch (fill) { |
| 119 case views::Fill::Top: { |
| 120 contents.Inset(0, new_height, 0, 0); |
| 121 break; |
| 122 } |
| 123 case views::Fill::Bottom: { |
| 124 contents.Inset(0, 0, 0, new_height); |
| 125 new_top = contents.bottom(); |
| 126 break; |
| 127 } |
| 128 case views::Fill::Left: { |
| 129 contents.Inset(new_width, 0, 0, 0); |
| 130 break; |
| 131 } |
| 132 case views::Fill::Right: { |
| 133 contents.Inset(0, 0, new_width, 0); |
| 134 new_left = contents.right(); |
| 135 // Fall through |
| 136 } |
| 137 default: |
| 138 break; |
| 139 } |
| 140 view->SetBounds(new_left, new_top, new_width, new_height); |
| 141 // If the view's bounds are constrained in some other manner, this |
| 142 // will ensure the content rect is adjusted based on the actual |
| 143 // size of the view. |
| 144 if (view->width() != new_width || view->height() != new_height) { |
| 145 switch (fill) { |
| 146 case views::Fill::Top: { |
| 147 contents.set_y(contents.y() - (new_height - view->height())); |
| 148 break; |
| 149 } |
| 150 case views::Fill::Bottom: { |
| 151 contents.set_height(contents.height() + (new_height - view->height())); |
| 152 break; |
| 153 } |
| 154 case views::Fill::Left: { |
| 155 contents.set_x(contents.x() - (new_width - view->width())); |
| 156 break; |
| 157 } |
| 158 case views::Fill::Right: { |
| 159 contents.set_width(contents.width() + (new_width - view->width())); |
| 160 break; |
| 161 } |
| 162 case views::Fill::Content: { |
| 163 contents.set_width(contents.width() + (new_width - view->width())); |
| 164 contents.set_height(contents.height() + (new_height - view->width())); |
| 165 } |
| 166 } |
| 167 } |
| 168 } |
| 169 |
| 170 bool AlignLayout::ShouldAlign(View* host) { |
| 171 for (int i = 0; i < host->child_count(); ++i) { |
| 172 FillAttribute* fill_attr; |
| 173 AnchorAttribute* anchor_attr; |
| 174 View* view = host->child_at(i); |
| 175 if (view->visible() && (view->attributes().Find(fill_attr) || |
| 176 view->attributes().Find(anchor_attr))) |
| 177 return true; |
| 178 } |
| 179 return false; |
| 180 } |
| 181 |
| 182 bool AlignLayout::ShouldInsert(View* child1, View* child2, views::Fill fill) { |
| 183 switch (fill) { |
| 184 case views::Fill::Top: |
| 185 return child1->y() < child2->y(); |
| 186 case views::Fill::Bottom: |
| 187 return child1->bounds().bottom() >= child2->bounds().bottom(); |
| 188 case views::Fill::Left: |
| 189 return child1->x() < child2->x(); |
| 190 case views::Fill::Right: |
| 191 return child1->bounds().right() >= child2->bounds().right(); |
| 192 default: |
| 193 return false; |
| 194 } |
| 195 } |
| 196 |
| 197 } // namespace views |
OLD | NEW |