1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
ash / bubble / simple_grid_layout.cc [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/bubble/simple_grid_layout.h"
#include "ui/views/view.h"
namespace ash {
SimpleGridLayout::SimpleGridLayout(int column_count,
std::optional<int> column_spacing,
std::optional<int> row_spacing)
: column_count_(column_count),
column_spacing_(column_spacing),
row_spacing_(row_spacing) {}
SimpleGridLayout::~SimpleGridLayout() = default;
views::ProposedLayout SimpleGridLayout::CalculateProposedLayout(
const views::SizeBounds& size_bounds) const {
views::ProposedLayout proposed_layout;
auto calculate_spacing = [](const views::SizeBound& bound, int child_size,
int child_count) {
if (!bound.is_bounded()) {
return 0;
}
return std::max(
0, (bound.value() - child_size * child_count) / (child_count - 1));
};
const gfx::Size child_size = GetChildPreferredSize();
const int column_spacing = column_spacing_.value_or(calculate_spacing(
size_bounds.width(), child_size.width(), column_count_));
const int row_spacing = row_spacing_.value_or(0);
proposed_layout.host_size =
CalculatePreferredSize(column_spacing, row_spacing);
int row = 0;
int col = 0;
for (views::View* child : host_view()->children()) {
if (!IsChildIncludedInLayout(child))
continue;
int x = col * (column_spacing + child_size.width());
int y = row * (row_spacing + child_size.height());
proposed_layout.child_layouts.push_back(views::ChildLayout{
child,
child->GetVisible(),
gfx::Rect(x, y, child_size.width(), child_size.height()),
{child_size.width(), child_size.height()}});
++col;
if (col % column_count_ == 0) {
++row;
col = 0;
}
}
return proposed_layout;
}
void SimpleGridLayout::OnLayoutChanged() {
cached_child_preferred_size_.reset();
LayoutManagerBase::OnLayoutChanged();
}
gfx::Size SimpleGridLayout::GetPreferredSize(
const views::View* host,
const views::SizeBounds& available_bounds) const {
// If column spacing is forced, the preferred layout size does not depend on
// the `available_bounds`. Using `GetPreferredSize(const view::View*)` will
// avoid some calculation, as the base class caches preferred size calculation
// results.
if (column_spacing_) {
return views::LayoutManagerBase::GetPreferredSize(host);
}
return views::LayoutManagerBase::GetPreferredSize(host, available_bounds);
}
gfx::Size SimpleGridLayout::GetChildPreferredSize() const {
if (cached_child_preferred_size_)
return *cached_child_preferred_size_;
if (!host_view()->children().size())
return gfx::Size();
for (views::View* child : host_view()->children()) {
if (IsChildIncludedInLayout(child)) {
cached_child_preferred_size_ = child->GetPreferredSize();
return *cached_child_preferred_size_;
}
}
return gfx::Size();
}
gfx::Size SimpleGridLayout::CalculatePreferredSize(int column_spacing,
int row_spacing) const {
int total_children = 0;
for (views::View* child : host_view()->children()) {
if (IsChildIncludedInLayout(child))
++total_children;
}
// Equivalent to `ceil(children().size() / column_count_)`.
const int number_of_rows =
(total_children + column_count_ - 1) / column_count_;
if (!number_of_rows)
return gfx::Size();
// `SimpleGridLayout` assumes all children have identical sizes.
const int child_height = GetChildPreferredSize().height();
const int child_width = GetChildPreferredSize().width();
const int height =
(number_of_rows * (row_spacing + child_height)) - row_spacing;
const int width =
(column_count_ * (child_width + column_spacing)) - column_spacing;
return gfx::Size(width, height);
}
} // namespace ash