Commit ca90c90b authored by Dana Fried's avatar Dana Fried Committed by Commit Bot

Provide default flex rule for embedding flex layouts in each other.

This is a continuation of the pattern of
AnimatingLayoutManager::GetDefaultFlexRule().

Bug: 1048061
Change-Id: I0aaff55bea6c674b07b42abd4584092058b01df4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2040731
Commit-Queue: Dana Fried <dfried@chromium.org>
Reviewed-by: default avatarCaroline Rising <corising@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747147}
parent c4e94b8c
...@@ -401,6 +401,24 @@ class WebAppFrameToolbarView::ToolbarButtonContainer ...@@ -401,6 +401,24 @@ class WebAppFrameToolbarView::ToolbarButtonContainer
web_app_menu_button_->SetColor(foreground_color_); web_app_menu_button_->SetColor(foreground_color_);
} }
views::FlexRule GetFlexRule() const {
// Prefer height consistency over accommodating edge case icons that may
// bump up the container height (e.g. extension action icons with badges).
// TODO(https://crbug.com/889745): Fix the inconsistent icon sizes found in
// the right-hand container and turn this into a DCHECK that the container
// height is the same as the app menu button height.
const auto* const layout =
static_cast<views::FlexLayout*>(GetLayoutManager());
return base::BindRepeating(
[](WebAppMenuButton* menu_button, views::FlexRule input_flex_rule,
const views::View* view, const views::SizeBounds& available_size) {
const gfx::Size preferred = input_flex_rule.Run(view, available_size);
return gfx::Size(preferred.width(),
menu_button->GetPreferredSize().height());
},
base::Unretained(web_app_menu_button_), layout->GetDefaultFlexRule());
}
ContentSettingsContainer* content_settings_container() { ContentSettingsContainer* content_settings_container() {
return content_settings_container_; return content_settings_container_;
} }
...@@ -444,17 +462,6 @@ class WebAppFrameToolbarView::ToolbarButtonContainer ...@@ -444,17 +462,6 @@ class WebAppFrameToolbarView::ToolbarButtonContainer
content_settings_container_->FadeIn(); content_settings_container_->FadeIn();
} }
// views::View:
gfx::Size CalculatePreferredSize() const override {
// Prefer height consistency over accommodating edge case icons that may
// bump up the container height (e.g. extension action icons with badges).
// TODO(https://crbug.com/889745): Fix the inconsistent icon sizes found in
// the right-hand container and turn this into a DCHECK that the container
// height is the same as the app menu button height.
return gfx::Size(views::View::CalculatePreferredSize().width(),
web_app_menu_button_->GetPreferredSize().height());
}
void ChildPreferredSizeChanged(views::View* child) override { void ChildPreferredSizeChanged(views::View* child) override {
PreferredSizeChanged(); PreferredSizeChanged();
} }
...@@ -717,9 +724,7 @@ WebAppFrameToolbarView::WebAppFrameToolbarView(views::Widget* widget, ...@@ -717,9 +724,7 @@ WebAppFrameToolbarView::WebAppFrameToolbarView(views::Widget* widget,
std::make_unique<ToolbarButtonContainer>(widget, browser_view)); std::make_unique<ToolbarButtonContainer>(widget, browser_view));
right_container_->SetProperty( right_container_->SetProperty(
views::kFlexBehaviorKey, views::kFlexBehaviorKey,
views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToMinimum, views::FlexSpecification(right_container_->GetFlexRule()).WithOrder(1));
views::MaximumFlexSizeRule::kPreferred)
.WithOrder(1));
UpdateStatusIconsVisibility(); UpdateStatusIconsVisibility();
......
...@@ -22,14 +22,6 @@ namespace views { ...@@ -22,14 +22,6 @@ namespace views {
namespace { namespace {
// Returns true if the specified |size| can fit in the specified |bounds|.
// Returns false if either the width or height of |bounds| is specified and is
// smaller than the corresponding element of |size|.
bool CanFitInBounds(const gfx::Size& size, const SizeBounds& bounds) {
return (!bounds.width() || (*bounds.width() >= size.width())) &&
(!bounds.height() || (*bounds.height() >= size.height()));
}
// Returns the ChildLayout data for the child view in the proposed layout, or // Returns the ChildLayout data for the child view in the proposed layout, or
// nullptr if not found. // nullptr if not found.
const ChildLayout* FindChildViewInLayout(const ProposedLayout& layout, const ChildLayout* FindChildViewInLayout(const ProposedLayout& layout,
......
...@@ -363,6 +363,11 @@ FlexLayout& FlexLayout::SetFlexAllocationOrder( ...@@ -363,6 +363,11 @@ FlexLayout& FlexLayout::SetFlexAllocationOrder(
return *this; return *this;
} }
FlexRule FlexLayout::GetDefaultFlexRule() const {
return base::BindRepeating(&FlexLayout::DefaultFlexRuleImpl,
base::Unretained(this));
}
ProposedLayout FlexLayout::CalculateProposedLayout( ProposedLayout FlexLayout::CalculateProposedLayout(
const SizeBounds& size_bounds) const { const SizeBounds& size_bounds) const {
FlexLayoutData data; FlexLayoutData data;
...@@ -856,4 +861,15 @@ void FlexLayout::AllocateFlexSpace( ...@@ -856,4 +861,15 @@ void FlexLayout::AllocateFlexSpace(
} }
} }
// static
gfx::Size FlexLayout::DefaultFlexRuleImpl(const FlexLayout* flex_layout,
const View* view,
const SizeBounds& size_bounds) {
if (size_bounds == SizeBounds())
return flex_layout->GetPreferredSize(view);
if (size_bounds == SizeBounds(0, 0))
return flex_layout->GetMinimumSize(view);
return flex_layout->CalculateProposedLayout(size_bounds).host_size;
}
} // namespace views } // namespace views
...@@ -105,6 +105,10 @@ class VIEWS_EXPORT FlexLayout : public LayoutManagerBase { ...@@ -105,6 +105,10 @@ class VIEWS_EXPORT FlexLayout : public LayoutManagerBase {
return flex_allocation_order_; return flex_allocation_order_;
} }
// Returns a flex rule that allows flex layouts to be nested with expected
// behavior.
FlexRule GetDefaultFlexRule() const;
// Moves and uses |value| as the default value for layout property |key|. // Moves and uses |value| as the default value for layout property |key|.
template <class T, class U> template <class T, class U>
FlexLayout& SetDefault(const ui::ClassProperty<T>* key, U&& value) { FlexLayout& SetDefault(const ui::ClassProperty<T>* key, U&& value) {
...@@ -243,6 +247,10 @@ class VIEWS_EXPORT FlexLayout : public LayoutManagerBase { ...@@ -243,6 +247,10 @@ class VIEWS_EXPORT FlexLayout : public LayoutManagerBase {
return *this; return *this;
} }
static gfx::Size DefaultFlexRuleImpl(const FlexLayout* flex_layout,
const View* view,
const SizeBounds& size_bounds);
LayoutOrientation orientation_ = LayoutOrientation::kHorizontal; LayoutOrientation orientation_ = LayoutOrientation::kHorizontal;
// Adjacent view margins should be collapsed. // Adjacent view margins should be collapsed.
......
...@@ -2939,4 +2939,68 @@ TEST_F(NestedFlexLayoutTest, Layout_Flex) { ...@@ -2939,4 +2939,68 @@ TEST_F(NestedFlexLayoutTest, Layout_Flex) {
EXPECT_EQ(gfx::Rect(6, 2, 1, 6), grandchild(2, 2)->bounds()); EXPECT_EQ(gfx::Rect(6, 2, 1, 6), grandchild(2, 2)->bounds());
} }
TEST_F(NestedFlexLayoutTest, UsingDefaultFlexRule) {
AddChildren(2);
AddGrandchild(1, gfx::Size(5, 5));
AddGrandchild(2, gfx::Size(5, 5));
AddGrandchild(2, gfx::Size(5, 5));
child(1)->SetProperty(
kFlexBehaviorKey,
FlexSpecification(layout(1)->GetDefaultFlexRule()).WithOrder(2));
child(2)->SetProperty(kFlexBehaviorKey,
FlexSpecification(layout(2)->GetDefaultFlexRule()));
grandchild(1, 1)->SetProperty(kFlexBehaviorKey, kUnboundedScaleToZero);
grandchild(2, 1)->SetProperty(kFlexBehaviorKey, kDropOut);
grandchild(2, 2)->SetProperty(kFlexBehaviorKey, kDropOut);
// Extra flex space is allocated to the first child view.
host_->SetSize(gfx::Size(17, 5));
host_->Layout();
EXPECT_TRUE(child(1)->GetVisible());
EXPECT_EQ(gfx::Size(7, 5), child(1)->size());
EXPECT_TRUE(grandchild(1, 1)->GetVisible());
EXPECT_EQ(gfx::Size(7, 5), grandchild(1, 1)->size());
EXPECT_TRUE(child(2)->GetVisible());
EXPECT_EQ(gfx::Size(10, 5), child(2)->size());
EXPECT_TRUE(grandchild(2, 1)->GetVisible());
EXPECT_EQ(gfx::Size(5, 5), grandchild(2, 1)->size());
EXPECT_TRUE(grandchild(2, 2)->GetVisible());
EXPECT_EQ(gfx::Size(5, 5), grandchild(2, 2)->size());
// Leftover flex space is still allocated to the first child view even after
// one of the grandchildren drops out.
host_->SetSize(gfx::Size(8, 5));
host_->Layout();
EXPECT_TRUE(child(1)->GetVisible());
EXPECT_EQ(gfx::Size(3, 5), child(1)->size());
EXPECT_TRUE(grandchild(1, 1)->GetVisible());
EXPECT_EQ(gfx::Size(3, 5), grandchild(1, 1)->size());
EXPECT_TRUE(child(2)->GetVisible());
EXPECT_EQ(gfx::Size(5, 5), child(2)->size());
EXPECT_TRUE(grandchild(2, 1)->GetVisible());
EXPECT_EQ(gfx::Size(5, 5), grandchild(2, 1)->size());
EXPECT_FALSE(grandchild(2, 2)->GetVisible());
// Leftover flex space is still allocated to the first child view even after
// two of the grandchildren drop out.
host_->SetSize(gfx::Size(4, 5));
host_->Layout();
EXPECT_TRUE(child(1)->GetVisible());
EXPECT_EQ(gfx::Size(4, 5), child(1)->size());
EXPECT_TRUE(grandchild(1, 1)->GetVisible());
EXPECT_EQ(gfx::Size(4, 5), grandchild(1, 1)->size());
EXPECT_FALSE(child(2)->GetVisible());
// If there is no leftover space, the first child view is hidden.
host_->SetSize(gfx::Size(5, 5));
host_->Layout();
EXPECT_FALSE(child(1)->GetVisible());
EXPECT_TRUE(child(2)->GetVisible());
EXPECT_EQ(gfx::Size(5, 5), child(2)->size());
EXPECT_TRUE(grandchild(2, 1)->GetVisible());
EXPECT_EQ(gfx::Size(5, 5), grandchild(2, 1)->size());
EXPECT_FALSE(grandchild(2, 2)->GetVisible());
}
} // namespace views } // namespace views
...@@ -23,4 +23,9 @@ std::string SizeBounds::ToString() const { ...@@ -23,4 +23,9 @@ std::string SizeBounds::ToString() const {
height_ ? base::NumberToString(*height_) : "_"}); height_ ? base::NumberToString(*height_) : "_"});
} }
bool CanFitInBounds(const gfx::Size& size, const SizeBounds& bounds) {
return (!bounds.width() || (*bounds.width() >= size.width())) &&
(!bounds.height() || (*bounds.height() >= size.height()));
}
} // namespace views } // namespace views
...@@ -82,6 +82,11 @@ constexpr bool operator<(const SizeBounds& lhs, const SizeBounds& rhs) { ...@@ -82,6 +82,11 @@ constexpr bool operator<(const SizeBounds& lhs, const SizeBounds& rhs) {
std::tie(rhs.height(), rhs.width()); std::tie(rhs.height(), rhs.width());
} }
// Returns true if the specified |size| can fit in the specified |bounds|.
// Returns false if either the width or height of |bounds| is specified and is
// smaller than the corresponding element of |size|.
bool CanFitInBounds(const gfx::Size& size, const SizeBounds& bounds);
// These are declared here for use in gtest-based unit tests but is defined in // These are declared here for use in gtest-based unit tests but is defined in
// the views_test_support target. Depend on that to use this in your unit test. // the views_test_support target. Depend on that to use this in your unit test.
// This should not be used in production code - call ToString() instead. // This should not be used in production code - call ToString() instead.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment