chromium/ash/style/counter_expand_button.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_STYLE_COUNTER_EXPAND_BUTTON_H_
#define ASH_STYLE_COUNTER_EXPAND_BUTTON_H_

#include <string>

#include "ash/ash_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/metadata/view_factory.h"

namespace views {
class Label;
class ImageView;
}  // namespace views

namespace ash {

// Customized expand button for ash that contains a number counter that
// represents the number of children views and a chevron icon. Used for grouped
// bubble that are available for expanding and collapsing children views.
//  /------\
// |  5 \/  |
//  \------/

class ASH_EXPORT CounterExpandButton : public views::Button {
  METADATA_HEADER(CounterExpandButton, views::Button)
 public:
  // The type of animation. This is used for animation smoothness histograms.
  enum class AnimationType {
    // `label_` fading in animation.
    kFadeInLabel,
    // `label_` fading out animation.
    kFadeOutLabel,
    // Animating bounds change for the whole button layer.
    kBoundsChange,
  };

  CounterExpandButton();
  CounterExpandButton(const CounterExpandButton&) = delete;
  CounterExpandButton& operator=(const CounterExpandButton&) = delete;
  ~CounterExpandButton() override;

  void set_label_fading_out(bool label_fading_out) {
    label_fading_out_ = label_fading_out;
  }

  void set_previous_bounds(gfx::Rect previous_bounds) {
    previous_bounds_ = previous_bounds;
  }

  views::Label* label() { return label_; }

  // Changes the expanded state. The icon will change.
  void SetExpanded(bool expanded);
  bool expanded() const { return expanded_; }

  // Whether the label displaying the number of children in a grouped bubble
  // needs to be displayed.
  bool ShouldShowLabel() const;

  // Updates the count of total grouped child views in the parent container and
  // updates the text for the label accordingly.
  void UpdateCounter(int count);

  // Performs expand/collapse animation. This includes bounds change and fade
  // in/out `label_`.
  void AnimateExpandCollapse();

  // Returns the animation smoothness histogram name used for the animation type
  // `type`.
  virtual const std::string GetAnimationHistogramName(AnimationType type);

  // views::Button:
  void OnThemeChanged() override;
  gfx::Size CalculatePreferredSize(
      const views::SizeBounds& available_size) const override;

  size_t counter_for_test() const { return counter_; }

 protected:
  views::ImageView* image() { return image_; }

  // Bounds change animation happens during expand/collapse and converting from
  // single to group animation.
  void AnimateBoundsChange(int duration_in_ms,
                           gfx::Tween::Type tween_type,
                           const std::string& animation_histogram_name);

  // Generates the icons used for chevron in the expanded and collapsed state.
  void UpdateIcons();

  // Updates the tooltip of the button.
  void UpdateTooltip();

  // Returns the tooltip text on the button in expanded/collapsed state.
  virtual std::u16string GetExpandedStateTooltipText() const;
  virtual std::u16string GetCollapsedStateTooltipText() const;

 private:
  void UpdateBackgroundColor();

  // Owned by views hierarchy.
  raw_ptr<views::Label> label_;
  raw_ptr<views::ImageView> image_;

  // Cached icons used to display the chevron in the button.
  gfx::ImageSkia expanded_image_;
  gfx::ImageSkia collapsed_image_;

  // Used in layer bounds animation.
  gfx::Rect previous_bounds_;

  // The number shown on `label_`. This is used to show the total number of
  // grouped child views in this button's parent view.
  size_t counter_ = 0;

  // The expand state of the button.
  bool expanded_ = false;

  // True if `label_` is in its fade out animation.
  bool label_fading_out_ = false;

  base::WeakPtrFactory<CounterExpandButton> weak_factory_{this};
};

BEGIN_VIEW_BUILDER(/*no export*/, CounterExpandButton, views::Button)
END_VIEW_BUILDER

}  // namespace ash

DEFINE_VIEW_BUILDER(/* no export */, ash::CounterExpandButton)

#endif  // ASH_STYLE_COUNTER_EXPAND_BUTTON_H_