• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "ui/views/layout/box_layout.h"
6 
7 #include "ui/gfx/rect.h"
8 #include "ui/views/view.h"
9 
10 namespace views {
11 
BoxLayout(BoxLayout::Orientation orientation,int inside_border_horizontal_spacing,int inside_border_vertical_spacing,int between_child_spacing)12 BoxLayout::BoxLayout(BoxLayout::Orientation orientation,
13                      int inside_border_horizontal_spacing,
14                      int inside_border_vertical_spacing,
15                      int between_child_spacing)
16     : orientation_(orientation),
17       inside_border_insets_(inside_border_vertical_spacing,
18                             inside_border_horizontal_spacing,
19                             inside_border_vertical_spacing,
20                             inside_border_horizontal_spacing),
21       between_child_spacing_(between_child_spacing),
22       spread_blank_space_(false) {
23 }
24 
~BoxLayout()25 BoxLayout::~BoxLayout() {
26 }
27 
Layout(View * host)28 void BoxLayout::Layout(View* host) {
29   gfx::Rect child_area(host->GetLocalBounds());
30   child_area.Inset(host->GetInsets());
31   child_area.Inset(inside_border_insets_);
32   int x = child_area.x();
33   int y = child_area.y();
34 
35   int padding = 0;
36   if (spread_blank_space_) {
37     int total = 0;
38     int visible = 0;
39     for (int i = 0; i < host->child_count(); ++i) {
40       View* child = host->child_at(i);
41       if (!child->visible())
42         continue;
43       if (orientation_ == kHorizontal) {
44         total += child->GetPreferredSize().width() + between_child_spacing_;
45       } else {
46         total += child->GetHeightForWidth(child_area.width()) +
47             between_child_spacing_;
48       }
49       ++visible;
50     }
51 
52     if (visible) {
53       total -= between_child_spacing_;
54       if (orientation_ == kHorizontal)
55         padding = (child_area.width() - total) / visible;
56       else
57         padding = (child_area.height() - total) / visible;
58 
59       if (padding < 0)
60         padding = 0;
61     }
62   }
63 
64   for (int i = 0; i < host->child_count(); ++i) {
65     View* child = host->child_at(i);
66     if (child->visible()) {
67       gfx::Rect bounds(x, y, child_area.width(), child_area.height());
68       if (orientation_ == kHorizontal) {
69         bounds.set_width(child->GetPreferredSize().width() + padding);
70         if (bounds.width() > 0)
71           x += bounds.width() + between_child_spacing_;
72       } else {
73         bounds.set_height(child->GetHeightForWidth(bounds.width()) + padding);
74         if (bounds.height() > 0)
75           y += bounds.height() + between_child_spacing_;
76       }
77       // Clamp child view bounds to |child_area|.
78       bounds.Intersect(child_area);
79       child->SetBoundsRect(bounds);
80     }
81   }
82 }
83 
GetPreferredSize(View * host)84 gfx::Size BoxLayout::GetPreferredSize(View* host) {
85   // Calculate the child views' preferred width.
86   int width = 0;
87   if (orientation_ == kVertical) {
88     for (int i = 0; i < host->child_count(); ++i) {
89       View* child = host->child_at(i);
90       if (!child->visible())
91         continue;
92 
93       width = std::max(width, child->GetPreferredSize().width());
94     }
95   }
96 
97   return GetPreferredSizeForChildWidth(host, width);
98 }
99 
GetPreferredHeightForWidth(View * host,int width)100 int BoxLayout::GetPreferredHeightForWidth(View* host, int width) {
101   int child_width = width - NonChildSize(host).width();
102   return GetPreferredSizeForChildWidth(host, child_width).height();
103 }
104 
GetPreferredSizeForChildWidth(View * host,int child_area_width)105 gfx::Size BoxLayout::GetPreferredSizeForChildWidth(View* host,
106                                                    int child_area_width) {
107   gfx::Rect child_area_bounds;
108 
109   if (orientation_ == kHorizontal) {
110     // Horizontal layouts ignore |child_area_width|, meaning they mimic the
111     // default behavior of GridLayout::GetPreferredHeightForWidth().
112     // TODO(estade): fix this if it ever becomes a problem.
113     int position = 0;
114     for (int i = 0; i < host->child_count(); ++i) {
115       View* child = host->child_at(i);
116       if (!child->visible())
117         continue;
118 
119       gfx::Size size(child->GetPreferredSize());
120       if (size.IsEmpty())
121         continue;
122 
123       gfx::Rect child_bounds(position, 0, size.width(), size.height());
124       child_area_bounds.Union(child_bounds);
125       position += size.width() + between_child_spacing_;
126     }
127   } else {
128     int height = 0;
129     for (int i = 0; i < host->child_count(); ++i) {
130       View* child = host->child_at(i);
131       if (!child->visible())
132         continue;
133 
134       int extra_height = child->GetHeightForWidth(child_area_width);
135       // Only add |between_child_spacing_| if this is not the only child.
136       if (height != 0 && extra_height > 0)
137         height += between_child_spacing_;
138       height += extra_height;
139     }
140 
141     child_area_bounds.set_width(child_area_width);
142     child_area_bounds.set_height(height);
143   }
144 
145   gfx::Size non_child_size = NonChildSize(host);
146   return gfx::Size(child_area_bounds.width() + non_child_size.width(),
147                    child_area_bounds.height() + non_child_size.height());
148 }
149 
NonChildSize(View * host)150 gfx::Size BoxLayout::NonChildSize(View* host) {
151   gfx::Insets insets(host->GetInsets());
152   return gfx::Size(insets.width() + inside_border_insets_.width(),
153                    insets.height() + inside_border_insets_.height());
154 }
155 
156 } // namespace views
157