chromium/ash/system/tray/hover_highlight_view.h

// Copyright 2013 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_TRAY_HOVER_HIGHLIGHT_VIEW_H_
#define ASH_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_

#include <memory>

#include "ash/ash_export.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/gfx/font.h"
#include "ui/gfx/text_constants.h"
#include "ui/views/controls/button/button.h"

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

namespace ash {
class TriView;
class ViewClickListener;

// A view that changes background color on hover, and triggers a callback in the
// associated ViewClickListener on click. The view can also be forced to
// maintain a fixed height.
class ASH_EXPORT HoverHighlightView : public views::Button {
  METADATA_HEADER(HoverHighlightView, views::Button)

 public:
  enum class AccessibilityState {
    // The default accessibility view.
    DEFAULT,
    // This view is a checked checkbox.
    CHECKED_CHECKBOX,
    // This view is an unchecked checkbox.
    UNCHECKED_CHECKBOX
  };

  // If |listener| is null then no action is taken on click.
  explicit HoverHighlightView(ViewClickListener* listener);

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

  ~HoverHighlightView() override;

  // Convenience function for populating the view with an icon and a label. This
  // also sets the accessible name. Primarily used for scrollable rows in
  // detailed views.
  // New callers should use the function below which takes an ImageModel.
  // TODO(b/259490845): Change callers to pass an ImageModel and eliminate this.
  void AddIconAndLabel(const gfx::ImageSkia& image, const std::u16string& text);

  // The same as the above function with `ImageModel` parameter instead.
  void AddIconAndLabel(const ui::ImageModel& image, const std::u16string& text);

  // Convenience function for populating the view with an arbitrary view and a
  // label. This also sets the accessible name.
  void AddViewAndLabel(std::unique_ptr<views::View> view,
                       const std::u16string& text);

  // Populates the view with a text label, inset on the left by the horizontal
  // space that would normally be occupied by an icon.
  void AddLabelRow(const std::u16string& text);

  // Populates the view with a text label with custom start inset.
  void AddLabelRow(const std::u16string& text, int start_inset);

  // Adds an optional right icon to an already populated view. |icon_size| is
  // the size of the icon in DP.
  void AddRightIcon(const ui::ImageModel& image, int icon_size);

  // Adds an optional right view to an already populated view.
  void AddRightView(views::View* view,
                    std::unique_ptr<views::Border> border = nullptr);

  // Adds an additional right view next to the `right_view_`.
  // TODO (b/266761290): Remove this method when it's not needed.
  void AddAdditionalRightView(views::View* view);

  // Hides or shows the right view for an already populated view.
  void SetRightViewVisible(bool visible);

  // Sets the text of the sub label for an already populated view. |sub_text|
  // must not be empty and prior to calling this function, |text_label_| must
  // not be null.
  void SetSubText(const std::u16string& sub_text);

  // Allows view to expand its height. Size of unexapandable view is fixed and
  // equals to kTrayPopupItemHeight.
  void SetExpandable(bool expandable);

  // Changes the view's current accessibility state. This will fire an
  // accessibility event if needed.
  void SetAccessibilityState(AccessibilityState accessibility_state);

  // Removes current children of the view so that it can be re-populated.
  void Reset();

  bool is_populated() const { return is_populated_; }

  views::ImageView* icon() { return icon_; }
  views::Label* text_label() { return text_label_; }
  views::Label* sub_text_label() { return sub_text_label_; }
  views::View* left_view() { return left_view_; }
  views::View* right_view() { return right_view_; }
  views::View* sub_row() { return sub_row_; }
  TriView* tri_view() { return tri_view_; }

 protected:
  // Override from Button to also set the tooltip for all child elements.
  void OnSetTooltipText(const std::u16string& tooltip_text) override;

 private:
  friend class TrayAccessibilityTest;

  void PerformAction();

  // views::View:
  gfx::Size CalculatePreferredSize(
      const views::SizeBounds& available_size) const override;
  void OnFocus() override;

  // Adds a view that acts as a container for all views that are added into the
  // sub-row, i.e. the row below the label.
  void AddSubRowContainer();

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

  void SetAndUpdateAccessibleDefaultAction();

  // Determines whether the view is populated or not. If it is, Reset() should
  // be called before re-populating the view.
  bool is_populated_ = false;

  const raw_ptr<ViewClickListener, DanglingUntriaged> listener_ = nullptr;
  raw_ptr<views::ImageView, DanglingUntriaged> icon_ = nullptr;
  raw_ptr<views::Label, DanglingUntriaged> text_label_ = nullptr;
  raw_ptr<views::Label, DanglingUntriaged> sub_text_label_ = nullptr;
  raw_ptr<views::View, DanglingUntriaged> left_view_ = nullptr;
  raw_ptr<views::View, DanglingUntriaged> right_view_ = nullptr;
  raw_ptr<views::View, DanglingUntriaged> sub_row_ = nullptr;
  raw_ptr<TriView, DanglingUntriaged> tri_view_ = nullptr;
  bool expandable_ = false;
  AccessibilityState accessibility_state_ = AccessibilityState::DEFAULT;
};

}  // namespace ash

#endif  // ASH_SYSTEM_TRAY_HOVER_HIGHLIGHT_VIEW_H_