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

Side by Side Diff: ui/views/layout/box_layout.cc

Issue 360213002: Add Flex to views::BoxLayout. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 5 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/layout/box_layout.h ('k') | ui/views/layout/box_layout_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/layout/box_layout.h" 5 #include "ui/views/layout/box_layout.h"
6 6
7 #include "ui/gfx/rect.h" 7 #include "ui/gfx/rect.h"
8 #include "ui/views/view.h" 8 #include "ui/views/view.h"
9 9
10 namespace views { 10 namespace views {
11 11
12 BoxLayout::BoxLayout(BoxLayout::Orientation orientation, 12 BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
13 int inside_border_horizontal_spacing, 13 int inside_border_horizontal_spacing,
14 int inside_border_vertical_spacing, 14 int inside_border_vertical_spacing,
15 int between_child_spacing) 15 int between_child_spacing)
16 : orientation_(orientation), 16 : orientation_(orientation),
17 inside_border_insets_(inside_border_vertical_spacing, 17 inside_border_insets_(inside_border_vertical_spacing,
18 inside_border_horizontal_spacing, 18 inside_border_horizontal_spacing,
19 inside_border_vertical_spacing, 19 inside_border_vertical_spacing,
20 inside_border_horizontal_spacing), 20 inside_border_horizontal_spacing),
21 between_child_spacing_(between_child_spacing), 21 between_child_spacing_(between_child_spacing),
22 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START), 22 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START),
23 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH) { 23 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH),
24 default_flex_(0),
25 host_(NULL) {
24 } 26 }
25 27
26 BoxLayout::~BoxLayout() { 28 BoxLayout::~BoxLayout() {
27 } 29 }
28 30
31 void BoxLayout::SetFlexForView(const View* view, int flex_weight) {
32 DCHECK(host_);
33 DCHECK(view);
34 DCHECK_EQ(host_, view->parent());
35 DCHECK_GE(flex_weight, 0);
36 flex_map_[view] = flex_weight;
37 }
38
39 void BoxLayout::ClearFlexForView(const View* view) {
40 DCHECK(view);
41 flex_map_.erase(view);
42 }
43
44 void BoxLayout::SetDefaultFlex(int default_flex) {
45 DCHECK_GE(default_flex, 0);
46 default_flex_ = default_flex;
47 }
48
29 void BoxLayout::Layout(View* host) { 49 void BoxLayout::Layout(View* host) {
50 DCHECK_EQ(host_, host);
30 gfx::Rect child_area(host->GetLocalBounds()); 51 gfx::Rect child_area(host->GetLocalBounds());
31 child_area.Inset(host->GetInsets()); 52 child_area.Inset(host->GetInsets());
32 child_area.Inset(inside_border_insets_); 53 child_area.Inset(inside_border_insets_);
33 54
34 int padding = 0; 55 int total_main_axis_size = 0;
35 if (main_axis_alignment_ != MAIN_AXIS_ALIGNMENT_START) { 56 int num_visible = 0;
36 int total_main_axis_size = 0; 57 int flex_sum = 0;
37 int num_visible = 0; 58 // Calculate the total size of children in the main axis.
38 for (int i = 0; i < host->child_count(); ++i) { 59 for (int i = 0; i < host->child_count(); ++i) {
39 View* child = host->child_at(i); 60 View* child = host->child_at(i);
40 if (!child->visible()) 61 if (!child->visible())
41 continue; 62 continue;
42 total_main_axis_size += MainAxisSizeForView(child, child_area.width()) + 63 total_main_axis_size +=
43 between_child_spacing_; 64 MainAxisSizeForView(child, child_area.width()) + between_child_spacing_;
44 ++num_visible; 65 ++num_visible;
45 } 66 flex_sum += GetFlexForView(child);
67 }
46 68
47 if (num_visible) { 69 if (!num_visible)
48 total_main_axis_size -= between_child_spacing_; 70 return;
49 int free_space = MainAxisSize(child_area) - total_main_axis_size; 71
50 int position = MainAxisPosition(child_area); 72 total_main_axis_size -= between_child_spacing_;
51 int size = MainAxisSize(child_area); 73 // Free space can be negative indicating that the views want to overflow.
74 int main_free_space = MainAxisSize(child_area) - total_main_axis_size;
75 {
76 int position = MainAxisPosition(child_area);
77 int size = MainAxisSize(child_area);
78 if (!flex_sum) {
52 switch (main_axis_alignment_) { 79 switch (main_axis_alignment_) {
53 case MAIN_AXIS_ALIGNMENT_FILL: 80 case MAIN_AXIS_ALIGNMENT_START:
54 padding = std::max(free_space / num_visible, 0);
55 break; 81 break;
56 case MAIN_AXIS_ALIGNMENT_CENTER: 82 case MAIN_AXIS_ALIGNMENT_CENTER:
57 position += free_space / 2; 83 position += main_free_space / 2;
58 size = total_main_axis_size; 84 size = total_main_axis_size;
59 break; 85 break;
60 case MAIN_AXIS_ALIGNMENT_END: 86 case MAIN_AXIS_ALIGNMENT_END:
61 position += free_space; 87 position += main_free_space;
62 size = total_main_axis_size; 88 size = total_main_axis_size;
63 break; 89 break;
64 default: 90 default:
65 NOTREACHED(); 91 NOTREACHED();
66 break; 92 break;
67 } 93 }
68 gfx::Rect new_child_area(child_area);
69 SetMainAxisPosition(position, &new_child_area);
70 SetMainAxisSize(size, &new_child_area);
71 child_area.Intersect(new_child_area);
72 } 94 }
95 gfx::Rect new_child_area(child_area);
96 SetMainAxisPosition(position, &new_child_area);
97 SetMainAxisSize(size, &new_child_area);
98 child_area.Intersect(new_child_area);
73 } 99 }
74 100
75 int main_position = MainAxisPosition(child_area); 101 int main_position = MainAxisPosition(child_area);
102 int total_padding = 0;
103 int current_flex = 0;
76 for (int i = 0; i < host->child_count(); ++i) { 104 for (int i = 0; i < host->child_count(); ++i) {
77 View* child = host->child_at(i); 105 View* child = host->child_at(i);
78 if (child->visible()) { 106 if (!child->visible())
79 gfx::Rect bounds(child_area); 107 continue;
80 SetMainAxisPosition(main_position, &bounds); 108
81 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) { 109 // Calculate cross axis size.
82 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child); 110 gfx::Rect bounds(child_area);
83 int position = CrossAxisPosition(bounds); 111 SetMainAxisPosition(main_position, &bounds);
84 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) { 112 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) {
85 position += free_space / 2; 113 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child);
86 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { 114 int position = CrossAxisPosition(bounds);
87 position += free_space; 115 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
88 } 116 position += free_space / 2;
89 SetCrossAxisPosition(position, &bounds); 117 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
90 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds); 118 position += free_space;
91 } 119 }
92 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 120 SetCrossAxisPosition(position, &bounds);
93 SetMainAxisSize(child_main_axis_size + padding, &bounds); 121 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds);
94 if (MainAxisSize(bounds) > 0) 122 }
95 main_position += MainAxisSize(bounds) + between_child_spacing_;
96 123
97 // Clamp child view bounds to |child_area|. 124 // Calculate flex padding.
98 bounds.Intersect(child_area); 125 int current_padding = 0;
99 child->SetBoundsRect(bounds); 126 if (GetFlexForView(child) > 0) {
127 current_flex += GetFlexForView(child);
128 int quot = (main_free_space * current_flex) / flex_sum;
129 int rem = (main_free_space * current_flex) % flex_sum;
130 current_padding = quot - total_padding;
131 // Use the current remainder to round to the nearest pixel.
132 if (std::abs(rem) * 2 >= flex_sum)
133 current_padding += main_free_space > 0 ? 1 : -1;
134 total_padding += current_padding;
100 } 135 }
136
137 // Set main axis size.
138 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
139 SetMainAxisSize(child_main_axis_size + current_padding, &bounds);
140 if (MainAxisSize(bounds) > 0 || GetFlexForView(child) > 0)
141 main_position += MainAxisSize(bounds) + between_child_spacing_;
142
143 // Clamp child view bounds to |child_area|.
144 bounds.Intersect(child_area);
145 child->SetBoundsRect(bounds);
101 } 146 }
147
148 // Flex views should have grown/shrunk to consume all free space.
149 if (flex_sum)
150 DCHECK_EQ(total_padding, main_free_space);
102 } 151 }
103 152
104 gfx::Size BoxLayout::GetPreferredSize(const View* host) const { 153 gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
154 DCHECK_EQ(host_, host);
105 // Calculate the child views' preferred width. 155 // Calculate the child views' preferred width.
106 int width = 0; 156 int width = 0;
107 if (orientation_ == kVertical) { 157 if (orientation_ == kVertical) {
108 for (int i = 0; i < host->child_count(); ++i) { 158 for (int i = 0; i < host->child_count(); ++i) {
109 const View* child = host->child_at(i); 159 const View* child = host->child_at(i);
110 if (!child->visible()) 160 if (!child->visible())
111 continue; 161 continue;
112 162
113 width = std::max(width, child->GetPreferredSize().width()); 163 width = std::max(width, child->GetPreferredSize().width());
114 } 164 }
115 } 165 }
116 166
117 return GetPreferredSizeForChildWidth(host, width); 167 return GetPreferredSizeForChildWidth(host, width);
118 } 168 }
119 169
120 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const { 170 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const {
171 DCHECK_EQ(host_, host);
121 int child_width = width - NonChildSize(host).width(); 172 int child_width = width - NonChildSize(host).width();
122 return GetPreferredSizeForChildWidth(host, child_width).height(); 173 return GetPreferredSizeForChildWidth(host, child_width).height();
123 } 174 }
124 175
176 void BoxLayout::Installed(View* host) {
177 DCHECK(!host_);
178 host_ = host;
179 }
180
181 void BoxLayout::Uninstalled(View* host) {
182 DCHECK_EQ(host_, host);
183 host_ = NULL;
184 flex_map_.clear();
185 }
186
187 void BoxLayout::ViewRemoved(View* host, View* view) {
188 ClearFlexForView(view);
189 }
190
191 int BoxLayout::GetFlexForView(const View* view) const {
192 std::map<const View*, int>::const_iterator it = flex_map_.find(view);
193 if (it == flex_map_.end())
194 return default_flex_;
195
196 return it->second;
197 }
198
125 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const { 199 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const {
126 return orientation_ == kHorizontal ? rect.width() : rect.height(); 200 return orientation_ == kHorizontal ? rect.width() : rect.height();
127 } 201 }
128 202
129 int BoxLayout::MainAxisPosition(const gfx::Rect& rect) const { 203 int BoxLayout::MainAxisPosition(const gfx::Rect& rect) const {
130 return orientation_ == kHorizontal ? rect.x() : rect.y(); 204 return orientation_ == kHorizontal ? rect.x() : rect.y();
131 } 205 }
132 206
133 void BoxLayout::SetMainAxisSize(int size, gfx::Rect* rect) const { 207 void BoxLayout::SetMainAxisSize(int size, gfx::Rect* rect) const {
134 if (orientation_ == kHorizontal) 208 if (orientation_ == kHorizontal)
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 child_area_bounds.height() + non_child_size.height()); 303 child_area_bounds.height() + non_child_size.height());
230 } 304 }
231 305
232 gfx::Size BoxLayout::NonChildSize(const View* host) const { 306 gfx::Size BoxLayout::NonChildSize(const View* host) const {
233 gfx::Insets insets(host->GetInsets()); 307 gfx::Insets insets(host->GetInsets());
234 return gfx::Size(insets.width() + inside_border_insets_.width(), 308 return gfx::Size(insets.width() + inside_border_insets_.width(),
235 insets.height() + inside_border_insets_.height()); 309 insets.height() + inside_border_insets_.height());
236 } 310 }
237 311
238 } // namespace views 312 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/layout/box_layout.h ('k') | ui/views/layout/box_layout_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698