File: help_bubble_views.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (155 lines) | stat: -rw-r--r-- 5,967 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
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_USER_EDUCATION_VIEWS_HELP_BUBBLE_VIEWS_H_
#define COMPONENTS_USER_EDUCATION_VIEWS_HELP_BUBBLE_VIEWS_H_

#include <concepts>
#include <optional>

#include "base/callback_list.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "components/user_education/common/help_bubble/custom_help_bubble.h"
#include "components/user_education/common/help_bubble/help_bubble.h"
#include "components/user_education/common/help_bubble/help_bubble_params.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/base/interaction/element_tracker.h"
#include "ui/color/color_id.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"

namespace user_education {

// Views-specific implementation of the help bubble.
//
// Because this is a FrameworkSpecificImplementation, you can use:
//   help_bubble->AsA<HelpBubbleViews>()->bubble_view()
// to retrieve the underlying bubble view.
class HelpBubbleViews : public HelpBubble,
                        public views::WidgetObserver,
                        public ui::AcceleratorTarget {
 public:
  ~HelpBubbleViews() override;

  DECLARE_FRAMEWORK_SPECIFIC_METADATA()

  // HelpBubble:
  bool ToggleFocusForAccessibility() override;
  void OnAnchorBoundsChanged() override;
  gfx::Rect GetBoundsInScreen() const override;
  ui::ElementContext GetContext() const override;

  // ui::AcceleratorTarget
  bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
  bool CanHandleAccelerators() const override;

  // Retrieve the bubble view. If the bubble has been closed, this may return
  // null.
  auto* bubble_view_for_testing() { return help_bubble_view_.get(); }
  const auto* bubble_view_for_testing() const {
    return help_bubble_view_.get();
  }

  static views::BubbleBorder::Arrow TranslateArrow(HelpBubbleArrow arrow);

 protected:
  HelpBubbleViews(views::BubbleDialogDelegateView* help_bubble_view,
                  ui::TrackedElement* anchor_element);

  // HelpBubble:
  void CloseBubbleImpl() override;

 private:
  friend class HelpBubbleFactoryViews;
  friend class HelpBubbleFactoryMac;
  friend class HelpBubbleViewsTest;
  friend class HelpBubbleViewsCustomBubbleTest;

  // Clean up properties on the anchor view, if applicable.
  void MaybeResetAnchorView();

  // views::WidgetObserver:
  void OnWidgetDestroying(views::Widget* widget) override;

  void OnElementHidden(ui::TrackedElement* element);
  void OnElementBoundsChanged(ui::TrackedElement* element);

  raw_ptr<views::BubbleDialogDelegateView> help_bubble_view_;
  base::ScopedObservation<views::Widget, views::WidgetObserver>
      scoped_observation_{this};

  // Track the anchor element to determine if/when it goes away.
  raw_ptr<const ui::TrackedElement> anchor_element_ = nullptr;

  // Listens so that the bubble can be closed if the anchor element disappears.
  // The specific anchor view is not tracked because in a few cases (e.g. Mac
  // native menus) the anchor view is not the anchor element itself but a
  // placeholder.
  base::CallbackListSubscription anchor_hidden_subscription_;

  // Listens for changes to the anchor bounding rect that are independent of the
  // anchor view. Necessary for e.g. WebUI elements, which can be scrolled or
  // moved within the web page.
  base::CallbackListSubscription anchor_bounds_changed_subscription_;

  base::WeakPtrFactory<HelpBubbleViews> weak_ptr_factory_{this};
};

// Help bubble that wraps a custom help bubble view.
//
// Rather than using this directly, prefer
// `CreateCustomHelpBubbleViewFactoryCallback()` as it removes a significant
// amount of boilerplate.
class CustomHelpBubbleViews : public HelpBubbleViews, public CustomHelpBubble {
 public:
  using UserAction = CustomHelpBubbleUi::UserAction;

  // Create a help bubble from a custom Views-based help bubble dialog.
  // Prefer `CreateCustomHelpBubbleViewFactoryCallback()`.
  //
  // NOTE: this hooks the `Widget::MakeCloseSynchronous` method and you should
  // NOT call that yourself. ESC and (X) are always handled, and the dialog
  // accept and cancel buttons (if present) will map to `accept_button_action`
  // and `cancel_button_action` correspondingly if specified.
  template <typename T>
    requires(std::derived_from<T, views::BubbleDialogDelegateView> &&
             std::derived_from<T, CustomHelpBubbleUi>)
  CustomHelpBubbleViews(
      std::unique_ptr<views::Widget> widget,
      T* bubble,
      ui::TrackedElement* anchor_element,
      std::optional<UserAction> accept_button_action = std::nullopt,
      std::optional<UserAction> cancel_button_action = std::nullopt)
      : CustomHelpBubbleViews(std::move(widget),
                              bubble,
                              *bubble,
                              anchor_element,
                              accept_button_action,
                              cancel_button_action) {}

  ~CustomHelpBubbleViews() override;

 protected:
  CustomHelpBubbleViews(std::unique_ptr<views::Widget> widget,
                        views::BubbleDialogDelegateView* bubble,
                        CustomHelpBubbleUi& ui,
                        ui::TrackedElement* anchor_element,
                        std::optional<UserAction> accept_button_action,
                        std::optional<UserAction> cancel_button_action);

 private:
  void OnHelpBubbleClosing(views::Widget::ClosedReason closed_reason);

  std::unique_ptr<views::Widget> help_bubble_widget_;
  std::optional<UserAction> accept_button_action_;
  std::optional<UserAction> cancel_button_action_;
};

}  // namespace user_education

#endif  // COMPONENTS_USER_EDUCATION_VIEWS_HELP_BUBBLE_VIEWS_H_