1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/bubble/tooltip_icon.h"
6
7 #include "base/timer/timer.h"
8 #include "components/vector_icons/vector_icons.h"
9 #include "ui/accessibility/ax_enums.mojom.h"
10 #include "ui/accessibility/ax_node_data.h"
11 #include "ui/gfx/paint_vector_icon.h"
12 #include "ui/views/bubble/bubble_frame_view.h"
13 #include "ui/views/bubble/info_bubble.h"
14 #include "ui/views/mouse_watcher_view_host.h"
15
16 namespace views {
17
TooltipIcon(const base::string16 & tooltip,int tooltip_icon_size)18 TooltipIcon::TooltipIcon(const base::string16& tooltip, int tooltip_icon_size)
19 : tooltip_(tooltip),
20 tooltip_icon_size_(tooltip_icon_size),
21 mouse_inside_(false),
22 bubble_(nullptr),
23 preferred_width_(0) {
24 SetDrawAsHovered(false);
25 }
26
~TooltipIcon()27 TooltipIcon::~TooltipIcon() {
28 for (auto& observer : observers_)
29 observer.OnTooltipIconDestroying(this);
30 HideBubble();
31 }
32
OnMouseEntered(const ui::MouseEvent & event)33 void TooltipIcon::OnMouseEntered(const ui::MouseEvent& event) {
34 mouse_inside_ = true;
35 show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), this,
36 &TooltipIcon::ShowBubble);
37 }
38
OnMouseExited(const ui::MouseEvent & event)39 void TooltipIcon::OnMouseExited(const ui::MouseEvent& event) {
40 show_timer_.Stop();
41 }
42
OnMousePressed(const ui::MouseEvent & event)43 bool TooltipIcon::OnMousePressed(const ui::MouseEvent& event) {
44 // Swallow the click so that the parent doesn't process it.
45 return true;
46 }
47
OnGestureEvent(ui::GestureEvent * event)48 void TooltipIcon::OnGestureEvent(ui::GestureEvent* event) {
49 if (event->type() == ui::ET_GESTURE_TAP) {
50 ShowBubble();
51 event->SetHandled();
52 }
53 }
54
GetAccessibleNodeData(ui::AXNodeData * node_data)55 void TooltipIcon::GetAccessibleNodeData(ui::AXNodeData* node_data) {
56 node_data->role = ax::mojom::Role::kTooltip;
57 node_data->SetName(tooltip_);
58 }
59
MouseMovedOutOfHost()60 void TooltipIcon::MouseMovedOutOfHost() {
61 if (IsMouseHovered()) {
62 mouse_watcher_->Start(GetWidget()->GetNativeWindow());
63 return;
64 }
65
66 mouse_inside_ = false;
67 HideBubble();
68 }
69
AddObserver(Observer * observer)70 void TooltipIcon::AddObserver(Observer* observer) {
71 observers_.AddObserver(observer);
72 }
73
RemoveObserver(Observer * observer)74 void TooltipIcon::RemoveObserver(Observer* observer) {
75 observers_.RemoveObserver(observer);
76 }
77
SetDrawAsHovered(bool hovered)78 void TooltipIcon::SetDrawAsHovered(bool hovered) {
79 SetImage(gfx::CreateVectorIcon(
80 vector_icons::kInfoOutlineIcon, tooltip_icon_size_,
81 GetNativeTheme()->GetSystemColor(
82 hovered ? ui::NativeTheme::kColorId_TooltipIconHovered
83 : ui::NativeTheme::kColorId_TooltipIcon)));
84 }
85
ShowBubble()86 void TooltipIcon::ShowBubble() {
87 if (bubble_)
88 return;
89
90 SetDrawAsHovered(true);
91
92 bubble_ = new InfoBubble(this, tooltip_);
93 bubble_->set_preferred_width(preferred_width_);
94 bubble_->SetArrow(anchor_point_arrow_);
95 // When shown due to a gesture event, close on deactivate (i.e. don't use
96 // "focusless").
97 bubble_->SetCanActivate(!mouse_inside_);
98
99 bubble_->Show();
100 observer_.Add(bubble_->GetWidget());
101
102 if (mouse_inside_) {
103 View* frame = bubble_->GetWidget()->non_client_view()->frame_view();
104 mouse_watcher_ = std::make_unique<MouseWatcher>(
105 std::make_unique<MouseWatcherViewHost>(frame, gfx::Insets()), this);
106 mouse_watcher_->Start(GetWidget()->GetNativeWindow());
107 }
108
109 for (auto& observer : observers_)
110 observer.OnTooltipBubbleShown(this);
111 }
112
HideBubble()113 void TooltipIcon::HideBubble() {
114 if (bubble_)
115 bubble_->Hide();
116 }
117
OnWidgetDestroyed(Widget * widget)118 void TooltipIcon::OnWidgetDestroyed(Widget* widget) {
119 observer_.Remove(widget);
120
121 SetDrawAsHovered(false);
122 mouse_watcher_.reset();
123 bubble_ = nullptr;
124 }
125
126 BEGIN_METADATA(TooltipIcon)
127 METADATA_PARENT_CLASS(ImageView)
128 END_METADATA()
129
130 } // namespace views
131