chromium/ash/style/tab_slider_button.h

// Copyright 2022 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_TAB_SLIDER_BUTTON_H_
#define ASH_STYLE_TAB_SLIDER_BUTTON_H_

#include <string>

#include "ash/ash_export.h"
#include "ash/style/tab_slider.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/color/color_id.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/image_view.h"

namespace gfx {
struct VectorIcon;
}  // namespace gfx

namespace views {
class Label;
}  // namespace views

namespace ash {

// A base class for tab slider buttons used in `TabSlider`. The button has
// selected and unselected states. When clicking the button, it will be set to
// selected. After a button is added to a tab slider, selecting the button will
// deselect the other buttons in the tab slider.
class ASH_EXPORT TabSliderButton : public views::Button {
  METADATA_HEADER(TabSliderButton, views::Button)

 public:
  TabSliderButton(PressedCallback callback, const std::u16string& tooltip_text);
  TabSliderButton(const TabSliderButton&) = delete;
  TabSliderButton& operator=(const TabSliderButton&) = delete;
  ~TabSliderButton() override;

  bool selected() const { return selected_; }

  // Called when the button is added to a tab slider.
  void AddedToSlider(TabSlider* tab_slider);

  // Changes the selected state.
  void SetSelected(bool selected);

  // Returns the recommended color id for the current button state.
  SkColor GetColorIdOnButtonState();

 private:
  // Called when the button selected state is changed.
  virtual void OnSelectedChanged() = 0;

  // views::Button:
  void NotifyClick(const ui::Event& event) override;

  // Not owned by button.
  raw_ptr<TabSlider> tab_slider_ = nullptr;
  // The selected state indicating if the button is selected.
  bool selected_ = false;
};

// An extension of `TabSliderButton` which is a circle button with an icon in
// the center. The icon has different color schemes for selected, unselected,
// and disabled states.
class ASH_EXPORT IconSliderButton : public TabSliderButton {
  METADATA_HEADER(IconSliderButton, TabSliderButton)

 public:
  IconSliderButton(PressedCallback callback,
                   const gfx::VectorIcon* icon,
                   const std::u16string& tooltip_text_base = u"");
  IconSliderButton(const IconSliderButton&) = delete;
  IconSliderButton& operator=(const IconSliderButton&) = delete;
  ~IconSliderButton() override;

 private:
  // TabSliderButton:
  void OnSelectedChanged() override;

  // views::Button:
  void OnThemeChanged() override;
  void PaintButtonContents(gfx::Canvas* canvas) override;

  const raw_ptr<const gfx::VectorIcon> icon_;
};

// An extension of `TabSliderButton` which is rounded rect button with a label
// in the center. The label text has different color schemes for selected,
// unselected, and disabled states.
class ASH_EXPORT LabelSliderButton : public TabSliderButton {
  METADATA_HEADER(LabelSliderButton, TabSliderButton)

 public:
  LabelSliderButton(PressedCallback callback,
                    const std::u16string& text,
                    const std::u16string& tooltip_text_base = u"");
  LabelSliderButton(const LabelSliderButton&) = delete;
  LabelSliderButton& operator=(const LabelSliderButton&) = delete;
  ~LabelSliderButton() override;

 private:
  // Update label color according to the current button state.
  void UpdateLabelColor();

  // TabSliderButton:
  void OnSelectedChanged() override;

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

  // Owned by the view hierarchy.
  raw_ptr<views::Label> label_;
};

// A `TabSliderButton` which shows an icon either:
// - Next to a label (`horizontal == true`).
// - Above a label (`horizontal == false`).
class ASH_EXPORT IconLabelSliderButton : public TabSliderButton {
  METADATA_HEADER(IconLabelSliderButton, TabSliderButton)

 public:
  static constexpr TabSlider::InitParams kSliderParams{
      /*internal_border_padding=*/4,
      /*between_child_spacing=*/0,
      /*has_background=*/true,
      /*has_selector_animation=*/true,
      /*distribute_space_evenly=*/true};

  IconLabelSliderButton(PressedCallback callback,
                        const gfx::VectorIcon* icon,
                        const std::u16string& text,
                        const std::u16string& tooltip_text_base = u"",
                        bool horizontal = false);
  IconLabelSliderButton(const IconLabelSliderButton&) = delete;
  IconLabelSliderButton& operator=(const IconLabelSliderButton&) = delete;
  ~IconLabelSliderButton() override;

 private:
  // Update label color according to the current button state.
  void UpdateColors();

  // TabSliderButton:
  void OnSelectedChanged() override;

  // Owned by the views hierarchy.
  const raw_ptr<views::ImageView> image_view_;
  const raw_ptr<views::Label> label_;
};

}  // namespace ash

#endif  // ASH_STYLE_TAB_SLIDER_BUTTON_H_