File: label_button.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; 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,806; 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 (367 lines) | stat: -rw-r--r-- 14,666 bytes parent folder | download | duplicates (6)
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_H_
#define UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_H_

#include <array>
#include <memory>
#include <optional>
#include <string_view>

#include "base/functional/bind.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_id.h"
#include "ui/color/color_variant.h"
#include "ui/gfx/geometry/rounded_corners_f.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/label_button_image_container.h"
#include "ui/views/controls/button/label_button_label.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/delegating_layout_manager.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/layout/proposed_layout.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/native_theme_delegate.h"
#include "ui/views/style/typography.h"
#include "ui/views/widget/widget.h"

namespace actions {
class ActionItem;
}

namespace views {

class InkDropContainerView;
class LabelButtonBorder;

// LabelButton is a button with text and an icon.
class VIEWS_EXPORT LabelButton : public Button,
                                 public NativeThemeDelegate,
                                 public LayoutDelegate {
  METADATA_HEADER(LabelButton, Button)

 public:
  // Creates a LabelButton with pressed events sent to `callback` and label
  // `text`. `button_context` is a value from views::style::TextContext and
  // determines the appearance of `text`.
  explicit LabelButton(
      PressedCallback callback = PressedCallback(),
      std::u16string_view text = {},
      int button_context = style::CONTEXT_BUTTON,
      std::unique_ptr<LabelButtonImageContainer> image_container =
          std::make_unique<SingleImageContainer>());
  LabelButton(const LabelButton&) = delete;
  LabelButton& operator=(const LabelButton&) = delete;
  ~LabelButton() override;

  // Gets the image shown for state.
  virtual gfx::ImageSkia GetImage(ButtonState state) const;

  // Gets the image model set for `state`. This may not be the image shown,
  // since a nullopt image model will use the STATE_NORMAL image.
  const std::optional<ui::ImageModel>& GetImageModel(ButtonState state) const;

  // Sets the image show for `state`. If `image_model` is nullopt, it will use
  // the STATE_NORMAL image. If `image_model` is empty, image won't be shown in
  // the button.
  virtual void SetImageModel(ButtonState state,
                             const std::optional<ui::ImageModel>& image_model);

  // Returns whether the image shown for `state` is not empty.
  bool HasImage(ButtonState state) const;

  // Gets or sets the text shown on the button.
  std::u16string_view GetText() const;
  virtual void SetText(std::u16string_view text);

  // Set the text style of the label.
  void SetLabelStyle(views::style::TextStyle text_style);

  // Makes the button report its preferred size without the label. This lets
  // AnimatingLayoutManager gradually shrink the button until the text is
  // invisible, at which point the text gets cleared. Think of this as
  // transitioning from the current text to SetText("").
  // Note that the layout manager (or manual SetBounds calls) need to be
  // configured to eventually hit the the button's preferred size (or smaller)
  // or the text will never be cleared.
  void ShrinkDownThenClearText();

  // Sets the text color shown for the specified button |for_state| to |color|.
  void SetTextColor(ButtonState for_state, ui::ColorVariant color);

  // Sets the text colors shown for the non-disabled states to |color|.
  virtual void SetEnabledTextColors(std::optional<ui::ColorVariant> color);

  // Gets the current state text color.
  SkColor GetCurrentTextColor() const;

  // Sets drop shadows underneath the text.
  void SetTextShadows(const gfx::ShadowValues& shadows);

  // Sets whether subpixel rendering is used on the label.
  void SetTextSubpixelRenderingEnabled(bool enabled);

  // Sets the elide behavior of this button.
  void SetElideBehavior(gfx::ElideBehavior elide_behavior);

  // Sets the horizontal alignment used for the button; reversed in RTL. The
  // optional image will lead the text, unless the button is right-aligned.
  void SetHorizontalAlignment(gfx::HorizontalAlignment alignment);
  gfx::HorizontalAlignment GetHorizontalAlignment() const;

  gfx::Size GetMinSize() const;
  void SetMinSize(const gfx::Size& min_size);

  gfx::Size GetMaxSize() const;
  void SetMaxSize(const gfx::Size& max_size);

  // Gets or sets the option to handle the return key; false by default.
  bool GetIsDefault() const;
  void SetIsDefault(bool is_default);

  // Sets the spacing between the image and the text.
  int GetImageLabelSpacing() const;
  void SetImageLabelSpacing(int spacing);

  // Gets or sets the option to place the image aligned with the center of the
  // the label. The image is not centered for CheckBox and RadioButton only.
  bool GetImageCentered() const;
  void SetImageCentered(bool image_centered);

  // Sets the corner radii of the focus ring around the button.
  gfx::RoundedCornersF GetFocusRingCornerRadii() const;
  void SetFocusRingCornerRadii(const gfx::RoundedCornersF& radii);
  void SetFocusRingCornerRadius(float radius);

  // Creates the default border for this button. This can be overridden by
  // subclasses.
  virtual std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const;

  // Normally a LabelButton only appears as disabled in an inactive widget if
  // PlatformStyle::kInactiveWidgetControlsAppearDisabled is true. This method
  // overrides the default PlatformStyle behavior for this button.
  void SetAppearDisabledInInactiveWidget(bool appear_disabled);

  // Button:
  void SetBorder(std::unique_ptr<Border> border) override;
  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
  gfx::Size CalculatePreferredSize(
      const SizeBounds& available_size) const override;
  gfx::Size GetMinimumSize() const override;
  void AddLayerToRegion(ui::Layer* new_layer,
                        views::LayerRegion region) override;
  void RemoveLayerFromRegions(ui::Layer* old_layer) override;
  std::unique_ptr<ActionViewInterface> GetActionViewInterface() override;

  // NativeThemeDelegate:
  ui::NativeTheme::Part GetThemePart() const override;
  gfx::Rect GetThemePaintRect() const override;
  ui::NativeTheme::State GetThemeState(
      ui::NativeTheme::ExtraParams* params) const override;
  const gfx::Animation* GetThemeAnimation() const override;
  ui::NativeTheme::State GetBackgroundThemeState(
      ui::NativeTheme::ExtraParams* params) const override;
  ui::NativeTheme::State GetForegroundThemeState(
      ui::NativeTheme::ExtraParams* params) const override;

  // LayoutDelegate:
  ProposedLayout CalculateProposedLayout(
      const SizeBounds& size_bounds) const override;

  // Returns the current visual appearance of the button. This takes into
  // account both the button's underlying state, the state of the containing
  // widget, and the parent of the containing widget.
  ButtonState GetVisualState() const;

  bool has_paint_as_active_subscription_for_testing() {
    return !!paint_as_active_subscription_;
  }

 protected:
  LabelButtonImageContainer* image_container() {
    return image_container_.get();
  }
  const LabelButtonImageContainer* image_container() const {
    return image_container_.get();
  }
  const View* image_container_view() const {
    return image_container_->GetView();
  }
  View* image_container_view() { return image_container_->GetView(); }
  Label* label() const { return label_; }
  InkDropContainerView* ink_drop_container() const {
    return ink_drop_container_;
  }

  bool explicitly_set_normal_color() const {
    return explicitly_set_colors_[STATE_NORMAL];
  }

  const std::array<bool, STATE_COUNT>& explicitly_set_colors() const {
    return explicitly_set_colors_;
  }
  void set_explicitly_set_colors(const std::array<bool, STATE_COUNT>& colors) {
    explicitly_set_colors_ = colors;
  }

  // Updates the image view to contain the appropriate button state image.
  void UpdateImage();

  // Updates the background color, if the background color is state-sensitive.
  virtual void UpdateBackgroundColor() {}

  // Fills |params| with information about the button.
  virtual void GetExtraParams(ui::NativeTheme::ExtraParams* params) const;

  // Changes the visual styling to match changes in the default state.  Returns
  // the PropertyEffects triggered as a result.
  virtual PropertyEffects UpdateStyleToIndicateDefaultStatus();

  // Button:
  void ChildPreferredSizeChanged(View* child) override;
  void AddedToWidget() override;
  void RemovedFromWidget() override;
  void OnFocus() override;
  void OnBlur() override;
  void OnThemeChanged() override;
  void StateChanged(ButtonState old_state) override;

 private:
  void SetTextInternal(std::u16string_view text);

  void ClearTextIfShrunkDown();

  // Gets the preferred size (without respecting min_size_ or max_size_), but
  // does not account for the label. This is shared between GetHeightForWidth
  // and CalculatePreferredSize. GetHeightForWidth will subtract the width
  // returned from this method to get width available for the label while
  // CalculatePreferredSize will just add the preferred width from the label.
  // Both methods will then use the max of inset height + label height and this
  // height as total height, and clamp to min/max sizes as appropriate.
  gfx::Size GetUnclampedSizeWithoutLabel() const;

  // Updates the portions of the object that might change in response to a
  // change in the value returned by GetVisualState().
  void VisualStateChanged();

  // Resets colors from the NativeTheme, explicitly set colors are unchanged.
  void ResetColorsFromNativeTheme();

  // Updates additional state related to focus or default status, rather than
  // merely the Button::state(). E.g. ensures the label text color is
  // correct for the current background.
  void ResetLabelEnabledColor();

  // Returns the state whose image is shown for `for_state`, by falling back to
  // STATE_NORMAL when `for_state` has not been set.
  ButtonState ImageStateForState(ButtonState for_state) const;

  void FlipCanvasOnPaintForRTLUIChanged();

  // The image container and label shown in the button.
  std::unique_ptr<LabelButtonImageContainer> image_container_;
  raw_ptr<internal::LabelButtonLabel> label_;

  // A separate view is necessary to hold the ink drop layer so that it can
  // be stacked below |image_| and on top of |label_|, without resorting to
  // drawing |label_| on a layer (which can mess with subpixel anti-aliasing).
  raw_ptr<InkDropContainerView> ink_drop_container_;

  // The cached font lists in the normal and default button style. The latter
  // may be bold.
  gfx::FontList cached_normal_font_list_;
  gfx::FontList cached_default_button_font_list_;

  // The image models and colors for each button state.
  std::array<std::optional<ui::ImageModel>, STATE_COUNT>
      button_state_image_models_;
  std::array<std::optional<ui::ColorVariant>, STATE_COUNT> button_state_colors_;

  // Used to track whether SetTextColor() has been invoked.
  std::array<bool, STATE_COUNT> explicitly_set_colors_ = {};

  // |min_size_| and |max_size_| may be set to clamp the preferred size.
  gfx::Size min_size_;
  gfx::Size max_size_;

  // A flag indicating that this button should not include the label in its
  // desired size. Furthermore, once the bounds of the button adapt to this
  // desired size, the text in the label should get cleared.
  bool shrinking_down_label_ = false;

  // Flag indicating default handling of the return key via an accelerator.
  // Whether or not the button appears or behaves as the default button in its
  // current context;
  bool is_default_ = false;

  // True if current border was set by SetBorder.
  bool explicitly_set_border_ = false;

  // A flag indicating that this button's image should be aligned with the
  // center of the label when multiline is enabled. This shouldn't be the case
  // for a CheckBox or a RadioButton.
  bool image_centered_ = true;

  // Spacing between the image and the text.
  int image_label_spacing_ = LayoutProvider::Get()->GetDistanceMetric(
      DISTANCE_RELATED_LABEL_HORIZONTAL);

  // Alignment of the button. This can be different from the alignment of the
  // text; for example, the label may be set to ALIGN_TO_HEAD (alignment matches
  // text direction) while |this| is laid out as ALIGN_LEFT (alignment matches
  // UI direction).
  gfx::HorizontalAlignment horizontal_alignment_ = gfx::ALIGN_LEFT;

  // Corner radii of the focus ring.
  gfx::RoundedCornersF focus_ring_corner_radii_ =
      gfx::RoundedCornersF(FocusRing::kDefaultCornerRadiusDp);

  base::CallbackListSubscription paint_as_active_subscription_;

  bool appear_disabled_in_inactive_widget_ = false;

  base::CallbackListSubscription flip_canvas_on_paint_subscription_ =
      AddFlipCanvasOnPaintForRTLUIChangedCallback(
          base::BindRepeating(&LabelButton::FlipCanvasOnPaintForRTLUIChanged,
                              base::Unretained(this)));
};

class VIEWS_EXPORT LabelButtonActionViewInterface
    : public ButtonActionViewInterface {
 public:
  explicit LabelButtonActionViewInterface(LabelButton* action_view);
  ~LabelButtonActionViewInterface() override = default;

  // ButtonActionViewInterface:
  void ActionItemChangedImpl(actions::ActionItem* action_item) override;

 private:
  raw_ptr<LabelButton> action_view_;
};

BEGIN_VIEW_BUILDER(VIEWS_EXPORT, LabelButton, Button)
VIEW_BUILDER_PROPERTY(std::u16string, Text)
VIEW_BUILDER_PROPERTY(gfx::HorizontalAlignment, HorizontalAlignment)
VIEW_BUILDER_PROPERTY(views::style::TextStyle, LabelStyle)
VIEW_BUILDER_PROPERTY(gfx::Size, MinSize)
VIEW_BUILDER_PROPERTY(gfx::Size, MaxSize)
VIEW_BUILDER_PROPERTY(std::optional<ui::ColorVariant>, EnabledTextColors)
VIEW_BUILDER_PROPERTY(bool, IsDefault)
VIEW_BUILDER_PROPERTY(int, ImageLabelSpacing)
VIEW_BUILDER_PROPERTY(bool, ImageCentered)
VIEW_BUILDER_METHOD(SetImageModel, Button::ButtonState, const ui::ImageModel&)
VIEW_BUILDER_METHOD(SetTextColor, Button::ButtonState, ui::ColorVariant)
END_VIEW_BUILDER

}  // namespace views

DEFINE_VIEW_BUILDER(VIEWS_EXPORT, LabelButton)

#endif  // UI_VIEWS_CONTROLS_BUTTON_LABEL_BUTTON_H_