chromium/ash/system/unified/feature_pod_button.h

// Copyright 2018 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_SYSTEM_UNIFIED_FEATURE_POD_BUTTON_H_
#define ASH_SYSTEM_UNIFIED_FEATURE_POD_BUTTON_H_

#include "ash/ash_export.h"
#include "ash/style/icon_button.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/vector_icon_types.h"
#include "ui/views/view.h"

namespace views {
class ImageView;
class Label;
}

namespace ash {

class FeaturePodControllerBase;

// TODO(crbug.com/40808951): Remove FeaturePodIconButton after the migration.
// A toggle button with an icon used by feature pods and in other places.
class ASH_EXPORT FeaturePodIconButton : public IconButton {
  METADATA_HEADER(FeaturePodIconButton, IconButton)

 public:
  FeaturePodIconButton(PressedCallback callback, bool is_togglable);
  FeaturePodIconButton(const FeaturePodIconButton&) = delete;
  FeaturePodIconButton& operator=(const FeaturePodIconButton&) = delete;
  ~FeaturePodIconButton() override;
};

// Button internally used in FeaturePodButton. Should not be used directly.
class ASH_EXPORT FeaturePodLabelButton : public views::Button {
  METADATA_HEADER(FeaturePodLabelButton, views::Button)

 public:
  explicit FeaturePodLabelButton(PressedCallback callback);

  FeaturePodLabelButton(const FeaturePodLabelButton&) = delete;
  FeaturePodLabelButton& operator=(const FeaturePodLabelButton&) = delete;

  ~FeaturePodLabelButton() override;

  // Set the text of label shown below the icon. See FeaturePodButton::SetLabel.
  void SetLabel(const std::u16string& label);
  const std::u16string& GetLabelText() const;

  // Set the text of sub-label shown below the label.
  // See FeaturePodButton::SetSubLabel.
  void SetSubLabel(const std::u16string& sub_label);
  const std::u16string& GetSubLabelText() const;

  // Show arrow to indicate that the feature has a detailed view.
  // See FeaturePodButton::ShowDetailedViewArrow.
  void ShowDetailedViewArrow();

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

 private:
  // Layout |child| in horizontal center with its vertical origin set to |y|.
  void LayoutInCenter(views::View* child, int y);

  // views::Button:
  void OnEnabledChanged() override;

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

// A button in FeaturePodsView. These buttons are main entry points of features
// in UnifiedSystemTray. Each button has its icon, label, and sub-label placed
// vertically. The button may be togglable and the background color indicates
// the current state. Otherwise, the button is not a toggle button and just
// navigates to the appropriate detailed view.
// See the comment in FeaturePodsView for detail.
class ASH_EXPORT FeaturePodButton : public views::View {
  METADATA_HEADER(FeaturePodButton, views::View)

 public:
  explicit FeaturePodButton(FeaturePodControllerBase* controller,
                            bool is_togglable = true);

  FeaturePodButton(const FeaturePodButton&) = delete;
  FeaturePodButton& operator=(const FeaturePodButton&) = delete;

  ~FeaturePodButton() override;

  // Set the vector icon shown in a circle.
  void SetVectorIcon(const gfx::VectorIcon& icon);

  // Set the text of label shown below the icon.
  void SetLabel(const std::u16string& label);

  // Set the text of sub-label shown below the label.
  void SetSubLabel(const std::u16string& sub_label);

  // Set the tooltip text of the icon button.
  void SetIconTooltip(const std::u16string& text);

  // Set the tooltip text of the label button.
  void SetLabelTooltip(const std::u16string& text);

  // Convenience method to set both icon and label tooltip texts.
  void SetIconAndLabelTooltips(const std::u16string& text);

  // Show arrow to indicate that the feature has a detailed view.
  void ShowDetailedViewArrow();

  // Remove the label button from keyboard focus chain. This is useful when
  // the icon button and the label button has the same action.
  void DisableLabelButtonFocus();

  // Change the toggled state. If toggled, the background color of the circle
  // will change. If the button is not togglable, then SetToggled() will do
  // nothing and |IsToggled()| will always return false.
  void SetToggled(bool toggled);
  bool IsToggled() const { return icon_button_->toggled(); }

  // Change the expanded state. 0.0 if collapsed, and 1.0 if expanded.
  // Otherwise, it shows intermediate state. In the collapsed state, the labels
  // are not shown, so the label buttons always fade out as expanded_amount
  // decreases. We also need to fade out the icon button when it's not part of
  // the buttons visible in the collapsed state. fade_icon_button will be passed
  // as true for these cases.
  void SetExpandedAmount(double expanded_amount, bool fade_icon_button);

  // Get opacity for a given expanded_amount value. Used to fade out
  // all label buttons and icon buttons that are hidden in collapsed state
  // while collapsing.
  double GetOpacityForExpandedAmount(double expanded_amount);

  // Only called by the container. Same as SetVisible but doesn't change
  // |visible_preferred_| flag.
  void SetVisibleByContainer(bool visible);

  // views::View:
  void SetVisible(bool visible) override;
  bool HasFocus() const override;
  void RequestFocus() override;

  bool visible_preferred() const { return visible_preferred_; }

  FeaturePodIconButton* icon_button() const { return icon_button_; }
  FeaturePodLabelButton* label_button() const { return label_button_; }

 private:
  // For unit tests.
  friend class BluetoothFeaturePodControllerTest;
  friend class NetworkFeaturePodControllerTest;
  friend class NightLightFeaturePodControllerTest;

  void OnEnabledChanged();

  // Owned by views hierarchy.
  const raw_ptr<FeaturePodIconButton> icon_button_;
  const raw_ptr<FeaturePodLabelButton> label_button_;

  // If true, it is preferred by the FeaturePodController that the view is
  // visible. Usually, this should match visible(), but in case that the
  // container does not have enough space, it might not match.
  // In such case, the preferred visibility is reflected after the container is
  // expanded.
  bool visible_preferred_ = true;

  base::CallbackListSubscription enabled_changed_subscription_ =
      AddEnabledChangedCallback(
          base::BindRepeating(&FeaturePodButton::OnEnabledChanged,
                              base::Unretained(this)));
};

}  // namespace ash

#endif  // ASH_SYSTEM_UNIFIED_FEATURE_POD_BUTTON_H_