Commit f0f21462 authored by Jan Krcal's avatar Jan Krcal Committed by Commit Bot

[LabelButton] Support fading out text using AnimatingLayoutManager

This CL adds support for fading out text of LabelButton using
AnimatingLayoutManager. Concretely, when ShrinkDownThenClearText() gets
called, the button reports a new desired size without it's label. The
AnimatingLayoutManager can then resize the button using an animation
to its newly desired size while the label is still (partially) visible.
Once the animation is finished, the button clears its label.

This CL directly makes use of this functionality for ToolbarButton.

Bug: 1002160
Change-Id: Id2569d4c58497ccb3198ca70a01cc2d7eb270a2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1810977
Commit-Queue: Jan Krcal <jkrcal@chromium.org>
Reviewed-by: default avatarPeter Boström <pbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#699252}
parent 76604066
......@@ -120,10 +120,7 @@ void ToolbarButton::SetText(const base::string16& text) {
void ToolbarButton::ClearHighlight() {
highlight_color_animation_.Hide();
// TODO(crbug.com/1002160): Support AnimatingLayoutManager by reporting
// preferred size without the label, clear the label only once the layout
// animation is completed.
LabelButton::SetText(base::string16());
ShrinkDownThenClearText();
}
void ToolbarButton::UpdateColorsAndInsets() {
......
......@@ -74,6 +74,16 @@ void LabelButton::SetText(const base::string16& text) {
SetTextInternal(text);
}
void LabelButton::ShrinkDownThenClearText() {
if (GetText().empty())
return;
// First, we recalculate preferred size for the new mode (without the label).
shrinking_down_label_ = true;
PreferredSizeChanged();
// Second, we clear the label right away if the button is already small.
ClearTextIfShrunkDown();
}
void LabelButton::SetTextColor(ButtonState for_state, SkColor color) {
button_state_colors_[for_state] = color;
if (for_state == STATE_DISABLED)
......@@ -178,16 +188,26 @@ void LabelButton::SetBorder(std::unique_ptr<Border> border) {
ResetCachedPreferredSize();
}
void LabelButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
ClearTextIfShrunkDown();
Button::OnBoundsChanged(previous_bounds);
}
gfx::Size LabelButton::CalculatePreferredSize() const {
// Cache the computed size, as recomputing it is an expensive operation.
if (!cached_preferred_size_) {
const gfx::Size preferred_label_size = label_->GetPreferredSize();
gfx::Size size = GetUnclampedSizeWithoutLabel();
// Disregard label in the preferred size if the button is shrinking down to
// show no label soon.
if (!shrinking_down_label_) {
const gfx::Size preferred_label_size = label_->GetPreferredSize();
size.Enlarge(preferred_label_size.width(), 0);
// Increase the height of the label (with insets) if larger.
size.set_height(std::max(
preferred_label_size.height() + GetInsets().height(), size.height()));
}
size.SetToMax(GetMinSize());
......@@ -475,11 +495,30 @@ void LabelButton::StateChanged(ButtonState old_state) {
void LabelButton::SetTextInternal(const base::string16& text) {
SetAccessibleName(text);
label_->SetText(text);
// Setting text cancels ShrinkDownThenClearText().
if (shrinking_down_label_) {
shrinking_down_label_ = false;
PreferredSizeChanged();
}
// TODO(pkasting): Remove this and forward callback subscriptions to the
// underlying label property when Label is converted to properties.
OnPropertyChanged(label_, kPropertyEffectsNone);
}
void LabelButton::ClearTextIfShrunkDown() {
if (!cached_preferred_size_)
CalculatePreferredSize();
if (shrinking_down_label_ && width() <= cached_preferred_size_->width() &&
height() <= cached_preferred_size_->height()) {
// Once the button shrinks down to its preferred size (that disregards the
// current text), we finish the operation by clearing the text.
shrinking_down_label_ = false;
SetTextInternal(base::string16());
}
}
void LabelButton::ResetCachedPreferredSize() {
cached_preferred_size_ = base::nullopt;
}
......
......@@ -48,6 +48,15 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
base::string16 GetText() const;
virtual void SetText(const base::string16& text);
// Makes the button report its preferred size without the label. This lets
// AnimatingLayoutManager gradually shrink the button until the text is
// invisible, at which point the text gets cleared. Think of this as
// transitioning from the current text to SetText("").
// Note that the layout manager (or manual SetBounds calls) need to be
// configured to eventually hit the the button's preferred size (or smaller)
// or the text will never be cleared.
void ShrinkDownThenClearText();
// Sets the text color shown for the specified button |for_state| to |color|.
void SetTextColor(ButtonState for_state, SkColor color);
......@@ -88,6 +97,7 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
// Button:
void SetBorder(std::unique_ptr<Border> border) override;
void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
gfx::Size CalculatePreferredSize() const override;
int GetHeightForWidth(int w) const override;
void Layout() override;
......@@ -157,6 +167,8 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
private:
void SetTextInternal(const base::string16& text);
void ClearTextIfShrunkDown();
// Resets |cached_preferred_size_|.
void ResetCachedPreferredSize();
......@@ -202,6 +214,11 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
// Cache the last computed preferred size.
mutable base::Optional<gfx::Size> cached_preferred_size_;
// A flag indicating that this button should not include the label in its
// desired size. Furthermore, once the bounds of the button adapt to this
// desired size, the text in the label should get cleared.
bool shrinking_down_label_ = false;
// Flag indicating default handling of the return key via an accelerator.
// Whether or not the button appears or behaves as the default button in its
// current context;
......
......@@ -172,6 +172,92 @@ TEST_F(LabelButtonTest, Label) {
gfx::Size(long_text_width, font_list.GetHeight() * 2));
}
TEST_F(LabelButtonTest, LabelShrinkDown) {
ASSERT_TRUE(button_->GetText().empty());
const gfx::FontList font_list = button_->label()->font_list();
const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
const int text_width = gfx::GetStringWidth(text, font_list);
ASSERT_LT(button_->GetPreferredSize().width(), text_width);
button_->SetText(text);
EXPECT_GT(button_->GetPreferredSize().width(), text_width);
button_->SetSize(button_->GetPreferredSize());
// When shrinking, the button should report again the size with no label
// (while keeping the label).
button_->ShrinkDownThenClearText();
EXPECT_EQ(button_->GetText(), text);
EXPECT_LT(button_->GetPreferredSize().width(), text_width);
// After the layout manager resizes the button to it's desired size, it's text
// should be empty again.
button_->SetSize(button_->GetPreferredSize());
EXPECT_TRUE(button_->GetText().empty());
}
TEST_F(LabelButtonTest, LabelShrinksDownOnManualSetBounds) {
ASSERT_TRUE(button_->GetText().empty());
ASSERT_GT(button_->GetPreferredSize().width(), 1);
const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
button_->SetText(text);
EXPECT_EQ(button_->GetText(), text);
button_->SetSize(button_->GetPreferredSize());
button_->SetBoundsRect(gfx::Rect(button_->GetPreferredSize()));
button_->ShrinkDownThenClearText();
// Manually setting a smaller size should also clear text.
button_->SetBoundsRect(gfx::Rect(1, 1));
EXPECT_TRUE(button_->GetText().empty());
}
TEST_F(LabelButtonTest, LabelShrinksDownCanceledBySettingText) {
ASSERT_TRUE(button_->GetText().empty());
const gfx::FontList font_list = button_->label()->font_list();
const base::string16 text(ASCIIToUTF16("abcdefghijklm"));
const int text_width = gfx::GetStringWidth(text, font_list);
ASSERT_LT(button_->GetPreferredSize().width(), text_width);
button_->SetText(text);
EXPECT_GT(button_->GetPreferredSize().width(), text_width);
button_->SetBoundsRect(gfx::Rect(button_->GetPreferredSize()));
// When shrinking, the button should report again the size with no label
// (while keeping the label).
button_->ShrinkDownThenClearText();
EXPECT_EQ(button_->GetText(), text);
gfx::Size shrinking_size = button_->GetPreferredSize();
EXPECT_LT(shrinking_size.width(), text_width);
// When we SetText() again, the shrinking gets canceled.
button_->SetText(text);
EXPECT_GT(button_->GetPreferredSize().width(), text_width);
// Even if the layout manager resizes the button to it's size desired for
// shrinking, it's text does not get cleared and it still prefers having space
// for its label.
button_->SetSize(shrinking_size);
EXPECT_FALSE(button_->GetText().empty());
EXPECT_GT(button_->GetPreferredSize().width(), text_width);
}
TEST_F(
LabelButtonTest,
LabelShrinksDownImmediatelyIfAlreadySmallerThanPreferredSizeWithoutLabel) {
button_->SetBoundsRect(gfx::Rect(1, 1));
button_->SetText(ASCIIToUTF16("abcdefghijklm"));
// Shrinking the text down when it's already shrunk down (its size is smaller
// than preferred without label) should clear the text immediately.
EXPECT_FALSE(button_->GetText().empty());
button_->ShrinkDownThenClearText();
EXPECT_TRUE(button_->GetText().empty());
}
// Test behavior of View::GetAccessibleNodeData() for buttons when setting a
// label.
TEST_F(LabelButtonTest, AccessibleState) {
......
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