File: rich_hover_button.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (174 lines) | stat: -rw-r--r-- 6,718 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_VIEWS_CONTROLS_RICH_HOVER_BUTTON_H_
#define CHROME_BROWSER_UI_VIEWS_CONTROLS_RICH_HOVER_BUTTON_H_

#include <string_view>
#include <vector>

#include "base/containers/extend.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ui/views/controls/hover_button.h"
#include "ui/views/metadata/view_factory.h"

namespace test {
class PageInfoBubbleViewTestApi;
}  // namespace test

namespace ui {
class ImageModel;
}  // namespace ui

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

// Hoverable button containing various components:
// *--------------------------------------------------------*
// | Icon | Title               | State image | Action icon |
// |--------------------------------------------------------|
// |      | Custom view         |             |             |
// |--------------------------------------------------------|
// |      | Subtitle            |             |             |
// |      | (multiline)         |             |             |
// *--------------------------------------------------------*
//
// 'RichHoverButton' inherits the interaction behavior from 'HoverButton'
// but sets up its own layout and content.
// TODO(pkasting): This class should subclass Button, not HoverButton.
class RichHoverButton : public HoverButton {
  METADATA_HEADER(RichHoverButton, HoverButton)

 public:
  RichHoverButton();
  RichHoverButton(views::Button::PressedCallback callback,
                  ui::ImageModel icon,
                  std::u16string_view title_text,
                  std::u16string_view subtitle_text,
                  ui::ImageModel action_icon = ui::ImageModel(),
                  ui::ImageModel state_icon = ui::ImageModel());

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

  ~RichHoverButton() override;

  ui::ImageModel GetIcon() const;
  void SetIcon(ui::ImageModel icon);

  std::u16string_view GetTitleText() const;
  void SetTitleText(std::u16string_view title_text);

  ui::ImageModel GetStateIcon() const;
  void SetStateIcon(ui::ImageModel state_icon);

  ui::ImageModel GetActionIcon() const;
  void SetActionIcon(ui::ImageModel action_icon);

  std::u16string_view GetSubtitleText() const;
  void SetSubtitleText(std::u16string_view subtitle_text);

  bool GetSubtitleMultiline() const;
  void SetSubtitleMultiline(bool subtitle_multiline);

  // TODO(crbug.com/40281048): Remove; at least color, and possibly both of
  // these, should instead be computed automatically from a single context value
  // on the button.
  void SetTitleTextStyleAndColor(int style, ui::ColorId);
  void SetSubtitleTextStyleAndColor(int style, ui::ColorId);

  // Sets the custom view. Pass an empty `std::unique_ptr<views::View>` to
  // reset.
  template <typename T>
  T* SetCustomView(std::unique_ptr<T> custom_view) {
    T* view = nullptr;
    if (!custom_view) {
      for (const auto& v : custom_view_row_views_) {
        RemoveChildViewT(v);
      }
      custom_view_row_views_.clear();
    } else if (custom_view_row_views_.empty()) {
      size_t start = custom_view_row_start_;
      custom_view_row_views_.push_back(AddChildViewAt(
          std::make_unique<views::View>(), start++));  // Skip main icon column.
      view = AddChildViewAt(std::move(custom_view), start++);
      custom_view_row_views_.push_back(view);
      base::Extend(custom_view_row_views_, AddFillerViews(start));
    } else {
      CHECK_GT(custom_view_row_views_.size(), 1u);
      RemoveChildViewT(custom_view_row_views_[1]);
      view = AddChildViewAt(std::move(custom_view), custom_view_row_start_ + 1);
      custom_view_row_views_[1] = view;
    }

    RecreateLayout();
    return view;
  }

 protected:
  // HoverButton:
  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
  views::View* GetTooltipHandlerForPoint(const gfx::Point& point) override;
  gfx::Size CalculatePreferredSize(
      const views::SizeBounds& available_size) const override;

 private:
  // Updates the image at `icon_member`, which corresponds to child
  // `child_index`, to be `icon`. If `icon` is empty, the member will be set to
  // null. If `use_placeholder` is true, empty `View`s are inserted (instead of
  // nothing) when the provided image is empty, to avoid changing the columns of
  // items in the table.
  void SetIconMember(raw_ptr<views::ImageView>& icon_member,
                     size_t child_index,
                     ui::ImageModel icon,
                     bool use_placeholder);

  // Recreates the table layout, which must be done any time the custom view or
  // subtitle change between empty and non-empty (since those rows are not
  // filled with placeholder `View`s when absent).
  // TODO(pkasting): This class should lay out using box, not table, with
  // top-aligned children, and add enough padding to the
  // icons/custom view/subtitle to properly align with the title. That would
  // obviate the need to recreate the layout after construction.
  void RecreateLayout();

  // Recomputes the accessible name, which is affected by both labels.
  void UpdateAccessibleName();

  // Adds filler views for state icon (if set) and action icon columns. Used for
  // the table rows after the first one.
  std::vector<raw_ptr<views::View>> AddFillerViews(size_t start);

  size_t start_;
  // `ImageView` pointers and `subtitle` are non-null only if present.
  raw_ptr<views::ImageView> icon_ = nullptr;
  raw_ptr<views::Label> title_;  // Never null.
  raw_ptr<views::ImageView> state_icon_ = nullptr;
  raw_ptr<views::ImageView> action_icon_ = nullptr;
  size_t custom_view_row_start_;
  std::vector<raw_ptr<views::View>> custom_view_row_views_;
  std::vector<raw_ptr<views::View>> subtitle_row_views_;
  raw_ptr<views::Label> subtitle_ = nullptr;
  bool subtitle_multiline_ = true;
};

BEGIN_VIEW_BUILDER(, RichHoverButton, HoverButton)
VIEW_BUILDER_PROPERTY(ui::ImageModel, Icon)
VIEW_BUILDER_PROPERTY(std::u16string_view, TitleText)
VIEW_BUILDER_PROPERTY(ui::ImageModel, StateIcon)
VIEW_BUILDER_PROPERTY(ui::ImageModel, ActionIcon)
VIEW_BUILDER_PROPERTY(std::u16string_view, SubtitleText)
VIEW_BUILDER_PROPERTY(bool, SubtitleMultiline)
VIEW_BUILDER_METHOD(SetTitleTextStyleAndColor, int, ui::ColorId)
VIEW_BUILDER_METHOD(SetSubtitleTextStyleAndColor, int, ui::ColorId)
VIEW_BUILDER_TEMPLATED_PROPERTY(<typename T>, CustomView, std::unique_ptr<T>)

END_VIEW_BUILDER

DEFINE_VIEW_BUILDER(, RichHoverButton)

#endif  // CHROME_BROWSER_UI_VIEWS_CONTROLS_RICH_HOVER_BUTTON_H_