Index: ui/views/layout/box_layout.cc |
diff --git a/ui/views/layout/box_layout.cc b/ui/views/layout/box_layout.cc |
index defbcd370c4610e7ff819a701a02d3c94e3e0ea6..fabf5bb492e22546c53e328ffc8f2417ab5d4350 100644 |
--- a/ui/views/layout/box_layout.cc |
+++ b/ui/views/layout/box_layout.cc |
@@ -8,12 +8,91 @@ |
#include "ui/gfx/geometry/rect.h" |
#include "ui/views/view.h" |
+#include "ui/views/view_properties.h" |
namespace views { |
+namespace { |
+ |
+// Returns the maximum of the given insets along the given |axis|. |
+// NOTE: |axis| is different from |orientation_|; it specifies the actual |
+// desired axis. |
+enum Axis { HORIZONTAL_AXIS, VERTICAL_AXIS }; |
+ |
+gfx::Insets MaxAxisInsets(Axis axis, |
+ const gfx::Insets& leading1, |
+ const gfx::Insets& leading2, |
+ const gfx::Insets& trailing1, |
+ const gfx::Insets& trailing2) { |
+ if (axis == HORIZONTAL_AXIS) { |
+ return gfx::Insets(0, std::max(leading1.left(), leading2.left()), 0, |
+ std::max(trailing1.right(), trailing2.right())); |
+ } |
+ return gfx::Insets(std::max(leading1.top(), leading2.top()), 0, |
+ std::max(trailing1.bottom(), trailing2.bottom()), 0); |
+} |
+ |
+} // namespace |
+ |
+BoxLayout::ViewWrapper::ViewWrapper() : view_(nullptr), layout_(nullptr) {} |
+ |
+BoxLayout::ViewWrapper::ViewWrapper(const BoxLayout* layout, View* view) |
+ : view_(view), layout_(layout) { |
+ gfx::Insets* margins = view_ ? view_->GetProperty(kMarginsKey) : nullptr; |
+ if (margins) |
+ margins_ = *margins; |
+} |
+ |
+BoxLayout::ViewWrapper::~ViewWrapper() {} |
+ |
+int BoxLayout::ViewWrapper::GetHeightForWidth(int width) const { |
+ // When collapse_margins_spacing_ is true, the BoxLayout handles the margin |
+ // calculations because it has to compare and use only the largest of several |
+ // adjacent margins or border insets. |
+ if (layout_->collapse_margins_spacing_) |
+ return view_->GetHeightForWidth(width); |
+ // When collapse_margins_spacing_ is false, the view margins are included in |
+ // the "virtual" size of the view. The view itself is unaware of this, so this |
+ // information has to be excluded before the call to View::GetHeightForWidth() |
+ // and added back in to the result. |
+ // If the orientation_ is kVertical, the cross-axis is the actual view width. |
+ // This is because the cross-axis margins are always handled by the layout. |
+ if (layout_->orientation_ == Orientation::kHorizontal) { |
+ return view_->GetHeightForWidth(std::max(0, width - margins_.width())) + |
+ margins_.height(); |
+ } |
+ return view_->GetHeightForWidth(width) + margins_.height(); |
+} |
+ |
+gfx::Size BoxLayout::ViewWrapper::GetPreferredSize() const { |
+ gfx::Size preferred_size = view_->GetPreferredSize(); |
+ if (!layout_->collapse_margins_spacing_) |
+ preferred_size.Enlarge(margins_.width(), margins_.height()); |
+ return preferred_size; |
+} |
+ |
+void BoxLayout::ViewWrapper::SetBoundsRect(const gfx::Rect& bounds) { |
+ gfx::Rect new_bounds = bounds; |
+ if (!layout_->collapse_margins_spacing_) { |
+ if (layout_->orientation_ == Orientation::kHorizontal) { |
+ new_bounds.set_x(bounds.x() + margins_.left()); |
+ new_bounds.set_width(std::max(0, bounds.width() - margins_.width())); |
+ } else { |
+ new_bounds.set_y(bounds.y() + margins_.top()); |
+ new_bounds.set_height(std::max(0, bounds.height() - margins_.height())); |
+ } |
+ } |
+ view_->SetBoundsRect(new_bounds); |
+} |
+ |
+bool BoxLayout::ViewWrapper::visible() const { |
+ return view_->visible(); |
+} |
+ |
BoxLayout::BoxLayout(BoxLayout::Orientation orientation, |
const gfx::Insets& inside_border_insets, |
- int between_child_spacing) |
+ int between_child_spacing, |
+ bool collapse_margins_spacing) |
: orientation_(orientation), |
inside_border_insets_(inside_border_insets), |
between_child_spacing_(between_child_spacing), |
@@ -21,6 +100,7 @@ BoxLayout::BoxLayout(BoxLayout::Orientation orientation, |
cross_axis_alignment_(CROSS_AXIS_ALIGNMENT_STRETCH), |
default_flex_(0), |
minimum_cross_axis_size_(0), |
+ collapse_margins_spacing_(collapse_margins_spacing), |
host_(nullptr) {} |
BoxLayout::~BoxLayout() { |
@@ -46,23 +126,32 @@ void BoxLayout::SetDefaultFlex(int default_flex) { |
void BoxLayout::Layout(View* host) { |
DCHECK_EQ(host_, host); |
- gfx::Rect child_area(host->GetLocalBounds()); |
- child_area.Inset(host->GetInsets()); |
- child_area.Inset(inside_border_insets_); |
+ gfx::Rect child_area(host->GetContentsBounds()); |
+ |
+ AdjustMainAxisForMargin(&child_area); |
+ gfx::Insets max_cross_axis_margin; |
+ if (!collapse_margins_spacing_) { |
+ AdjustCrossAxisForInsets(&child_area); |
+ max_cross_axis_margin = CrossAxisMaxViewMargin(); |
+ } |
+ if (child_area.IsEmpty()) |
+ return; |
int total_main_axis_size = 0; |
int num_visible = 0; |
int flex_sum = 0; |
// Calculate the total size of children in the main axis. |
for (int i = 0; i < host->child_count(); ++i) { |
- View* child = host->child_at(i); |
- if (!child->visible()) |
+ const ViewWrapper child(this, host->child_at(i)); |
+ if (!child.visible()) |
continue; |
- int flex = GetFlexForView(child); |
+ int flex = GetFlexForView(child.view()); |
int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); |
if (child_main_axis_size == 0 && flex == 0) |
continue; |
- total_main_axis_size += child_main_axis_size + between_child_spacing_; |
+ total_main_axis_size += child_main_axis_size + |
+ MainAxisMarginBetweenViews( |
+ child, ViewWrapper(this, NextVisibleView(i))); |
++num_visible; |
flex_sum += flex; |
} |
@@ -103,8 +192,8 @@ void BoxLayout::Layout(View* host) { |
int total_padding = 0; |
int current_flex = 0; |
for (int i = 0; i < host->child_count(); ++i) { |
- View* child = host->child_at(i); |
- if (!child->visible()) |
+ ViewWrapper child(this, host->child_at(i)); |
+ if (!child.visible()) |
continue; |
// TODO(bruthig): Fix this. The main axis should be calculated before |
@@ -113,23 +202,56 @@ void BoxLayout::Layout(View* host) { |
// Calculate cross axis size. |
gfx::Rect bounds(child_area); |
+ gfx::Rect min_child_area(child_area); |
+ gfx::Insets child_margins; |
+ if (collapse_margins_spacing_) { |
+ child_margins = MaxAxisInsets( |
+ orientation_ == kVertical ? HORIZONTAL_AXIS : VERTICAL_AXIS, |
+ child.margins(), inside_border_insets_, child.margins(), |
+ inside_border_insets_); |
+ } else { |
+ child_margins = child.margins(); |
+ } |
+ |
+ if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_STRETCH || |
+ cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) { |
+ InsetCrossAxis(&min_child_area, CrossAxisLeadingInset(child_margins), |
+ CrossAxisTrailingInset(child_margins)); |
+ } |
+ |
SetMainAxisPosition(main_position, &bounds); |
if (cross_axis_alignment_ != CROSS_AXIS_ALIGNMENT_STRETCH) { |
- int free_space = CrossAxisSize(bounds) - CrossAxisSizeForView(child); |
+ int cross_axis_margin_size = CrossAxisMarginSizeForView(child); |
+ int view_cross_axis_size = |
+ CrossAxisSizeForView(child) - cross_axis_margin_size; |
+ int free_space = CrossAxisSize(bounds) - view_cross_axis_size; |
int position = CrossAxisPosition(bounds); |
if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_CENTER) { |
+ if (view_cross_axis_size > CrossAxisSize(min_child_area)) |
+ view_cross_axis_size = CrossAxisSize(min_child_area); |
position += free_space / 2; |
+ position = std::max(position, CrossAxisLeadingEdge(min_child_area)); |
} else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { |
- position += free_space; |
+ position += free_space - CrossAxisTrailingInset(max_cross_axis_margin); |
+ if (!collapse_margins_spacing_) |
+ InsetCrossAxis(&min_child_area, |
+ CrossAxisLeadingInset(child.margins()), |
+ CrossAxisTrailingInset(max_cross_axis_margin)); |
+ } else { |
+ position += CrossAxisLeadingInset(max_cross_axis_margin); |
+ if (!collapse_margins_spacing_) |
+ InsetCrossAxis(&min_child_area, |
+ CrossAxisLeadingInset(max_cross_axis_margin), |
+ CrossAxisTrailingInset(child.margins())); |
} |
SetCrossAxisPosition(position, &bounds); |
- SetCrossAxisSize(CrossAxisSizeForView(child), &bounds); |
+ SetCrossAxisSize(view_cross_axis_size, &bounds); |
} |
// Calculate flex padding. |
int current_padding = 0; |
- if (GetFlexForView(child) > 0) { |
- current_flex += GetFlexForView(child); |
+ if (GetFlexForView(child.view()) > 0) { |
+ current_flex += GetFlexForView(child.view()); |
int quot = (main_free_space * current_flex) / flex_sum; |
int rem = (main_free_space * current_flex) % flex_sum; |
current_padding = quot - total_padding; |
@@ -144,12 +266,14 @@ void BoxLayout::Layout(View* host) { |
// See https://crbug.com/682266. |
int child_main_axis_size = MainAxisSizeForView(child, child_area.width()); |
SetMainAxisSize(child_main_axis_size + current_padding, &bounds); |
- if (MainAxisSize(bounds) > 0 || GetFlexForView(child) > 0) |
- main_position += MainAxisSize(bounds) + between_child_spacing_; |
+ if (MainAxisSize(bounds) > 0 || GetFlexForView(child.view()) > 0) |
+ main_position += MainAxisSize(bounds) + |
+ MainAxisMarginBetweenViews( |
+ child, ViewWrapper(this, NextVisibleView(i))); |
// Clamp child view bounds to |child_area|. |
- bounds.Intersect(child_area); |
- child->SetBoundsRect(bounds); |
+ bounds.Intersect(min_child_area); |
+ child.SetBoundsRect(bounds); |
} |
// Flex views should have grown/shrunk to consume all free space. |
@@ -162,14 +286,54 @@ gfx::Size BoxLayout::GetPreferredSize(const View* host) const { |
// Calculate the child views' preferred width. |
int width = 0; |
if (orientation_ == kVertical) { |
- for (int i = 0; i < host->child_count(); ++i) { |
- const View* child = host->child_at(i); |
- if (!child->visible()) |
+ // Calculating the child views' overall preferred width is a little involved |
+ // because of the way the margins interact with |cross_axis_alignment_|. |
+ int leading = 0; |
+ int trailing = 0; |
+ gfx::Rect child_view_area; |
+ for (int i = 0; i < host_->child_count(); ++i) { |
+ const ViewWrapper child(this, host_->child_at(i)); |
+ if (!child.visible()) |
continue; |
- width = std::max(width, child->GetPreferredSize().width()); |
+ // We need to bypass the ViewWrapper GetPreferredSize() to get the actual |
+ // raw view size because the margins along the cross axis are handled |
+ // below. |
+ gfx::Size child_size = child.view()->GetPreferredSize(); |
+ gfx::Insets child_margins; |
+ if (collapse_margins_spacing_) { |
+ child_margins = MaxAxisInsets(HORIZONTAL_AXIS, child.margins(), |
+ inside_border_insets_, child.margins(), |
+ inside_border_insets_); |
+ } else { |
+ child_margins = child.margins(); |
+ } |
+ |
+ // The value of |cross_axis_alignment_| will determine how the view's |
+ // margins interact with each other or the |inside_border_insets_|. |
+ if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_START) { |
+ leading = std::max(leading, CrossAxisLeadingInset(child_margins)); |
+ width = std::max( |
+ width, child_size.width() + CrossAxisTrailingInset(child_margins)); |
+ } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { |
+ trailing = std::max(trailing, CrossAxisTrailingInset(child_margins)); |
+ width = std::max( |
+ width, child_size.width() + CrossAxisLeadingInset(child_margins)); |
+ } else { |
+ // We don't have a rectangle which can be used to calculate a common |
+ // center-point, so a single known point (0) along the horizontal axis |
+ // is used. This is OK because we're only interested in the overall |
+ // width and not the position. |
+ gfx::Rect child_bounds = |
+ gfx::Rect(-(child_size.width() / 2), 0, child_size.width(), |
+ child_size.height()); |
+ child_bounds.Inset(-child.margins().left(), 0, -child.margins().right(), |
+ 0); |
+ child_view_area.Union(child_bounds); |
+ width = std::max(width, child_view_area.width()); |
+ } |
} |
- width = std::max(width, minimum_cross_axis_size_); |
+ width = std::max(width + leading + trailing, minimum_cross_axis_size_); |
} |
return GetPreferredSizeForChildWidth(host, width); |
@@ -191,7 +355,7 @@ void BoxLayout::ViewRemoved(View* host, View* view) { |
} |
int BoxLayout::GetFlexForView(const View* view) const { |
- std::map<const View*, int>::const_iterator it = flex_map_.find(view); |
+ FlexMap::const_iterator it = flex_map_.find(view); |
if (it == flex_map_.end()) |
return default_flex_; |
@@ -242,26 +406,118 @@ void BoxLayout::SetCrossAxisPosition(int position, gfx::Rect* rect) const { |
rect->set_y(position); |
} |
-int BoxLayout::MainAxisSizeForView(const View* view, |
+int BoxLayout::MainAxisSizeForView(const ViewWrapper& view, |
int child_area_width) const { |
return orientation_ == kHorizontal |
- ? view->GetPreferredSize().width() |
- : view->GetHeightForWidth(cross_axis_alignment_ == |
- CROSS_AXIS_ALIGNMENT_STRETCH |
- ? child_area_width |
- : view->GetPreferredSize().width()); |
+ ? view.GetPreferredSize().width() |
+ : view.GetHeightForWidth(cross_axis_alignment_ == |
+ CROSS_AXIS_ALIGNMENT_STRETCH |
+ ? child_area_width |
+ : view.GetPreferredSize().width()); |
+} |
+ |
+int BoxLayout::MainAxisLeadingInset(const gfx::Insets& insets) const { |
+ return orientation_ == kHorizontal ? insets.left() : insets.top(); |
+} |
+ |
+int BoxLayout::MainAxisTrailingInset(const gfx::Insets& insets) const { |
+ return orientation_ == kHorizontal ? insets.right() : insets.bottom(); |
+} |
+ |
+int BoxLayout::CrossAxisLeadingEdge(const gfx::Rect& rect) const { |
+ return orientation_ == kVertical ? rect.x() : rect.y(); |
} |
-int BoxLayout::CrossAxisSizeForView(const View* view) const { |
+int BoxLayout::CrossAxisLeadingInset(const gfx::Insets& insets) const { |
+ return orientation_ == kVertical ? insets.left() : insets.top(); |
+} |
+ |
+int BoxLayout::CrossAxisTrailingInset(const gfx::Insets& insets) const { |
+ return orientation_ == kVertical ? insets.right() : insets.bottom(); |
+} |
+ |
+int BoxLayout::MainAxisMarginBetweenViews(const ViewWrapper& leading, |
+ const ViewWrapper& trailing) const { |
+ if (!collapse_margins_spacing_ || !leading.view() || !trailing.view()) |
+ return between_child_spacing_; |
+ return std::max(between_child_spacing_, |
+ std::max(MainAxisTrailingInset(leading.margins()), |
+ MainAxisLeadingInset(trailing.margins()))); |
+} |
+ |
+gfx::Insets BoxLayout::MainAxisOuterMargin() const { |
+ if (collapse_margins_spacing_) { |
+ const ViewWrapper first(this, FirstVisibleView()); |
+ const ViewWrapper last(this, LastVisibleView()); |
+ return MaxAxisInsets( |
+ orientation_ == kHorizontal ? HORIZONTAL_AXIS : VERTICAL_AXIS, |
+ inside_border_insets_, first.margins(), inside_border_insets_, |
+ last.margins()); |
+ } |
+ return MaxAxisInsets( |
+ orientation_ == kHorizontal ? HORIZONTAL_AXIS : VERTICAL_AXIS, |
+ inside_border_insets_, gfx::Insets(), inside_border_insets_, |
+ gfx::Insets()); |
+} |
+ |
+gfx::Insets BoxLayout::CrossAxisMaxViewMargin() const { |
+ int leading = 0; |
+ int trailing = 0; |
+ for (int i = 0; i < host_->child_count(); ++i) { |
+ const ViewWrapper child(this, host_->child_at(i)); |
+ if (!child.visible()) |
+ continue; |
+ leading = std::max(leading, CrossAxisLeadingInset(child.margins())); |
+ trailing = std::max(trailing, CrossAxisTrailingInset(child.margins())); |
+ } |
+ if (orientation_ == Orientation::kVertical) |
+ return gfx::Insets(0, leading, 0, trailing); |
+ return gfx::Insets(leading, 0, trailing, 0); |
+} |
+ |
+void BoxLayout::AdjustMainAxisForMargin(gfx::Rect* rect) const { |
+ rect->Inset(MainAxisOuterMargin()); |
+} |
+ |
+void BoxLayout::AdjustCrossAxisForInsets(gfx::Rect* rect) const { |
+ rect->Inset(orientation_ == Orientation::kVertical |
+ ? gfx::Insets(0, inside_border_insets_.left(), 0, |
+ inside_border_insets_.right()) |
+ : gfx::Insets(inside_border_insets_.top(), 0, |
+ inside_border_insets_.bottom(), 0)); |
+} |
+ |
+int BoxLayout::CrossAxisSizeForView(const ViewWrapper& view) const { |
// TODO(bruthig): For horizontal case use the available width and not the |
// preferred width. See https://crbug.com/682266. |
return orientation_ == kVertical |
- ? view->GetPreferredSize().width() |
- : view->GetHeightForWidth(view->GetPreferredSize().width()); |
+ ? view.GetPreferredSize().width() |
+ : view.GetHeightForWidth(view.GetPreferredSize().width()); |
+} |
+ |
+int BoxLayout::CrossAxisMarginSizeForView(const ViewWrapper& view) const { |
+ return collapse_margins_spacing_ |
+ ? 0 |
+ : (orientation_ == kVertical ? view.margins().width() |
+ : view.margins().height()); |
+} |
+ |
+int BoxLayout::CrossAxisLeadingMarginForView(const ViewWrapper& view) const { |
+ return collapse_margins_spacing_ ? 0 : CrossAxisLeadingInset(view.margins()); |
+} |
+ |
+void BoxLayout::InsetCrossAxis(gfx::Rect* rect, |
+ int leading, |
+ int trailing) const { |
+ if (orientation_ == kVertical) |
+ rect->Inset(leading, 0, trailing, 0); |
+ else |
+ rect->Inset(0, leading, 0, trailing); |
} |
gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, |
int child_area_width) const { |
+ DCHECK_EQ(host, host_); |
gfx::Rect child_area_bounds; |
if (orientation_ == kHorizontal) { |
@@ -269,34 +525,64 @@ gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, |
// default behavior of GridLayout::GetPreferredHeightForWidth(). |
// TODO(estade|bruthig): Fix this See // https://crbug.com/682266. |
int position = 0; |
- for (int i = 0; i < host->child_count(); ++i) { |
- const View* child = host->child_at(i); |
- if (!child->visible()) |
+ gfx::Insets max_margins = CrossAxisMaxViewMargin(); |
+ for (int i = 0; i < host_->child_count(); ++i) { |
+ const ViewWrapper child(this, host_->child_at(i)); |
+ if (!child.visible()) |
continue; |
- gfx::Size size(child->GetPreferredSize()); |
+ gfx::Size size(child.view()->GetPreferredSize()); |
if (size.IsEmpty()) |
continue; |
- gfx::Rect child_bounds(position, 0, size.width(), size.height()); |
+ gfx::Rect child_bounds = gfx::Rect( |
+ position, 0, |
+ size.width() + |
+ (!collapse_margins_spacing_ ? child.margins().width() : 0), |
+ size.height()); |
+ gfx::Insets child_margins; |
+ if (collapse_margins_spacing_) |
+ child_margins = |
+ MaxAxisInsets(VERTICAL_AXIS, child.margins(), inside_border_insets_, |
+ child.margins(), inside_border_insets_); |
+ else |
+ child_margins = child.margins(); |
+ |
+ if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_START) { |
+ child_bounds.Inset(0, -CrossAxisLeadingInset(max_margins), 0, |
+ -child_margins.bottom()); |
+ child_bounds.set_origin(gfx::Point(position, 0)); |
+ } else if (cross_axis_alignment_ == CROSS_AXIS_ALIGNMENT_END) { |
+ child_bounds.Inset(0, -child_margins.top(), 0, |
+ -CrossAxisTrailingInset(max_margins)); |
+ child_bounds.set_origin(gfx::Point(position, 0)); |
+ } else { |
+ child_bounds.set_origin( |
+ gfx::Point(position, -(child_bounds.height() / 2))); |
+ child_bounds.Inset(0, -child_margins.top(), 0, -child_margins.bottom()); |
+ } |
+ |
child_area_bounds.Union(child_bounds); |
- position += size.width() + between_child_spacing_; |
+ position += child_bounds.width() + |
+ MainAxisMarginBetweenViews( |
+ child, ViewWrapper(this, NextVisibleView(i))); |
} |
child_area_bounds.set_height( |
std::max(child_area_bounds.height(), minimum_cross_axis_size_)); |
} else { |
int height = 0; |
- for (int i = 0; i < host->child_count(); ++i) { |
- const View* child = host->child_at(i); |
- if (!child->visible()) |
+ for (int i = 0; i < host_->child_count(); ++i) { |
+ const ViewWrapper child(this, host_->child_at(i)); |
+ if (!child.visible()) |
continue; |
+ const ViewWrapper next(this, NextVisibleView(i)); |
// Use the child area width for getting the height if the child is |
// supposed to stretch. Use its preferred size otherwise. |
int extra_height = MainAxisSizeForView(child, child_area_width); |
// Only add |between_child_spacing_| if this is not the only child. |
- if (height != 0 && extra_height > 0) |
- height += between_child_spacing_; |
+ if (next.view() && extra_height > 0) |
+ height += MainAxisMarginBetweenViews(child, next); |
height += extra_height; |
} |
@@ -304,15 +590,42 @@ gfx::Size BoxLayout::GetPreferredSizeForChildWidth(const View* host, |
child_area_bounds.set_height(height); |
} |
- gfx::Size non_child_size = NonChildSize(host); |
+ gfx::Size non_child_size = NonChildSize(host_); |
return gfx::Size(child_area_bounds.width() + non_child_size.width(), |
child_area_bounds.height() + non_child_size.height()); |
} |
gfx::Size BoxLayout::NonChildSize(const View* host) const { |
gfx::Insets insets(host->GetInsets()); |
- return gfx::Size(insets.width() + inside_border_insets_.width(), |
- insets.height() + inside_border_insets_.height()); |
+ if (!collapse_margins_spacing_) |
+ return gfx::Size(insets.width() + inside_border_insets_.width(), |
+ insets.height() + inside_border_insets_.height()); |
+ gfx::Insets main_axis = MainAxisOuterMargin(); |
+ gfx::Insets cross_axis = inside_border_insets_; |
+ return gfx::Size(insets.width() + main_axis.width() + cross_axis.width(), |
+ insets.height() + main_axis.height() + cross_axis.height()); |
+} |
+ |
+View* BoxLayout::NextVisibleView(int index) const { |
+ for (int i = index + 1; i < host_->child_count(); ++i) { |
+ View* result = host_->child_at(i); |
+ if (result->visible()) |
+ return result; |
+ } |
+ return nullptr; |
+} |
+ |
+View* BoxLayout::FirstVisibleView() const { |
+ return NextVisibleView(-1); |
+} |
+ |
+View* BoxLayout::LastVisibleView() const { |
+ for (int i = host_->child_count() - 1; i >= 0; --i) { |
+ View* result = host_->child_at(i); |
+ if (result->visible()) |
+ return result; |
+ } |
+ return nullptr; |
} |
} // namespace views |