Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / ash / launcher / launcher_tooltip_manager.cc
blob568ff5672d702c16648489c24a51628b3fae7e32
1 // Copyright (c) 2012 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.
5 #include "ash/launcher/launcher_tooltip_manager.h"
7 #include "ash/launcher/launcher_view.h"
8 #include "ash/shelf/shelf_layout_manager.h"
9 #include "ash/shell.h"
10 #include "ash/shell_window_ids.h"
11 #include "ash/wm/window_animations.h"
12 #include "base/bind.h"
13 #include "base/message_loop.h"
14 #include "base/time.h"
15 #include "base/timer.h"
16 #include "ui/aura/root_window.h"
17 #include "ui/aura/window.h"
18 #include "ui/base/events/event.h"
19 #include "ui/base/events/event_constants.h"
20 #include "ui/gfx/insets.h"
21 #include "ui/views/bubble/bubble_delegate.h"
22 #include "ui/views/bubble/bubble_frame_view.h"
23 #include "ui/views/controls/label.h"
24 #include "ui/views/layout/fill_layout.h"
25 #include "ui/views/widget/widget.h"
27 namespace ash {
28 namespace internal {
29 namespace {
30 const int kTooltipTopBottomMargin = 3;
31 const int kTooltipLeftRightMargin = 10;
32 const int kTooltipAppearanceDelay = 200; // msec
33 const int kTooltipMinHeight = 29 - 2 * kTooltipTopBottomMargin;
34 const SkColor kTooltipTextColor = SkColorSetRGB(0x22, 0x22, 0x22);
36 // The maximum width of the tooltip bubble. Borrowed the value from
37 // ash/tooltip/tooltip_controller.cc
38 const int kTooltipMaxWidth = 250;
40 // The offset for the tooltip bubble - making sure that the bubble is flush
41 // with the shelf. The offset includes the arrow size in pixels as well as
42 // the activation bar and other spacing elements.
43 const int kArrowOffsetLeftRight = 11;
44 const int kArrowOffsetTopBottom = 7;
46 } // namespace
48 // The implementation of tooltip of the launcher.
49 class LauncherTooltipManager::LauncherTooltipBubble
50 : public views::BubbleDelegateView {
51 public:
52 LauncherTooltipBubble(views::View* anchor,
53 views::BubbleBorder::ArrowLocation arrow_location,
54 LauncherTooltipManager* host);
56 void SetText(const string16& text);
57 void Close();
59 private:
60 // views::WidgetDelegate overrides:
61 virtual void WindowClosing() OVERRIDE;
63 // views::View overrides:
64 virtual gfx::Size GetPreferredSize() OVERRIDE;
66 LauncherTooltipManager* host_;
67 views::Label* label_;
69 DISALLOW_COPY_AND_ASSIGN(LauncherTooltipBubble);
72 LauncherTooltipManager::LauncherTooltipBubble::LauncherTooltipBubble(
73 views::View* anchor,
74 views::BubbleBorder::ArrowLocation arrow_location,
75 LauncherTooltipManager* host)
76 : views::BubbleDelegateView(anchor, arrow_location),
77 host_(host) {
78 gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom,
79 kArrowOffsetLeftRight,
80 kArrowOffsetTopBottom,
81 kArrowOffsetLeftRight);
82 // Launcher items can have an asymmetrical border for spacing reasons.
83 // Adjust anchor location for this.
84 if (anchor->border())
85 insets += anchor->border()->GetInsets();
87 set_anchor_view_insets(insets);
88 set_close_on_esc(false);
89 set_close_on_deactivate(false);
90 set_use_focusless(true);
91 set_accept_events(false);
92 set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin,
93 kTooltipTopBottomMargin, kTooltipLeftRightMargin));
94 set_shadow(views::BubbleBorder::SMALL_SHADOW);
95 SetLayoutManager(new views::FillLayout());
96 // The anchor may not have the widget in tests.
97 if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) {
98 aura::RootWindow* root_window =
99 anchor->GetWidget()->GetNativeView()->GetRootWindow();
100 set_parent_window(ash::Shell::GetInstance()->GetContainer(
101 root_window, ash::internal::kShellWindowId_SettingBubbleContainer));
103 label_ = new views::Label;
104 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
105 label_->SetEnabledColor(kTooltipTextColor);
106 label_->SetElideBehavior(views::Label::ELIDE_AT_END);
107 AddChildView(label_);
108 views::BubbleDelegateView::CreateBubble(this);
111 void LauncherTooltipManager::LauncherTooltipBubble::SetText(
112 const string16& text) {
113 label_->SetText(text);
114 SizeToContents();
117 void LauncherTooltipManager::LauncherTooltipBubble::Close() {
118 if (GetWidget()) {
119 host_ = NULL;
120 GetWidget()->Close();
124 void LauncherTooltipManager::LauncherTooltipBubble::WindowClosing() {
125 views::BubbleDelegateView::WindowClosing();
126 if (host_)
127 host_->OnBubbleClosed(this);
130 gfx::Size LauncherTooltipManager::LauncherTooltipBubble::GetPreferredSize() {
131 gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize();
132 if (pref_size.height() < kTooltipMinHeight)
133 pref_size.set_height(kTooltipMinHeight);
134 if (pref_size.width() > kTooltipMaxWidth)
135 pref_size.set_width(kTooltipMaxWidth);
136 return pref_size;
139 LauncherTooltipManager::LauncherTooltipManager(
140 ShelfLayoutManager* shelf_layout_manager,
141 LauncherView* launcher_view)
142 : view_(NULL),
143 widget_(NULL),
144 anchor_(NULL),
145 shelf_layout_manager_(shelf_layout_manager),
146 launcher_view_(launcher_view) {
147 if (shelf_layout_manager)
148 shelf_layout_manager->AddObserver(this);
149 if (Shell::HasInstance())
150 Shell::GetInstance()->AddPreTargetHandler(this);
153 LauncherTooltipManager::~LauncherTooltipManager() {
154 CancelHidingAnimation();
155 Close();
156 if (shelf_layout_manager_)
157 shelf_layout_manager_->RemoveObserver(this);
158 if (Shell::HasInstance())
159 Shell::GetInstance()->RemovePreTargetHandler(this);
162 void LauncherTooltipManager::ShowDelayed(views::View* anchor,
163 const string16& text) {
164 if (view_) {
165 if (timer_.get() && timer_->IsRunning()) {
166 return;
167 } else {
168 CancelHidingAnimation();
169 Close();
173 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
174 return;
176 CreateBubble(anchor, text);
177 ResetTimer();
180 void LauncherTooltipManager::ShowImmediately(views::View* anchor,
181 const string16& text) {
182 if (view_) {
183 if (timer_.get() && timer_->IsRunning())
184 StopTimer();
185 CancelHidingAnimation();
186 Close();
189 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
190 return;
192 CreateBubble(anchor, text);
193 ShowInternal();
196 void LauncherTooltipManager::Close() {
197 StopTimer();
198 if (view_) {
199 view_->Close();
200 view_ = NULL;
201 widget_ = NULL;
205 void LauncherTooltipManager::OnBubbleClosed(views::BubbleDelegateView* view) {
206 if (view == view_) {
207 view_ = NULL;
208 widget_ = NULL;
212 void LauncherTooltipManager::UpdateArrowLocation() {
213 if (view_) {
214 CancelHidingAnimation();
215 Close();
216 ShowImmediately(anchor_, text_);
220 void LauncherTooltipManager::ResetTimer() {
221 if (timer_.get() && timer_->IsRunning()) {
222 timer_->Reset();
223 return;
226 // We don't start the timer if the shelf isn't visible.
227 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
228 return;
230 base::OneShotTimer<LauncherTooltipManager>* new_timer =
231 new base::OneShotTimer<LauncherTooltipManager>();
232 new_timer->Start(
233 FROM_HERE,
234 base::TimeDelta::FromMilliseconds(kTooltipAppearanceDelay),
235 this,
236 &LauncherTooltipManager::ShowInternal);
237 timer_.reset(new_timer);
240 void LauncherTooltipManager::StopTimer() {
241 timer_.reset();
244 bool LauncherTooltipManager::IsVisible() {
245 if (timer_.get() && timer_->IsRunning())
246 return false;
248 return widget_ && widget_->IsVisible();
251 void LauncherTooltipManager::OnMouseEvent(ui::MouseEvent* event) {
252 DCHECK(event->target());
253 DCHECK(event);
254 if (!widget_ || !widget_->IsVisible())
255 return;
257 DCHECK(view_);
258 DCHECK(launcher_view_);
260 aura::Window* target = static_cast<aura::Window*>(event->target());
261 if (widget_->GetNativeWindow()->GetRootWindow() != target->GetRootWindow()) {
262 CloseSoon();
263 return;
266 gfx::Point location_in_launcher_view = event->location();
267 aura::Window::ConvertPointToTarget(
268 target, launcher_view_->GetWidget()->GetNativeWindow(),
269 &location_in_launcher_view);
271 gfx::Point location_on_screen = event->location();
272 aura::Window::ConvertPointToTarget(
273 target, target->GetRootWindow(), &location_on_screen);
274 gfx::Rect bubble_rect = widget_->GetWindowBoundsInScreen();
276 if (launcher_view_->ShouldHideTooltip(location_in_launcher_view) &&
277 !bubble_rect.Contains(location_on_screen)) {
278 // Because this mouse event may arrive to |view_|, here we just schedule
279 // the closing event rather than directly calling Close().
280 CloseSoon();
284 void LauncherTooltipManager::OnTouchEvent(ui::TouchEvent* event) {
285 aura::Window* target = static_cast<aura::Window*>(event->target());
286 if (widget_ && widget_->IsVisible() && widget_->GetNativeWindow() != target)
287 Close();
290 void LauncherTooltipManager::OnGestureEvent(ui::GestureEvent* event) {
291 if (widget_ && widget_->IsVisible()) {
292 // Because this mouse event may arrive to |view_|, here we just schedule
293 // the closing event rather than directly calling Close().
294 CloseSoon();
298 void LauncherTooltipManager::OnCancelMode(ui::CancelModeEvent* event) {
299 Close();
302 void LauncherTooltipManager::WillDeleteShelf() {
303 shelf_layout_manager_ = NULL;
306 void LauncherTooltipManager::WillChangeVisibilityState(
307 ShelfVisibilityState new_state) {
308 if (new_state == SHELF_HIDDEN) {
309 StopTimer();
310 Close();
314 void LauncherTooltipManager::OnAutoHideStateChanged(
315 ShelfAutoHideState new_state) {
316 if (new_state == SHELF_AUTO_HIDE_HIDDEN) {
317 StopTimer();
318 // AutoHide state change happens during an event filter, so immediate close
319 // may cause a crash in the HandleMouseEvent() after the filter. So we just
320 // schedule the Close here.
321 CloseSoon();
325 void LauncherTooltipManager::CancelHidingAnimation() {
326 if (!widget_ || !widget_->GetNativeView())
327 return;
329 gfx::NativeView native_view = widget_->GetNativeView();
330 views::corewm::SetWindowVisibilityAnimationTransition(
331 native_view, views::corewm::ANIMATE_NONE);
334 void LauncherTooltipManager::CloseSoon() {
335 MessageLoopForUI::current()->PostTask(
336 FROM_HERE,
337 base::Bind(&LauncherTooltipManager::Close, base::Unretained(this)));
340 void LauncherTooltipManager::ShowInternal() {
341 if (view_)
342 view_->GetWidget()->Show();
344 timer_.reset();
347 void LauncherTooltipManager::CreateBubble(views::View* anchor,
348 const string16& text) {
349 DCHECK(!view_);
351 anchor_ = anchor;
352 text_ = text;
353 views::BubbleBorder::ArrowLocation arrow_location =
354 shelf_layout_manager_->SelectValueForShelfAlignment(
355 views::BubbleBorder::BOTTOM_CENTER,
356 views::BubbleBorder::LEFT_CENTER,
357 views::BubbleBorder::RIGHT_CENTER,
358 views::BubbleBorder::TOP_CENTER);
360 view_ = new LauncherTooltipBubble(anchor, arrow_location, this);
361 widget_ = view_->GetWidget();
362 view_->SetText(text_);
364 gfx::NativeView native_view = widget_->GetNativeView();
365 views::corewm::SetWindowVisibilityAnimationType(
366 native_view, views::corewm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
367 views::corewm::SetWindowVisibilityAnimationTransition(
368 native_view, views::corewm::ANIMATE_HIDE);
371 } // namespace internal
372 } // namespace ash