OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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 "ui/message_center/views/message_popup_collection.h" | 5 #include "ui/message_center/views/message_popup_collection.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 15 matching lines...) Expand all Loading... |
26 #include "ui/views/view.h" | 26 #include "ui/views/view.h" |
27 #include "ui/views/widget/widget.h" | 27 #include "ui/views/widget/widget.h" |
28 #include "ui/views/widget/widget_delegate.h" | 28 #include "ui/views/widget/widget_delegate.h" |
29 | 29 |
30 namespace message_center { | 30 namespace message_center { |
31 namespace { | 31 namespace { |
32 | 32 |
33 // Timeout between the last user-initiated close of the toast and the moment | 33 // Timeout between the last user-initiated close of the toast and the moment |
34 // when normal layout/update of the toast stack continues. If the last toast was | 34 // when normal layout/update of the toast stack continues. If the last toast was |
35 // just closed, the timeout is shorter. | 35 // just closed, the timeout is shorter. |
36 const int kUpdateTimeoutOnUserActionMs = 2000; | 36 const int kMouseExitedDeferTimeoutMs = 200; |
37 const int kUpdateTimeoutOnUserActionEmptyMs = 700; | |
38 | 37 |
39 const int kToastMargin = kMarginBetweenItems; | 38 const int kToastMargin = kMarginBetweenItems; |
40 | 39 |
41 } // namespace. | 40 } // namespace. |
42 | 41 |
43 MessagePopupCollection::MessagePopupCollection(gfx::NativeView parent, | 42 MessagePopupCollection::MessagePopupCollection(gfx::NativeView parent, |
44 MessageCenter* message_center) | 43 MessageCenter* message_center) |
45 : parent_(parent), | 44 : parent_(parent), |
46 message_center_(message_center), | 45 message_center_(message_center), |
47 defer_counter_(0), | 46 defer_counter_(0), |
| 47 latest_toast_entered_(NULL), |
48 user_is_closing_toasts_by_clicking_(false) { | 48 user_is_closing_toasts_by_clicking_(false) { |
49 DCHECK(message_center_); | 49 DCHECK(message_center_); |
50 defer_timer_.reset(new base::OneShotTimer<MessagePopupCollection>); | 50 defer_timer_.reset(new base::OneShotTimer<MessagePopupCollection>); |
51 DoUpdateIfPossible(); | 51 DoUpdateIfPossible(); |
52 message_center_->AddObserver(this); | 52 message_center_->AddObserver(this); |
53 } | 53 } |
54 | 54 |
55 MessagePopupCollection::~MessagePopupCollection() { | 55 MessagePopupCollection::~MessagePopupCollection() { |
56 message_center_->RemoveObserver(this); | 56 message_center_->RemoveObserver(this); |
57 CloseAllWidgets(); | 57 CloseAllWidgets(); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 toasts_.push_back(toast); | 101 toasts_.push_back(toast); |
102 | 102 |
103 toast->RevealWithAnimation( | 103 toast->RevealWithAnimation( |
104 gfx::Point(base_position.x() - kToastMargin, bottom)); | 104 gfx::Point(base_position.x() - kToastMargin, bottom)); |
105 bottom -= view_height + kToastMargin; | 105 bottom -= view_height + kToastMargin; |
106 | 106 |
107 message_center_->DisplayedNotification((*iter)->id()); | 107 message_center_->DisplayedNotification((*iter)->id()); |
108 } | 108 } |
109 } | 109 } |
110 | 110 |
111 void MessagePopupCollection::OnMouseEntered() { | 111 void MessagePopupCollection::OnMouseEntered(ToastContentsView* toast_entered) { |
| 112 // Sometimes we can get two MouseEntered/MouseExited in a row when animating |
| 113 // toasts. So we need to keep track of which one is the currently active one. |
| 114 latest_toast_entered_ = toast_entered; |
| 115 |
112 for (Toasts::iterator iter = toasts_.begin(); iter != toasts_.end(); ++iter) { | 116 for (Toasts::iterator iter = toasts_.begin(); iter != toasts_.end(); ++iter) { |
113 (*iter)->SuspendTimer(); | 117 (*iter)->SuspendTimer(); |
114 } | 118 } |
| 119 |
| 120 if (user_is_closing_toasts_by_clicking_) |
| 121 defer_timer_->Stop(); |
115 } | 122 } |
116 | 123 |
117 void MessagePopupCollection::OnMouseExited() { | 124 void MessagePopupCollection::OnMouseExited(ToastContentsView* toast_exited) { |
118 for (Toasts::iterator iter = toasts_.begin(); iter != toasts_.end(); ++iter) { | 125 // If we're exiting a toast after entering a different toast, then ignore |
119 (*iter)->StartTimer(); | 126 // this mouse event. |
| 127 if (toast_exited != latest_toast_entered_) |
| 128 return; |
| 129 latest_toast_entered_ = NULL; |
| 130 |
| 131 if (user_is_closing_toasts_by_clicking_) { |
| 132 defer_timer_->Start( |
| 133 FROM_HERE, |
| 134 base::TimeDelta::FromMilliseconds(kMouseExitedDeferTimeoutMs), |
| 135 this, |
| 136 &MessagePopupCollection::OnDeferTimerExpired); |
| 137 } else { |
| 138 for (Toasts::iterator iter = toasts_.begin(); |
| 139 iter != toasts_.end(); |
| 140 ++iter) { |
| 141 (*iter)->StartTimer(); |
| 142 } |
120 } | 143 } |
121 } | 144 } |
122 | 145 |
123 void MessagePopupCollection::CloseAllWidgets() { | 146 void MessagePopupCollection::CloseAllWidgets() { |
124 for (Toasts::iterator iter = toasts_.begin(); iter != toasts_.end();) { | 147 for (Toasts::iterator iter = toasts_.begin(); iter != toasts_.end();) { |
125 // the toast can be removed from toasts_ during CloseWithAnimation(). | 148 // the toast can be removed from toasts_ during CloseWithAnimation(). |
126 Toasts::iterator curiter = iter++; | 149 Toasts::iterator curiter = iter++; |
127 (*curiter)->CloseWithAnimation(); | 150 (*curiter)->CloseWithAnimation(); |
128 } | 151 } |
129 DCHECK(toasts_.empty()); | 152 DCHECK(toasts_.empty()); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 // normal locations after tracking the mouse pointer for easy deletion. | 238 // normal locations after tracking the mouse pointer for easy deletion. |
216 // This provides a period of time when toasts are easy to remove because | 239 // This provides a period of time when toasts are easy to remove because |
217 // they re-position themselves to have Close button right under the mouse | 240 // they re-position themselves to have Close button right under the mouse |
218 // pointer. If the user continue to remove the toasts, the delay is reset. | 241 // pointer. If the user continue to remove the toasts, the delay is reset. |
219 // Once user stopped removing the toasts, the toasts re-populate/rearrange | 242 // Once user stopped removing the toasts, the toasts re-populate/rearrange |
220 // after the specified delay. | 243 // after the specified delay. |
221 if (!user_is_closing_toasts_by_clicking_) { | 244 if (!user_is_closing_toasts_by_clicking_) { |
222 user_is_closing_toasts_by_clicking_ = true; | 245 user_is_closing_toasts_by_clicking_ = true; |
223 IncrementDeferCounter(); | 246 IncrementDeferCounter(); |
224 } | 247 } |
225 int update_timeout = | |
226 toasts_.empty() ? kUpdateTimeoutOnUserActionEmptyMs : | |
227 kUpdateTimeoutOnUserActionMs; | |
228 defer_timer_->Start( | |
229 FROM_HERE, | |
230 base::TimeDelta::FromMilliseconds(update_timeout), | |
231 this, | |
232 &MessagePopupCollection::OnDeferTimerExpired); | |
233 } | 248 } |
234 } | 249 } |
235 | 250 |
236 void MessagePopupCollection::OnDeferTimerExpired() { | 251 void MessagePopupCollection::OnDeferTimerExpired() { |
237 user_is_closing_toasts_by_clicking_ = false; | 252 user_is_closing_toasts_by_clicking_ = false; |
238 DecrementDeferCounter(); | 253 DecrementDeferCounter(); |
| 254 |
| 255 for (Toasts::iterator iter = toasts_.begin(); iter != toasts_.end(); ++iter) { |
| 256 (*iter)->StartTimer(); |
| 257 } |
239 } | 258 } |
240 | 259 |
241 void MessagePopupCollection::OnNotificationUpdated( | 260 void MessagePopupCollection::OnNotificationUpdated( |
242 const std::string& notification_id) { | 261 const std::string& notification_id) { |
243 // Find a toast. | 262 // Find a toast. |
244 Toasts::iterator toast_iter = toasts_.begin(); | 263 Toasts::iterator toast_iter = toasts_.begin(); |
245 for (; toast_iter != toasts_.end(); ++toast_iter) { | 264 for (; toast_iter != toasts_.end(); ++toast_iter) { |
246 if ((*toast_iter)->id() == notification_id) | 265 if ((*toast_iter)->id() == notification_id) |
247 break; | 266 break; |
248 } | 267 } |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 views::Widget* widget = (*iter)->GetWidget(); | 368 views::Widget* widget = (*iter)->GetWidget(); |
350 if (widget) | 369 if (widget) |
351 return widget->GetWindowBoundsInScreen(); | 370 return widget->GetWindowBoundsInScreen(); |
352 break; | 371 break; |
353 } | 372 } |
354 } | 373 } |
355 return gfx::Rect(); | 374 return gfx::Rect(); |
356 } | 375 } |
357 | 376 |
358 } // namespace message_center | 377 } // namespace message_center |
OLD | NEW |