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