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

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

Issue 2836313002: BoxLayout now suports per-view margins. (Closed)
Patch Set: BoxLayout now uses Margins property on the view Created 3 years, 7 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
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 <algorithm> 7 #include <algorithm>
8 8
9 #include "ui/gfx/geometry/rect.h" 9 #include "ui/gfx/geometry/rect.h"
10 #include "ui/views/view.h" 10 #include "ui/views/view.h"
11 11
12 namespace views { 12 namespace views {
13 13
14 BoxLayout::ViewWrapper::ViewWrapper() : view_(nullptr) {}
15
16 BoxLayout::ViewWrapper::ViewWrapper(View* view) : view_(view) {
17 gfx::Insets* margins = view_->GetProperty(kMarginsKey);
18 if (margins)
19 margins_ = *margins;
20 }
21
22 BoxLayout::ViewWrapper::~ViewWrapper() {}
23
24 int BoxLayout::ViewWrapper::GetHeightForWidth(int width) const {
25 return view_->GetHeightForWidth(width - margins_.width()) + margins_.height();
26 }
27
28 gfx::Size BoxLayout::ViewWrapper::GetPreferredSize() const {
29 gfx::Size preferred_size = view_->GetPreferredSize();
30 preferred_size.Enlarge(margins_.width(), margins_.height());
31 return preferred_size;
32 }
33
34 void BoxLayout::ViewWrapper::SetBoundsRect(const gfx::Rect& bounds) {
35 view_->SetBounds(bounds.x() + margins_.left(), bounds.y() + margins_.top(),
36 bounds.width() - margins_.width(),
37 bounds.height() - margins_.height());
38 }
39
40 bool BoxLayout::ViewWrapper::visible() const {
41 return view_->visible();
42 }
43
14 BoxLayout::BoxLayout(BoxLayout::Orientation orientation, 44 BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
15 int inside_border_horizontal_spacing, 45 int inside_border_horizontal_spacing,
16 int inside_border_vertical_spacing, 46 int inside_border_vertical_spacing,
17 int between_child_spacing) 47 int between_child_spacing)
18 : orientation_(orientation), 48 : orientation_(orientation),
19 inside_border_insets_(inside_border_vertical_spacing, 49 inside_border_insets_(inside_border_vertical_spacing,
20 inside_border_horizontal_spacing), 50 inside_border_horizontal_spacing),
21 between_child_spacing_(between_child_spacing), 51 between_child_spacing_(between_child_spacing),
22 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START), 52 main_axis_alignment_(MAIN_AXIS_ALIGNMENT_START),
23 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH), 53 cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH),
(...skipping 18 matching lines...) Expand all
42 flex_map_.erase(view); 72 flex_map_.erase(view);
43 } 73 }
44 74
45 void BoxLayout::SetDefaultFlex(int default_flex) { 75 void BoxLayout::SetDefaultFlex(int default_flex) {
46 DCHECK_GE(default_flex, 0); 76 DCHECK_GE(default_flex, 0);
47 default_flex_ = default_flex; 77 default_flex_ = default_flex;
48 } 78 }
49 79
50 void BoxLayout::Layout(View* host) { 80 void BoxLayout::Layout(View* host) {
51 DCHECK_EQ(host_, host); 81 DCHECK_EQ(host_, host);
52 gfx::Rect child_area(host->GetLocalBounds()); 82 gfx::Rect child_area(host->GetContentsBounds());
53 child_area.Inset(host->GetInsets());
54 child_area.Inset(inside_border_insets_); 83 child_area.Inset(inside_border_insets_);
55 84
56 int total_main_axis_size = 0; 85 int total_main_axis_size = 0;
57 int num_visible = 0; 86 int num_visible = 0;
58 int flex_sum = 0; 87 int flex_sum = 0;
59 // Calculate the total size of children in the main axis. 88 // Calculate the total size of children in the main axis.
60 for (int i = 0; i < host->child_count(); ++i) { 89 for (int i = 0; i < host->child_count(); ++i) {
61 View* child = host->child_at(i); 90 ViewWrapper child(host->child_at(i));
62 if (!child->visible()) 91 if (!child.visible())
63 continue; 92 continue;
64 int flex = GetFlexForView(child); 93 int flex = GetFlexForView(child.view());
65 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 94 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
66 if (child_main_axis_size == 0 && flex == 0) 95 if (child_main_axis_size == 0 && flex == 0)
67 continue; 96 continue;
68 total_main_axis_size += child_main_axis_size + between_child_spacing_; 97 total_main_axis_size += child_main_axis_size + between_child_spacing_;
69 ++num_visible; 98 ++num_visible;
70 flex_sum += flex; 99 flex_sum += flex;
71 } 100 }
72 101
73 if (!num_visible) 102 if (!num_visible)
74 return; 103 return;
(...skipping 24 matching lines...) Expand all
99 gfx::Rect new_child_area(child_area); 128 gfx::Rect new_child_area(child_area);
100 SetMainAxisPosition(position, &new_child_area); 129 SetMainAxisPosition(position, &new_child_area);
101 SetMainAxisSize(size, &new_child_area); 130 SetMainAxisSize(size, &new_child_area);
102 child_area.Intersect(new_child_area); 131 child_area.Intersect(new_child_area);
103 } 132 }
104 133
105 int main_position = MainAxisPosition(child_area); 134 int main_position = MainAxisPosition(child_area);
106 int total_padding = 0; 135 int total_padding = 0;
107 int current_flex = 0; 136 int current_flex = 0;
108 for (int i = 0; i < host->child_count(); ++i) { 137 for (int i = 0; i < host->child_count(); ++i) {
109 View* child = host->child_at(i); 138 ViewWrapper child(host->child_at(i));
110 if (!child->visible()) 139 if (!child.visible())
111 continue; 140 continue;
112 141
113 // TODO(bruthig): Fix this. The main axis should be calculated before 142 // TODO(bruthig): Fix this. The main axis should be calculated before
114 // the cross axis size because child Views may calculate their cross axis 143 // the cross axis size because child Views may calculate their cross axis
115 // size based on their main axis size. See https://crbug.com/682266. 144 // size based on their main axis size. See https://crbug.com/682266.
116 145
117 // Calculate cross axis size. 146 // Calculate cross axis size.
118 gfx::Rect bounds(child_area); 147 gfx::Rect bounds(child_area);
119 SetMainAxisPosition(main_position, &bounds); 148 SetMainAxisPosition(main_position, &bounds);
120 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) { 149 if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) {
121 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child); 150 int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child);
122 int position = CrossAxisPosition(bounds); 151 int position = CrossAxisPosition(bounds);
123 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) { 152 if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) {
124 position += free_space / 2; 153 position += free_space / 2;
125 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { 154 } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) {
126 position += free_space; 155 position += free_space;
127 } 156 }
128 SetCrossAxisPosition(position, &bounds); 157 SetCrossAxisPosition(position, &bounds);
129 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds); 158 SetCrossAxisSize(CrossAxisSizeForView(child), &bounds);
130 } 159 }
131 160
132 // Calculate flex padding. 161 // Calculate flex padding.
133 int current_padding = 0; 162 int current_padding = 0;
134 if (GetFlexForView(child) > 0) { 163 if (GetFlexForView(child.view()) > 0) {
135 current_flex += GetFlexForView(child); 164 current_flex += GetFlexForView(child.view());
136 int quot = (main_free_space * current_flex) / flex_sum; 165 int quot = (main_free_space * current_flex) / flex_sum;
137 int rem = (main_free_space * current_flex) % flex_sum; 166 int rem = (main_free_space * current_flex) % flex_sum;
138 current_padding = quot - total_padding; 167 current_padding = quot - total_padding;
139 // Use the current remainder to round to the nearest pixel. 168 // Use the current remainder to round to the nearest pixel.
140 if (std::abs(rem) * 2 >= flex_sum) 169 if (std::abs(rem) * 2 >= flex_sum)
141 current_padding += main_free_space > 0 ? 1 : -1; 170 current_padding += main_free_space > 0 ? 1 : -1;
142 total_padding += current_padding; 171 total_padding += current_padding;
143 } 172 }
144 173
145 // Set main axis size. 174 // Set main axis size.
146 // TODO(bruthig): Use the allocated width to determine the cross axis size. 175 // TODO(bruthig): Use the allocated width to determine the cross axis size.
147 // See https://crbug.com/682266. 176 // See https://crbug.com/682266.
148 int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); 177 int child_main_axis_size = MainAxisSizeForView(child, child_area.width());
149 SetMainAxisSize(child_main_axis_size + current_padding, &bounds); 178 SetMainAxisSize(child_main_axis_size + current_padding, &bounds);
150 if (MainAxisSize(bounds) > 0 || GetFlexForView(child) > 0) 179 if (MainAxisSize(bounds) > 0 || GetFlexForView(child.view()) > 0)
151 main_position += MainAxisSize(bounds) + between_child_spacing_; 180 main_position += MainAxisSize(bounds) + between_child_spacing_;
152 181
153 // Clamp child view bounds to |child_area|. 182 // Clamp child view bounds to |child_area|.
154 bounds.Intersect(child_area); 183 bounds.Intersect(child_area);
155 child->SetBoundsRect(bounds); 184 child.SetBoundsRect(bounds);
156 } 185 }
157 186
158 // Flex views should have grown/shrunk to consume all free space. 187 // Flex views should have grown/shrunk to consume all free space.
159 if (flex_sum) 188 if (flex_sum)
160 DCHECK_EQ(total_padding, main_free_space); 189 DCHECK_EQ(total_padding, main_free_space);
161 } 190 }
162 191
163 gfx::Size BoxLayout::GetPreferredSize(const View* host) const { 192 gfx::Size BoxLayout::GetPreferredSize(const View* host) const {
164 DCHECK_EQ(host_, host); 193 DCHECK_EQ(host_, host);
165 // Calculate the child views' preferred width. 194 // Calculate the child views' preferred width.
166 int width = 0; 195 int width = 0;
167 if (orientation_ == kVertical) { 196 if (orientation_ == kVertical) {
168 for (int i = 0; i < host->child_count(); ++i) { 197 for (int i = 0; i < host_->child_count(); ++i) {
169 const View* child = host->child_at(i); 198 const ViewWrapper child(host_->child_at(i));
170 if (!child->visible()) 199 if (!child.visible())
171 continue; 200 continue;
172 201
173 width = std::max(width, child->GetPreferredSize().width()); 202 width = std::max(width, child.GetPreferredSize().width());
174 } 203 }
175 width = std::max(width, minimum_cross_axis_size_); 204 width = std::max(width, minimum_cross_axis_size_);
176 } 205 }
177 206
178 return GetPreferredSizeForChildWidth(host, width); 207 return GetPreferredSizeForChildWidth(host, width);
179 } 208 }
180 209
181 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const { 210 int BoxLayout::GetPreferredHeightForWidth(const View* host, int width) const {
182 DCHECK_EQ(host_, host); 211 DCHECK_EQ(host_, host);
183 int child_width = width - NonChildSize(host).width(); 212 int child_width = width - NonChildSize(host).width();
184 return GetPreferredSizeForChildWidth(host, child_width).height(); 213 return GetPreferredSizeForChildWidth(host, child_width).height();
185 } 214 }
186 215
187 void BoxLayout::Installed(View* host) { 216 void BoxLayout::Installed(View* host) {
188 DCHECK(!host_); 217 DCHECK(!host_);
189 host_ = host; 218 host_ = host;
190 } 219 }
191 220
192 void BoxLayout::ViewRemoved(View* host, View* view) { 221 void BoxLayout::ViewRemoved(View* host, View* view) {
193 ClearFlexForView(view); 222 ClearFlexForView(view);
194 } 223 }
195 224
196 int BoxLayout::GetFlexForView(const View* view) const { 225 int BoxLayout::GetFlexForView(const View* view) const {
197 std::map<const View*, int>::const_iterator it = flex_map_.find(view); 226 FlexMap::const_iterator it = flex_map_.find(view);
198 if (it == flex_map_.end()) 227 if (it == flex_map_.end())
199 return default_flex_; 228 return default_flex_;
200 229
201 return it->second; 230 return it->second;
202 } 231 }
203 232
204 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const { 233 int BoxLayout::MainAxisSize(const gfx::Rect& rect) const {
205 return orientation_ == kHorizontal ? rect.width() : rect.height(); 234 return orientation_ == kHorizontal ? rect.width() : rect.height();
206 } 235 }
207 236
(...skipping 30 matching lines...) Expand all
238 rect->set_height(size); 267 rect->set_height(size);
239 } 268 }
240 269
241 void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const { 270 void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const {
242 if (orientation_ == kVertical) 271 if (orientation_ == kVertical)
243 rect->set_x(position); 272 rect->set_x(position);
244 else 273 else
245 rect->set_y(position); 274 rect->set_y(position);
246 } 275 }
247 276
248 int BoxLayout::MainAxisSizeForView(const View* view, 277 int BoxLayout::MainAxisSizeForView(const ViewWrapper& view,
249 int child_area_width) const { 278 int child_area_width) const {
250 return orientation_ == kHorizontal 279 return orientation_ == kHorizontal
251 ? view->GetPreferredSize().width() 280 ? view.GetPreferredSize().width()
252 : view->GetHeightForWidth(cross_axis_alignment_ == 281 : view.GetHeightForWidth(cross_axis_alignment_ ==
253 CROSS_AXIS_ALIGNMENT_STRETCH 282 CROSS_AXIS_ALIGNMENT_STRETCH
254 ? child_area_width 283 ? child_area_width
255 : view->GetPreferredSize().width()); 284 : view.GetPreferredSize().width());
256 } 285 }
257 286
258 int BoxLayout::CrossAxisSizeForView(const View* view) const { 287 int BoxLayout::CrossAxisSizeForView(const ViewWrapper& view) const {
259 // TODO(bruthig): For horizontal case use the available width and not the 288 // TODO(bruthig): For horizontal case use the available width and not the
260 // preferred width. See https://crbug.com/682266. 289 // preferred width. See https://crbug.com/682266.
261 return orientation_ == kVertical 290 return orientation_ == kVertical
262 ? view->GetPreferredSize().width() 291 ? view.GetPreferredSize().width()
263 : view->GetHeightForWidth(view->GetPreferredSize().width()); 292 : view.GetHeightForWidth(view.GetPreferredSize().width());
264 } 293 }
265 294
266 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, 295 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host,
267 int child_area_width) const { 296 int child_area_width) const {
297 DCHECK_EQ(host, host_);
268 gfx::Rect child_area_bounds; 298 gfx::Rect child_area_bounds;
269 299
270 if (orientation_ == kHorizontal) { 300 if (orientation_ == kHorizontal) {
271 // Horizontal layouts ignore |child_area_width|, meaning they mimic the 301 // Horizontal layouts ignore |child_area_width|, meaning they mimic the
272 // default behavior of GridLayout::GetPreferredHeightForWidth(). 302 // default behavior of GridLayout::GetPreferredHeightForWidth().
273 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266. 303 // TODO(estade|bruthig): Fix this See // https://crbug.com/682266.
274 int position = 0; 304 int position = 0;
275 for (int i = 0; i < host->child_count(); ++i) { 305 for (int i = 0; i < host_->child_count(); ++i) {
276 const View* child = host->child_at(i); 306 const ViewWrapper child(host_->child_at(i));
277 if (!child->visible()) 307 if (!child.visible())
278 continue; 308 continue;
279 309
280 gfx::Size size(child->GetPreferredSize()); 310 gfx::Size size(child.GetPreferredSize());
281 if (size.IsEmpty()) 311 if (size.IsEmpty())
282 continue; 312 continue;
283 313
284 gfx::Rect child_bounds(position, 0, size.width(), size.height()); 314 gfx::Rect child_bounds(position, 0, size.width(), size.height());
285 child_area_bounds.Union(child_bounds); 315 child_area_bounds.Union(child_bounds);
286 position += size.width() + between_child_spacing_; 316 position += size.width() + between_child_spacing_;
287 } 317 }
288 child_area_bounds.set_height( 318 child_area_bounds.set_height(
289 std::max(child_area_bounds.height(), minimum_cross_axis_size_)); 319 std::max(child_area_bounds.height(), minimum_cross_axis_size_));
290 } else { 320 } else {
291 int height = 0; 321 int height = 0;
292 for (int i = 0; i < host->child_count(); ++i) { 322 for (int i = 0; i < host_->child_count(); ++i) {
293 const View* child = host->child_at(i); 323 const ViewWrapper child(host_->child_at(i));
294 if (!child->visible()) 324 if (!child.visible())
295 continue; 325 continue;
296 326
297 // Use the child area width for getting the height if the child is 327 // Use the child area width for getting the height if the child is
298 // supposed to stretch. Use its preferred size otherwise. 328 // supposed to stretch. Use its preferred size otherwise.
299 int extra_height = MainAxisSizeForView(child, child_area_width); 329 int extra_height = MainAxisSizeForView(child, child_area_width);
300 // Only add |between_child_spacing_| if this is not the only child. 330 // Only add |between_child_spacing_| if this is not the only child.
301 if (height != 0 && extra_height > 0) 331 if (height != 0 && extra_height > 0)
302 height += between_child_spacing_; 332 height += between_child_spacing_;
303 height += extra_height; 333 height += extra_height;
304 } 334 }
305 335
306 child_area_bounds.set_width(child_area_width); 336 child_area_bounds.set_width(child_area_width);
307 child_area_bounds.set_height(height); 337 child_area_bounds.set_height(height);
308 } 338 }
309 339
310 gfx::Size non_child_size = NonChildSize(host); 340 gfx::Size non_child_size = NonChildSize(host_);
311 return gfx::Size(child_area_bounds.width() + non_child_size.width(), 341 return gfx::Size(child_area_bounds.width() + non_child_size.width(),
312 child_area_bounds.height() + non_child_size.height()); 342 child_area_bounds.height() + non_child_size.height());
313 } 343 }
314 344
315 gfx::Size BoxLayout::NonChildSize(const View* host) const { 345 gfx::Size BoxLayout::NonChildSize(const View* host) const {
316 gfx::Insets insets(host->GetInsets()); 346 gfx::Insets insets(host->GetInsets());
317 return gfx::Size(insets.width() + inside_border_insets_.width(), 347 return gfx::Size(insets.width() + inside_border_insets_.width(),
318 insets.height() + inside_border_insets_.height()); 348 insets.height() + inside_border_insets_.height());
319 } 349 }
320 350
321 } // namespace views 351 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/layout/box_layout.h ('k') | ui/views/view.h » ('j') | ui/views/view.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698