Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: ash/shelf/shelf_tooltip_manager.cc

Issue 1816753002: Enable mash shelf tooltips. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address destructor comment. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ash/shelf/shelf_tooltip_manager.h ('k') | ash/shelf/shelf_tooltip_manager_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/shelf/shelf_tooltip_manager.h" 5 #include "ash/shelf/shelf_tooltip_manager.h"
6 6
7 #include "ash/shelf/shelf.h" 7 #include "ash/shelf/shelf.h"
8 #include "ash/shelf/shelf_layout_manager.h" 8 #include "ash/shelf/shelf_layout_manager.h"
9 #include "ash/shelf/shelf_view.h" 9 #include "ash/shelf/shelf_view.h"
10 #include "ash/shell.h" 10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h" 11 #include "ash/shell_window_ids.h"
12 #include "ash/wm/window_animations.h" 12 #include "ash/wm/window_animations.h"
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/thread_task_runner_handle.h" 14 #include "base/thread_task_runner_handle.h"
15 #include "base/time/time.h" 15 #include "base/time/time.h"
16 #include "base/timer/timer.h"
17 #include "ui/aura/window.h" 16 #include "ui/aura/window.h"
18 #include "ui/aura/window_event_dispatcher.h"
19 #include "ui/events/event.h" 17 #include "ui/events/event.h"
20 #include "ui/events/event_constants.h" 18 #include "ui/events/event_constants.h"
21 #include "ui/gfx/geometry/insets.h" 19 #include "ui/gfx/geometry/insets.h"
22 #include "ui/views/bubble/bubble_delegate.h" 20 #include "ui/views/bubble/bubble_delegate.h"
23 #include "ui/views/bubble/bubble_frame_view.h"
24 #include "ui/views/controls/label.h" 21 #include "ui/views/controls/label.h"
25 #include "ui/views/layout/fill_layout.h" 22 #include "ui/views/layout/fill_layout.h"
26 #include "ui/views/widget/widget.h" 23 #include "ui/views/widget/widget.h"
27 24
28 namespace ash { 25 namespace ash {
29 namespace { 26 namespace {
30 const int kTooltipTopBottomMargin = 3; 27 const int kTooltipTopBottomMargin = 3;
31 const int kTooltipLeftRightMargin = 10; 28 const int kTooltipLeftRightMargin = 10;
32 const int kTooltipAppearanceDelay = 1000; // msec 29 const int kTooltipAppearanceDelay = 1000; // msec
33 const int kTooltipMinHeight = 29 - 2 * kTooltipTopBottomMargin; 30 const int kTooltipMinHeight = 29 - 2 * kTooltipTopBottomMargin;
34 const SkColor kTooltipTextColor = SkColorSetRGB(0x22, 0x22, 0x22); 31 const SkColor kTooltipTextColor = SkColorSetRGB(0x22, 0x22, 0x22);
35 32
36 // The maximum width of the tooltip bubble. Borrowed the value from 33 // The maximum width of the tooltip bubble. Borrowed the value from
37 // ash/tooltip/tooltip_controller.cc 34 // ash/tooltip/tooltip_controller.cc
38 const int kTooltipMaxWidth = 250; 35 const int kTooltipMaxWidth = 250;
39 36
40 // The offset for the tooltip bubble - making sure that the bubble is flush 37 // 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 38 // with the shelf. The offset includes the arrow size in pixels as well as
42 // the activation bar and other spacing elements. 39 // the activation bar and other spacing elements.
43 const int kArrowOffsetLeftRight = 11; 40 const int kArrowOffsetLeftRight = 11;
44 const int kArrowOffsetTopBottom = 7; 41 const int kArrowOffsetTopBottom = 7;
45 42
46 } // namespace 43 } // namespace
47 44
48 // The implementation of tooltip of the launcher. 45 // The implementation of tooltip of the launcher.
49 class ShelfTooltipManager::ShelfTooltipBubble 46 class ShelfTooltipManager::ShelfTooltipBubble
50 : public views::BubbleDelegateView { 47 : public views::BubbleDelegateView {
51 public: 48 public:
52 ShelfTooltipBubble(views::View* anchor, 49 ShelfTooltipBubble(views::View* anchor,
53 views::BubbleBorder::Arrow arrow, 50 views::BubbleBorder::Arrow arrow,
54 ShelfTooltipManager* host); 51 const base::string16& text);
55
56 void SetText(const base::string16& text);
57 void Close();
58 52
59 private: 53 private:
60 // views::WidgetDelegate overrides:
61 void WindowClosing() override;
62
63 // views::View overrides: 54 // views::View overrides:
64 gfx::Size GetPreferredSize() const override; 55 gfx::Size GetPreferredSize() const override;
65 56
66 ShelfTooltipManager* host_;
67 views::Label* label_;
68
69 DISALLOW_COPY_AND_ASSIGN(ShelfTooltipBubble); 57 DISALLOW_COPY_AND_ASSIGN(ShelfTooltipBubble);
70 }; 58 };
71 59
72 ShelfTooltipManager::ShelfTooltipBubble::ShelfTooltipBubble( 60 ShelfTooltipManager::ShelfTooltipBubble::ShelfTooltipBubble(
73 views::View* anchor, 61 views::View* anchor,
74 views::BubbleBorder::Arrow arrow, 62 views::BubbleBorder::Arrow arrow,
75 ShelfTooltipManager* host) 63 const base::string16& text)
76 : views::BubbleDelegateView(anchor, arrow), host_(host) { 64 : views::BubbleDelegateView(anchor, arrow) {
77 gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom, 65 gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom,
78 kArrowOffsetLeftRight,
79 kArrowOffsetTopBottom,
80 kArrowOffsetLeftRight); 66 kArrowOffsetLeftRight);
81 // Shelf items can have an asymmetrical border for spacing reasons. 67 // Adjust the anchor location for asymmetrical borders of shelf item.
82 // Adjust anchor location for this.
83 if (anchor->border()) 68 if (anchor->border())
84 insets += anchor->border()->GetInsets(); 69 insets += anchor->border()->GetInsets();
85 70
86 set_anchor_view_insets(insets); 71 set_anchor_view_insets(insets);
87 set_close_on_esc(false); 72 set_close_on_esc(false);
88 set_close_on_deactivate(false); 73 set_close_on_deactivate(false);
89 set_can_activate(false); 74 set_can_activate(false);
90 set_accept_events(false); 75 set_accept_events(false);
91 set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin, 76 set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin));
92 kTooltipTopBottomMargin, kTooltipLeftRightMargin));
93 set_shadow(views::BubbleBorder::SMALL_SHADOW); 77 set_shadow(views::BubbleBorder::SMALL_SHADOW);
94 SetLayoutManager(new views::FillLayout()); 78 SetLayoutManager(new views::FillLayout());
95 // The anchor may not have the widget in tests. 79 // The anchor may not have the widget in tests.
96 if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) { 80 if (anchor->GetWidget() && anchor->GetWidget()->GetNativeWindow()) {
97 aura::Window* root_window = 81 set_parent_window(ash::Shell::GetContainer(
98 anchor->GetWidget()->GetNativeView()->GetRootWindow(); 82 anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
99 set_parent_window(ash::Shell::GetInstance()->GetContainer( 83 ash::kShellWindowId_SettingBubbleContainer));
100 root_window, ash::kShellWindowId_SettingBubbleContainer));
101 } 84 }
102 label_ = new views::Label; 85 views::Label* label = new views::Label(text);
103 label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 86 label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
104 label_->SetEnabledColor(kTooltipTextColor); 87 label->SetEnabledColor(kTooltipTextColor);
105 AddChildView(label_); 88 AddChildView(label);
106 views::BubbleDelegateView::CreateBubble(this); 89 views::BubbleDelegateView::CreateBubble(this);
107 }
108
109 void ShelfTooltipManager::ShelfTooltipBubble::SetText(
110 const base::string16& text) {
111 label_->SetText(text);
112 SizeToContents(); 90 SizeToContents();
113 } 91 }
114 92
115 void ShelfTooltipManager::ShelfTooltipBubble::Close() { 93 gfx::Size ShelfTooltipManager::ShelfTooltipBubble::GetPreferredSize() const {
116 if (GetWidget()) { 94 const gfx::Size size = views::BubbleDelegateView::GetPreferredSize();
117 host_ = NULL; 95 return gfx::Size(std::min(size.width(), kTooltipMaxWidth),
118 GetWidget()->Close(); 96 std::max(size.height(), kTooltipMinHeight));
119 }
120 } 97 }
121 98
122 void ShelfTooltipManager::ShelfTooltipBubble::WindowClosing() { 99 ShelfTooltipManager::ShelfTooltipManager(ShelfView* shelf_view)
123 views::BubbleDelegateView::WindowClosing(); 100 : timer_delay_(kTooltipAppearanceDelay),
124 if (host_) 101 shelf_view_(shelf_view),
125 host_->OnBubbleClosed(this); 102 shelf_layout_manager_(nullptr),
103 bubble_(nullptr),
104 weak_factory_(this) {}
105
106 ShelfTooltipManager::~ShelfTooltipManager() {
107 WillDeleteShelf();
126 } 108 }
127 109
128 gfx::Size ShelfTooltipManager::ShelfTooltipBubble::GetPreferredSize() const { 110 void ShelfTooltipManager::Init() {
129 gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize(); 111 shelf_layout_manager_ = shelf_view_->shelf()->shelf_layout_manager();
130 if (pref_size.height() < kTooltipMinHeight) 112 shelf_layout_manager_->AddObserver(this);
131 pref_size.set_height(kTooltipMinHeight); 113 // TODO(msw): Capture events outside the shelf to close tooltips?
132 if (pref_size.width() > kTooltipMaxWidth) 114 shelf_view_->GetWidget()->GetNativeWindow()->AddPreTargetHandler(this);
133 pref_size.set_width(kTooltipMaxWidth);
134 return pref_size;
135 } 115 }
136 116
137 ShelfTooltipManager::ShelfTooltipManager( 117 void ShelfTooltipManager::Close() {
138 ShelfLayoutManager* shelf_layout_manager, 118 timer_.Stop();
139 ShelfView* shelf_view) 119 if (bubble_)
140 : view_(NULL), 120 bubble_->GetWidget()->Close();
141 widget_(NULL), 121 bubble_ = nullptr;
142 anchor_(NULL),
143 shelf_layout_manager_(shelf_layout_manager),
144 shelf_view_(shelf_view),
145 weak_factory_(this) {
146 if (shelf_layout_manager)
147 shelf_layout_manager->AddObserver(this);
148 if (Shell::HasInstance())
149 Shell::GetInstance()->AddPreTargetHandler(this);
150 } 122 }
151 123
152 ShelfTooltipManager::~ShelfTooltipManager() { 124 bool ShelfTooltipManager::IsVisible() const {
153 CancelHidingAnimation(); 125 return bubble_ && bubble_->GetWidget()->IsVisible();
154 Close();
155 if (shelf_layout_manager_)
156 shelf_layout_manager_->RemoveObserver(this);
157 if (Shell::HasInstance())
158 Shell::GetInstance()->RemovePreTargetHandler(this);
159 } 126 }
160 127
161 void ShelfTooltipManager::ShowDelayed(views::View* anchor, 128 views::View* ShelfTooltipManager::GetCurrentAnchorView() const {
162 const base::string16& text) { 129 return bubble_ ? bubble_->GetAnchorView() : nullptr;
163 if (view_) {
164 if (timer_.get() && timer_->IsRunning()) {
165 return;
166 } else {
167 CancelHidingAnimation();
168 Close();
169 }
170 }
171
172 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
173 return;
174
175 CreateBubble(anchor, text);
176 ResetTimer();
177 } 130 }
178 131
179 void ShelfTooltipManager::ShowImmediately(views::View* anchor, 132 void ShelfTooltipManager::ShowTooltip(views::View* view) {
180 const base::string16& text) { 133 timer_.Stop();
181 if (view_) { 134 if (bubble_) {
182 if (timer_.get() && timer_->IsRunning()) 135 // Cancel the hiding animation to hide the old bubble immediately.
183 StopTimer(); 136 gfx::NativeView native_view = bubble_->GetWidget()->GetNativeView();
184 CancelHidingAnimation(); 137 wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_NONE);
185 Close(); 138 Close();
186 } 139 }
187 140
188 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible()) 141 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
189 return; 142 return;
190 143
191 CreateBubble(anchor, text); 144 Shelf* shelf = shelf_view_->shelf();
192 ShowInternal(); 145 views::BubbleBorder::Arrow arrow = shelf->SelectValueForShelfAlignment(
146 views::BubbleBorder::BOTTOM_CENTER, views::BubbleBorder::LEFT_CENTER,
147 views::BubbleBorder::RIGHT_CENTER, views::BubbleBorder::TOP_CENTER);
148
149 base::string16 text = shelf_view_->GetTitleForView(view);
150 bubble_ = new ShelfTooltipBubble(view, arrow, text);
151 gfx::NativeView native_view = bubble_->GetWidget()->GetNativeView();
152 wm::SetWindowVisibilityAnimationType(
153 native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
154 wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_HIDE);
155 bubble_->GetWidget()->Show();
193 } 156 }
194 157
195 void ShelfTooltipManager::Close() { 158 void ShelfTooltipManager::ShowTooltipWithDelay(views::View* view) {
196 StopTimer(); 159 if (!shelf_layout_manager_ || shelf_layout_manager_->IsVisible()) {
197 if (view_) { 160 timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timer_delay_),
198 view_->Close(); 161 base::Bind(&ShelfTooltipManager::ShowTooltip,
199 view_ = NULL; 162 weak_factory_.GetWeakPtr(), view));
200 widget_ = NULL;
201 } 163 }
202 } 164 }
203 165
204 void ShelfTooltipManager::OnBubbleClosed(views::BubbleDelegateView* view) { 166 void ShelfTooltipManager::OnEvent(ui::Event* event) {
205 if (view == view_) { 167 // Close the tooltip on mouse press or exit, and on most non-mouse events.
206 view_ = NULL; 168 if (event->type() == ui::ET_MOUSE_PRESSED ||
207 widget_ = NULL; 169 event->type() == ui::ET_MOUSE_EXITED || !event->IsMouseEvent()) {
170 if (!event->IsKeyEvent())
171 Close();
172 return;
173 }
174
175 gfx::Point point = static_cast<ui::LocatedEvent*>(event)->location();
176 views::View::ConvertPointFromWidget(shelf_view_, &point);
177 if (IsVisible() && shelf_view_->ShouldHideTooltip(point)) {
178 Close();
179 return;
180 }
181
182 views::View* view = shelf_view_->GetTooltipHandlerForPoint(point);
183 const bool should_show = shelf_view_->ShouldShowTooltipForView(view);
184 if (IsVisible() && bubble_->GetAnchorView() != view && should_show)
185 ShowTooltip(view);
186
187 if (!IsVisible() && event->type() == ui::ET_MOUSE_MOVED) {
188 timer_.Stop();
189 if (should_show)
190 ShowTooltipWithDelay(view);
208 } 191 }
209 } 192 }
210 193
211 void ShelfTooltipManager::UpdateArrow() { 194 void ShelfTooltipManager::WillDeleteShelf() {
212 if (view_) { 195 if (shelf_layout_manager_)
213 CancelHidingAnimation(); 196 shelf_layout_manager_->RemoveObserver(this);
214 Close(); 197 shelf_layout_manager_ = nullptr;
215 ShowImmediately(anchor_, text_);
216 }
217 }
218 198
219 void ShelfTooltipManager::ResetTimer() { 199 views::Widget* widget = shelf_view_ ? shelf_view_->GetWidget() : nullptr;
220 if (timer_.get() && timer_->IsRunning()) { 200 if (widget && widget->GetNativeWindow())
221 timer_->Reset(); 201 widget->GetNativeWindow()->RemovePreTargetHandler(this);
222 return; 202 shelf_view_ = nullptr;
223 }
224
225 // We don't start the timer if the shelf isn't visible.
226 if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible())
227 return;
228
229 CreateTimer(kTooltipAppearanceDelay);
230 }
231
232 void ShelfTooltipManager::StopTimer() {
233 timer_.reset();
234 }
235
236 bool ShelfTooltipManager::IsVisible() {
237 if (timer_.get() && timer_->IsRunning())
238 return false;
239
240 return widget_ && widget_->IsVisible();
241 }
242
243 void ShelfTooltipManager::CreateZeroDelayTimerForTest() {
244 CreateTimer(0);
245 }
246
247 void ShelfTooltipManager::OnMouseEvent(ui::MouseEvent* event) {
248 DCHECK(event);
249 DCHECK(event->target());
250 if (!widget_ || !widget_->IsVisible())
251 return;
252
253 DCHECK(view_);
254 DCHECK(shelf_view_);
255
256 // Pressing the mouse button anywhere should close the tooltip.
257 if (event->type() == ui::ET_MOUSE_PRESSED) {
258 CloseSoon();
259 return;
260 }
261
262 aura::Window* target = static_cast<aura::Window*>(event->target());
263 if (widget_->GetNativeWindow()->GetRootWindow() != target->GetRootWindow()) {
264 CloseSoon();
265 return;
266 }
267
268 gfx::Point location_in_shelf_view = event->location();
269 aura::Window::ConvertPointToTarget(
270 target, shelf_view_->GetWidget()->GetNativeWindow(),
271 &location_in_shelf_view);
272
273 if (shelf_view_->ShouldHideTooltip(location_in_shelf_view)) {
274 // Because this mouse event may arrive to |view_|, here we just schedule
275 // the closing event rather than directly calling Close().
276 CloseSoon();
277 }
278 }
279
280 void ShelfTooltipManager::OnTouchEvent(ui::TouchEvent* event) {
281 aura::Window* target = static_cast<aura::Window*>(event->target());
282 if (widget_ && widget_->IsVisible() && widget_->GetNativeWindow() != target)
283 Close();
284 }
285
286 void ShelfTooltipManager::OnGestureEvent(ui::GestureEvent* event) {
287 if (widget_ && widget_->IsVisible()) {
288 // Because this mouse event may arrive to |view_|, here we just schedule
289 // the closing event rather than directly calling Close().
290 CloseSoon();
291 }
292 }
293
294 void ShelfTooltipManager::OnCancelMode(ui::CancelModeEvent* event) {
295 Close();
296 }
297
298 void ShelfTooltipManager::WillDeleteShelf() {
299 shelf_layout_manager_ = NULL;
300 } 203 }
301 204
302 void ShelfTooltipManager::WillChangeVisibilityState( 205 void ShelfTooltipManager::WillChangeVisibilityState(
303 ShelfVisibilityState new_state) { 206 ShelfVisibilityState new_state) {
304 if (new_state == SHELF_HIDDEN) { 207 if (new_state == SHELF_HIDDEN)
305 StopTimer();
306 Close(); 208 Close();
307 }
308 } 209 }
309 210
310 void ShelfTooltipManager::OnAutoHideStateChanged(ShelfAutoHideState new_state) { 211 void ShelfTooltipManager::OnAutoHideStateChanged(ShelfAutoHideState new_state) {
311 if (new_state == SHELF_AUTO_HIDE_HIDDEN) { 212 if (new_state == SHELF_AUTO_HIDE_HIDDEN) {
312 StopTimer(); 213 timer_.Stop();
313 // AutoHide state change happens during an event filter, so immediate close 214 // AutoHide state change happens during an event filter, so immediate close
314 // may cause a crash in the HandleMouseEvent() after the filter. So we just 215 // may cause a crash in the HandleMouseEvent() after the filter. So we just
315 // schedule the Close here. 216 // schedule the Close here.
316 CloseSoon(); 217 base::ThreadTaskRunnerHandle::Get()->PostTask(
218 FROM_HERE,
219 base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr()));
317 } 220 }
318 } 221 }
319 222
320 void ShelfTooltipManager::CancelHidingAnimation() {
321 if (!widget_ || !widget_->GetNativeView())
322 return;
323
324 gfx::NativeView native_view = widget_->GetNativeView();
325 wm::SetWindowVisibilityAnimationTransition(
326 native_view, wm::ANIMATE_NONE);
327 }
328
329 void ShelfTooltipManager::CloseSoon() {
330 base::ThreadTaskRunnerHandle::Get()->PostTask(
331 FROM_HERE,
332 base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr()));
333 }
334
335 void ShelfTooltipManager::ShowInternal() {
336 if (view_)
337 view_->GetWidget()->Show();
338
339 timer_.reset();
340 }
341
342 void ShelfTooltipManager::CreateBubble(views::View* anchor,
343 const base::string16& text) {
344 DCHECK(!view_);
345
346 anchor_ = anchor;
347 text_ = text;
348 Shelf* shelf = shelf_layout_manager_->shelf_widget()->shelf();
349 views::BubbleBorder::Arrow arrow = shelf->SelectValueForShelfAlignment(
350 views::BubbleBorder::BOTTOM_CENTER, views::BubbleBorder::LEFT_CENTER,
351 views::BubbleBorder::RIGHT_CENTER, views::BubbleBorder::TOP_CENTER);
352
353 view_ = new ShelfTooltipBubble(anchor, arrow, this);
354 widget_ = view_->GetWidget();
355 view_->SetText(text_);
356
357 gfx::NativeView native_view = widget_->GetNativeView();
358 wm::SetWindowVisibilityAnimationType(
359 native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
360 wm::SetWindowVisibilityAnimationTransition(
361 native_view, wm::ANIMATE_HIDE);
362 }
363
364 void ShelfTooltipManager::CreateTimer(int delay_in_ms) {
365 base::OneShotTimer* new_timer = new base::OneShotTimer();
366 new_timer->Start(FROM_HERE,
367 base::TimeDelta::FromMilliseconds(delay_in_ms),
368 this,
369 &ShelfTooltipManager::ShowInternal);
370 timer_.reset(new_timer);
371 }
372
373 } // namespace ash 223 } // namespace ash
OLDNEW
« no previous file with comments | « ash/shelf/shelf_tooltip_manager.h ('k') | ash/shelf/shelf_tooltip_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698