blob: b43335573d392cb6c51d3f7ac93cd1be2d691b80 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/autofill/tooltip_icon.h"
#include "base/basictypes.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/views/autofill/info_bubble.h"
#include "grit/theme_resources.h"
#include "ui/accessibility/ax_view_state.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/mouse_watcher_view_host.h"
#include "ui/views/painter.h"
namespace autofill {
namespace {
gfx::Insets GetPreferredInsets(const views::View* view) {
gfx::Size pref_size = view->GetPreferredSize();
gfx::Rect local_bounds = view->GetLocalBounds();
gfx::Point origin = local_bounds.CenterPoint();
origin.Offset(-pref_size.width() / 2, -pref_size.height() / 2);
return gfx::Insets(origin.y(),
origin.x(),
local_bounds.bottom() - (origin.y() + pref_size.height()),
local_bounds.right() - (origin.x() + pref_size.width()));
}
// An info bubble with some extra positioning magic for tooltip icons.
class TooltipBubble : public InfoBubble {
public:
TooltipBubble(views::View* anchor, const base::string16& message)
: InfoBubble(anchor, message) {}
virtual ~TooltipBubble() {}
protected:
// InfoBubble:
virtual gfx::Rect GetAnchorRect() const override {
gfx::Rect bounds = views::BubbleDelegateView::GetAnchorRect();
bounds.Inset(GetPreferredInsets(anchor()));
return bounds;
}
private:
DISALLOW_COPY_AND_ASSIGN(TooltipBubble);
};
} // namespace
TooltipIcon::TooltipIcon(const base::string16& tooltip)
: tooltip_(tooltip),
mouse_inside_(false),
bubble_(NULL),
observer_(this) {
ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON);
}
TooltipIcon::~TooltipIcon() {
HideBubble();
}
// static
const char TooltipIcon::kViewClassName[] = "autofill/TooltipIcon";
const char* TooltipIcon::GetClassName() const {
return TooltipIcon::kViewClassName;
}
void TooltipIcon::OnMouseEntered(const ui::MouseEvent& event) {
mouse_inside_ = true;
show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), this,
&TooltipIcon::ShowBubble);
}
void TooltipIcon::OnMouseExited(const ui::MouseEvent& event) {
show_timer_.Stop();
}
void TooltipIcon::OnGestureEvent(ui::GestureEvent* event) {
if (event->type() == ui::ET_GESTURE_TAP) {
ShowBubble();
event->SetHandled();
}
}
void TooltipIcon::GetAccessibleState(ui::AXViewState* state) {
state->name = tooltip_;
}
void TooltipIcon::MouseMovedOutOfHost() {
if (IsMouseHovered()) {
mouse_watcher_->Start();
return;
}
mouse_inside_ = false;
HideBubble();
}
void TooltipIcon::ChangeImageTo(int idr) {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
SetImage(rb.GetImageNamed(idr).ToImageSkia());
}
void TooltipIcon::ShowBubble() {
if (bubble_)
return;
ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON_H);
bubble_ = new TooltipBubble(this, tooltip_);
// When shown due to a gesture event, close on deactivate (i.e. don't use
// "focusless").
bubble_->set_can_activate(!mouse_inside_);
bubble_->Show();
observer_.Add(bubble_->GetWidget());
if (mouse_inside_) {
views::View* frame = bubble_->GetWidget()->non_client_view()->frame_view();
scoped_ptr<views::MouseWatcherHost> host(
new views::MouseWatcherViewHost(frame, gfx::Insets()));
mouse_watcher_.reset(new views::MouseWatcher(host.release(), this));
mouse_watcher_->Start();
}
}
void TooltipIcon::HideBubble() {
if (bubble_)
bubble_->Hide();
}
void TooltipIcon::OnWidgetDestroyed(views::Widget* widget) {
observer_.Remove(widget);
ChangeImageTo(IDR_AUTOFILL_TOOLTIP_ICON);
mouse_watcher_.reset();
bubble_ = NULL;
}
} // namespace autofill