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 "chrome/browser/ui/views/autofill/tooltip_icon.h" 6 7 #include "base/basictypes.h" 8 #include "base/timer/timer.h" 9 #include "chrome/browser/ui/views/autofill/info_bubble.h" 10 #include "grit/theme_resources.h" 11 #include "ui/base/resource/resource_bundle.h" 12 #include "ui/views/bubble/bubble_frame_view.h" 13 #include "ui/views/mouse_watcher_view_host.h" 14 #include "ui/views/painter.h" 15 16 namespace autofill { 17 18 namespace { 19 20 gfx::Insets GetPreferredInsets(views::View* view) { 21 gfx::Size pref_size = view->GetPreferredSize(); 22 gfx::Rect local_bounds = view->GetLocalBounds(); 23 gfx::Point origin = local_bounds.CenterPoint(); 24 origin.Offset(-pref_size.width() / 2, -pref_size.height() / 2); 25 return gfx::Insets(origin.y(), 26 origin.x(), 27 local_bounds.bottom() - (origin.y() + pref_size.height()), 28 local_bounds.right() - (origin.x() + pref_size.width())); 29 } 30 31 // An info bubble with some extra positioning magic for tooltip icons. 32 class TooltipBubble : public InfoBubble { 33 public: 34 TooltipBubble(views::View* anchor, const base::string16& message) 35 : InfoBubble(anchor, message) {} 36 virtual ~TooltipBubble() {} 37 38 protected: 39 // InfoBubble: 40 virtual gfx::Rect GetAnchorRect() OVERRIDE { 41 gfx::Rect bounds = views::BubbleDelegateView::GetAnchorRect(); 42 bounds.Inset(GetPreferredInsets(anchor())); 43 return bounds; 44 } 45 46 private: 47 DISALLOW_COPY_AND_ASSIGN(TooltipBubble); 48 }; 49 50 } // namespace 51 52 TooltipIcon::TooltipIcon(const base::string16& tooltip) 53 : tooltip_(tooltip), 54 mouse_inside_(false), 55 bubble_(NULL), 56 observer_(this) { 57 ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON); 58 SetFocusable(true); 59 } 60 61 TooltipIcon::~TooltipIcon() { 62 HideBubble(); 63 } 64 65 // static 66 const char TooltipIcon::kViewClassName[] = "autofill/TooltipIcon"; 67 68 const char* TooltipIcon::GetClassName() const { 69 return TooltipIcon::kViewClassName; 70 } 71 72 void TooltipIcon::OnMouseEntered(const ui::MouseEvent& event) { 73 mouse_inside_ = true; 74 show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), this, 75 &TooltipIcon::ShowBubble); 76 } 77 78 void TooltipIcon::OnMouseExited(const ui::MouseEvent& event) { 79 show_timer_.Stop(); 80 } 81 82 void TooltipIcon::OnGestureEvent(ui::GestureEvent* event) { 83 if (event->type() == ui::ET_GESTURE_TAP) { 84 ShowBubble(); 85 event->SetHandled(); 86 } 87 } 88 89 void TooltipIcon::OnBoundsChanged(const gfx::Rect& prev_bounds) { 90 SetFocusPainter(views::Painter::CreateDashedFocusPainterWithInsets( 91 GetPreferredInsets(this))); 92 } 93 94 void TooltipIcon::OnFocus() { 95 ShowBubble(); 96 } 97 98 void TooltipIcon::OnBlur() { 99 if (!mouse_inside_) 100 HideBubble(); 101 } 102 103 void TooltipIcon::MouseMovedOutOfHost() { 104 if (IsMouseHovered()) { 105 mouse_watcher_->Start(); 106 return; 107 } 108 109 mouse_inside_ = false; 110 if (!HasFocus()) 111 HideBubble(); 112 } 113 114 void TooltipIcon::ChangeImageTo(int idr) { 115 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 116 SetImage(rb.GetImageNamed(idr).ToImageSkia()); 117 } 118 119 void TooltipIcon::ShowBubble() { 120 if (bubble_) 121 return; 122 123 ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON_H); 124 125 bubble_ = new TooltipBubble(this, tooltip_); 126 // When shown due to a gesture event, close on deactivate (i.e. don't use 127 // "focusless"). 128 bubble_->set_use_focusless(mouse_inside_ || HasFocus()); 129 130 bubble_->Show(); 131 observer_.Add(bubble_->GetWidget()); 132 133 if (mouse_inside_) { 134 views::View* frame = bubble_->GetWidget()->non_client_view()->frame_view(); 135 scoped_ptr<views::MouseWatcherHost> host( 136 new views::MouseWatcherViewHost(frame, gfx::Insets())); 137 mouse_watcher_.reset(new views::MouseWatcher(host.release(), this)); 138 mouse_watcher_->Start(); 139 } 140 } 141 142 void TooltipIcon::HideBubble() { 143 if (bubble_) 144 bubble_->Hide(); 145 } 146 147 void TooltipIcon::OnWidgetDestroyed(views::Widget* widget) { 148 observer_.Remove(widget); 149 150 ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON); 151 mouse_watcher_.reset(); 152 bubble_ = NULL; 153 } 154 155 } // namespace autofill 156