| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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 "base/command_line.h" | 5 #include "base/command_line.h" |
| 6 #include "ui/gfx/animation/slide_animation.h" | 6 #include "ui/gfx/animation/slide_animation.h" |
| 7 #include "ui/message_center/message_center_style.h" | 7 #include "ui/message_center/message_center_style.h" |
| 8 #include "ui/message_center/message_center_switches.h" | 8 #include "ui/message_center/message_center_switches.h" |
| 9 #include "ui/message_center/views/message_center_view.h" | 9 #include "ui/message_center/views/message_center_view.h" |
| 10 #include "ui/message_center/views/message_list_view.h" | 10 #include "ui/message_center/views/message_list_view.h" |
| 11 #include "ui/message_center/views/message_view.h" | 11 #include "ui/message_center/views/message_view.h" |
| 12 #include "ui/views/animation/bounds_animator.h" | |
| 13 #include "ui/views/background.h" | 12 #include "ui/views/background.h" |
| 14 #include "ui/views/border.h" | 13 #include "ui/views/border.h" |
| 15 #include "ui/views/layout/box_layout.h" | 14 #include "ui/views/layout/box_layout.h" |
| 16 #include "ui/views/widget/widget.h" | 15 #include "ui/views/widget/widget.h" |
| 17 | 16 |
| 18 namespace message_center { | 17 namespace message_center { |
| 19 | 18 |
| 20 namespace { | 19 namespace { |
| 21 const int kAnimateClearingNextNotificationDelayMS = 40; | 20 const int kAnimateClearingNextNotificationDelayMS = 40; |
| 22 } // namespace | 21 } // namespace |
| 23 | 22 |
| 24 MessageListView::MessageListView(MessageCenterView* message_center_view, | 23 MessageListView::MessageListView(MessageCenterView* message_center_view, |
| 25 bool top_down) | 24 bool top_down) |
| 26 : message_center_view_(message_center_view), | 25 : message_center_view_(message_center_view), |
| 27 reposition_top_(-1), | 26 reposition_top_(-1), |
| 28 fixed_height_(0), | 27 fixed_height_(0), |
| 29 has_deferred_task_(false), | 28 has_deferred_task_(false), |
| 30 clear_all_started_(false), | 29 clear_all_started_(false), |
| 31 top_down_(top_down), | 30 top_down_(top_down), |
| 31 animator_(this), |
| 32 weak_ptr_factory_(this) { | 32 weak_ptr_factory_(this) { |
| 33 views::BoxLayout* layout = | 33 views::BoxLayout* layout = |
| 34 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); | 34 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1); |
| 35 layout->SetDefaultFlex(1); | 35 layout->SetDefaultFlex(1); |
| 36 SetLayoutManager(layout); | 36 SetLayoutManager(layout); |
| 37 | 37 |
| 38 // Set the margin to 0 for the layout. BoxLayout assumes the same margin | 38 // Set the margin to 0 for the layout. BoxLayout assumes the same margin |
| 39 // for top and bottom, but the bottom margin here should be smaller | 39 // for top and bottom, but the bottom margin here should be smaller |
| 40 // because of the shadow of message view. Use an empty border instead | 40 // because of the shadow of message view. Use an empty border instead |
| 41 // to provide this margin. | 41 // to provide this margin. |
| 42 gfx::Insets shadow_insets = MessageView::GetShadowInsets(); | 42 gfx::Insets shadow_insets = MessageView::GetShadowInsets(); |
| 43 set_background( | 43 set_background( |
| 44 views::Background::CreateSolidBackground(kMessageCenterBackgroundColor)); | 44 views::Background::CreateSolidBackground(kMessageCenterBackgroundColor)); |
| 45 SetBorder(views::Border::CreateEmptyBorder( | 45 SetBorder(views::Border::CreateEmptyBorder( |
| 46 top_down ? 0 : kMarginBetweenItems - shadow_insets.top(), /* top */ | 46 top_down ? 0 : kMarginBetweenItems - shadow_insets.top(), /* top */ |
| 47 kMarginBetweenItems - shadow_insets.left(), /* left */ | 47 kMarginBetweenItems - shadow_insets.left(), /* left */ |
| 48 top_down ? kMarginBetweenItems - shadow_insets.bottom() : 0, /* bottom */ | 48 top_down ? kMarginBetweenItems - shadow_insets.bottom() : 0, /* bottom */ |
| 49 kMarginBetweenItems - shadow_insets.right() /* right */)); | 49 kMarginBetweenItems - shadow_insets.right() /* right */)); |
| 50 animator_.AddObserver(this); |
| 50 } | 51 } |
| 51 | 52 |
| 52 MessageListView::~MessageListView() { | 53 MessageListView::~MessageListView() { |
| 53 if (animator_.get()) | 54 animator_.RemoveObserver(this); |
| 54 animator_->RemoveObserver(this); | |
| 55 } | 55 } |
| 56 | 56 |
| 57 void MessageListView::Layout() { | 57 void MessageListView::Layout() { |
| 58 if (animator_.get() && animator_->IsAnimating()) | 58 if (animator_.IsAnimating()) |
| 59 return; | 59 return; |
| 60 | 60 |
| 61 gfx::Rect child_area = GetContentsBounds(); | 61 gfx::Rect child_area = GetContentsBounds(); |
| 62 int top = child_area.y(); | 62 int top = child_area.y(); |
| 63 int between_items = | 63 int between_items = |
| 64 kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); | 64 kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); |
| 65 | 65 |
| 66 for (int i = 0; i < child_count(); ++i) { | 66 for (int i = 0; i < child_count(); ++i) { |
| 67 views::View* child = child_at(i); | 67 views::View* child = child_at(i); |
| 68 if (!child->visible()) | 68 if (!child->visible()) |
| (...skipping 28 matching lines...) Expand all Loading... |
| 97 } | 97 } |
| 98 | 98 |
| 99 void MessageListView::RemoveNotification(MessageView* view) { | 99 void MessageListView::RemoveNotification(MessageView* view) { |
| 100 DCHECK_EQ(view->parent(), this); | 100 DCHECK_EQ(view->parent(), this); |
| 101 if (GetContentsBounds().IsEmpty()) { | 101 if (GetContentsBounds().IsEmpty()) { |
| 102 delete view; | 102 delete view; |
| 103 } else { | 103 } else { |
| 104 if (view->layer()) { | 104 if (view->layer()) { |
| 105 deleting_views_.insert(view); | 105 deleting_views_.insert(view); |
| 106 } else { | 106 } else { |
| 107 if (animator_.get()) | 107 animator_.StopAnimatingView(view); |
| 108 animator_->StopAnimatingView(view); | |
| 109 delete view; | 108 delete view; |
| 110 } | 109 } |
| 111 DoUpdateIfPossible(); | 110 DoUpdateIfPossible(); |
| 112 } | 111 } |
| 113 } | 112 } |
| 114 | 113 |
| 115 void MessageListView::UpdateNotification(MessageView* view, | 114 void MessageListView::UpdateNotification(MessageView* view, |
| 116 const Notification& notification) { | 115 const Notification& notification) { |
| 117 int index = GetIndexOf(view); | 116 int index = GetIndexOf(view); |
| 118 DCHECK_LE(0, index); // GetIndexOf is negative if not a child. | 117 DCHECK_LE(0, index); // GetIndexOf is negative if not a child. |
| 119 | 118 |
| 120 if (animator_.get()) | 119 animator_.StopAnimatingView(view); |
| 121 animator_->StopAnimatingView(view); | |
| 122 if (deleting_views_.find(view) != deleting_views_.end()) | 120 if (deleting_views_.find(view) != deleting_views_.end()) |
| 123 deleting_views_.erase(view); | 121 deleting_views_.erase(view); |
| 124 if (deleted_when_done_.find(view) != deleted_when_done_.end()) | 122 if (deleted_when_done_.find(view) != deleted_when_done_.end()) |
| 125 deleted_when_done_.erase(view); | 123 deleted_when_done_.erase(view); |
| 126 view->UpdateWithNotification(notification); | 124 view->UpdateWithNotification(notification); |
| 127 DoUpdateIfPossible(); | 125 DoUpdateIfPossible(); |
| 128 } | 126 } |
| 129 | 127 |
| 130 gfx::Size MessageListView::GetPreferredSize() const { | 128 gfx::Size MessageListView::GetPreferredSize() const { |
| 131 int width = 0; | 129 int width = 0; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 177 | 175 |
| 178 void MessageListView::SetRepositionTarget(const gfx::Rect& target) { | 176 void MessageListView::SetRepositionTarget(const gfx::Rect& target) { |
| 179 reposition_top_ = target.y(); | 177 reposition_top_ = target.y(); |
| 180 fixed_height_ = GetHeightForWidth(width()); | 178 fixed_height_ = GetHeightForWidth(width()); |
| 181 } | 179 } |
| 182 | 180 |
| 183 void MessageListView::ResetRepositionSession() { | 181 void MessageListView::ResetRepositionSession() { |
| 184 // Don't call DoUpdateIfPossible(), but let Layout() do the task without | 182 // Don't call DoUpdateIfPossible(), but let Layout() do the task without |
| 185 // animation. Reset will cause the change of the bubble size itself, and | 183 // animation. Reset will cause the change of the bubble size itself, and |
| 186 // animation from the old location will look weird. | 184 // animation from the old location will look weird. |
| 187 if (reposition_top_ >= 0 && animator_.get()) { | 185 if (reposition_top_ >= 0) { |
| 188 has_deferred_task_ = false; | 186 has_deferred_task_ = false; |
| 189 // cancel cause OnBoundsAnimatorDone which deletes |deleted_when_done_|. | 187 // cancel cause OnBoundsAnimatorDone which deletes |deleted_when_done_|. |
| 190 animator_->Cancel(); | 188 animator_.Cancel(); |
| 191 STLDeleteContainerPointers(deleting_views_.begin(), deleting_views_.end()); | 189 STLDeleteContainerPointers(deleting_views_.begin(), deleting_views_.end()); |
| 192 deleting_views_.clear(); | 190 deleting_views_.clear(); |
| 193 adding_views_.clear(); | 191 adding_views_.clear(); |
| 194 animator_.reset(); | |
| 195 } | 192 } |
| 196 | 193 |
| 197 reposition_top_ = -1; | 194 reposition_top_ = -1; |
| 198 fixed_height_ = 0; | 195 fixed_height_ = 0; |
| 199 } | 196 } |
| 200 | 197 |
| 201 void MessageListView::ClearAllNotifications( | 198 void MessageListView::ClearAllNotifications( |
| 202 const gfx::Rect& visible_scroll_rect) { | 199 const gfx::Rect& visible_scroll_rect) { |
| 203 for (int i = 0; i < child_count(); ++i) { | 200 for (int i = 0; i < child_count(); ++i) { |
| 204 views::View* child = child_at(i); | 201 views::View* child = child_at(i); |
| 205 if (!child->visible()) | 202 if (!child->visible()) |
| 206 continue; | 203 continue; |
| 207 if (gfx::IntersectRects(child->bounds(), visible_scroll_rect).IsEmpty()) | 204 if (gfx::IntersectRects(child->bounds(), visible_scroll_rect).IsEmpty()) |
| 208 continue; | 205 continue; |
| 209 clearing_all_views_.push_back(child); | 206 clearing_all_views_.push_back(child); |
| 210 } | 207 } |
| 211 DoUpdateIfPossible(); | 208 DoUpdateIfPossible(); |
| 212 } | 209 } |
| 213 | 210 |
| 214 void MessageListView::OnBoundsAnimatorProgressed( | 211 void MessageListView::OnBoundsAnimatorProgressed( |
| 215 views::BoundsAnimator* animator) { | 212 views::BoundsAnimator* animator) { |
| 216 DCHECK_EQ(animator_.get(), animator); | 213 DCHECK_EQ(&animator_, animator); |
| 217 for (std::set<views::View*>::iterator iter = deleted_when_done_.begin(); | 214 for (std::set<views::View*>::iterator iter = deleted_when_done_.begin(); |
| 218 iter != deleted_when_done_.end(); ++iter) { | 215 iter != deleted_when_done_.end(); ++iter) { |
| 219 const gfx::SlideAnimation* animation = animator->GetAnimationForView(*iter); | 216 const gfx::SlideAnimation* animation = animator->GetAnimationForView(*iter); |
| 220 if (animation) | 217 if (animation) |
| 221 (*iter)->layer()->SetOpacity(animation->CurrentValueBetween(1.0, 0.0)); | 218 (*iter)->layer()->SetOpacity(animation->CurrentValueBetween(1.0, 0.0)); |
| 222 } | 219 } |
| 223 } | 220 } |
| 224 | 221 |
| 225 void MessageListView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { | 222 void MessageListView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { |
| 226 STLDeleteContainerPointers(deleted_when_done_.begin(), | 223 STLDeleteContainerPointers(deleted_when_done_.begin(), |
| (...skipping 20 matching lines...) Expand all Loading... |
| 247 deleting_views_.end() && | 244 deleting_views_.end() && |
| 248 deleted_when_done_.find(const_cast<views::View*>(child)) == | 245 deleted_when_done_.find(const_cast<views::View*>(child)) == |
| 249 deleted_when_done_.end(); | 246 deleted_when_done_.end(); |
| 250 } | 247 } |
| 251 | 248 |
| 252 void MessageListView::DoUpdateIfPossible() { | 249 void MessageListView::DoUpdateIfPossible() { |
| 253 gfx::Rect child_area = GetContentsBounds(); | 250 gfx::Rect child_area = GetContentsBounds(); |
| 254 if (child_area.IsEmpty()) | 251 if (child_area.IsEmpty()) |
| 255 return; | 252 return; |
| 256 | 253 |
| 257 if (animator_.get() && animator_->IsAnimating()) { | 254 if (animator_.IsAnimating()) { |
| 258 has_deferred_task_ = true; | 255 has_deferred_task_ = true; |
| 259 return; | 256 return; |
| 260 } | 257 } |
| 261 | 258 |
| 262 if (!animator_.get()) { | |
| 263 animator_.reset(new views::BoundsAnimator(this)); | |
| 264 animator_->AddObserver(this); | |
| 265 } | |
| 266 | |
| 267 if (!clearing_all_views_.empty()) { | 259 if (!clearing_all_views_.empty()) { |
| 268 AnimateClearingOneNotification(); | 260 AnimateClearingOneNotification(); |
| 269 return; | 261 return; |
| 270 } | 262 } |
| 271 | 263 |
| 272 if (top_down_ || | 264 if (top_down_ || |
| 273 base::CommandLine::ForCurrentProcess()->HasSwitch( | 265 base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 274 switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)) | 266 switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)) |
| 275 AnimateNotificationsBelowTarget(); | 267 AnimateNotificationsBelowTarget(); |
| 276 else | 268 else |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 if (AnimateChild(child, bottom - child->height(), child->height())) | 324 if (AnimateChild(child, bottom - child->height(), child->height())) |
| 333 bottom -= child->height() + between_items; | 325 bottom -= child->height() + between_items; |
| 334 } | 326 } |
| 335 } | 327 } |
| 336 } | 328 } |
| 337 | 329 |
| 338 bool MessageListView::AnimateChild(views::View* child, int top, int height) { | 330 bool MessageListView::AnimateChild(views::View* child, int top, int height) { |
| 339 gfx::Rect child_area = GetContentsBounds(); | 331 gfx::Rect child_area = GetContentsBounds(); |
| 340 if (adding_views_.find(child) != adding_views_.end()) { | 332 if (adding_views_.find(child) != adding_views_.end()) { |
| 341 child->SetBounds(child_area.right(), top, child_area.width(), height); | 333 child->SetBounds(child_area.right(), top, child_area.width(), height); |
| 342 animator_->AnimateViewTo( | 334 animator_.AnimateViewTo( |
| 343 child, gfx::Rect(child_area.x(), top, child_area.width(), height)); | 335 child, gfx::Rect(child_area.x(), top, child_area.width(), height)); |
| 344 } else if (deleting_views_.find(child) != deleting_views_.end()) { | 336 } else if (deleting_views_.find(child) != deleting_views_.end()) { |
| 345 DCHECK(child->layer()); | 337 DCHECK(child->layer()); |
| 346 // No moves, but animate to fade-out. | 338 // No moves, but animate to fade-out. |
| 347 animator_->AnimateViewTo(child, child->bounds()); | 339 animator_.AnimateViewTo(child, child->bounds()); |
| 348 deleted_when_done_.insert(child); | 340 deleted_when_done_.insert(child); |
| 349 return false; | 341 return false; |
| 350 } else { | 342 } else { |
| 351 gfx::Rect target(child_area.x(), top, child_area.width(), height); | 343 gfx::Rect target(child_area.x(), top, child_area.width(), height); |
| 352 if (child->bounds().origin() != target.origin()) | 344 if (child->bounds().origin() != target.origin()) |
| 353 animator_->AnimateViewTo(child, target); | 345 animator_.AnimateViewTo(child, target); |
| 354 else | 346 else |
| 355 child->SetBoundsRect(target); | 347 child->SetBoundsRect(target); |
| 356 } | 348 } |
| 357 return true; | 349 return true; |
| 358 } | 350 } |
| 359 | 351 |
| 360 void MessageListView::AnimateClearingOneNotification() { | 352 void MessageListView::AnimateClearingOneNotification() { |
| 361 DCHECK(!clearing_all_views_.empty()); | 353 DCHECK(!clearing_all_views_.empty()); |
| 362 | 354 |
| 363 clear_all_started_ = true; | 355 clear_all_started_ = true; |
| 364 | 356 |
| 365 views::View* child = clearing_all_views_.front(); | 357 views::View* child = clearing_all_views_.front(); |
| 366 clearing_all_views_.pop_front(); | 358 clearing_all_views_.pop_front(); |
| 367 | 359 |
| 368 // Slide from left to right. | 360 // Slide from left to right. |
| 369 gfx::Rect new_bounds = child->bounds(); | 361 gfx::Rect new_bounds = child->bounds(); |
| 370 new_bounds.set_x(new_bounds.right() + kMarginBetweenItems); | 362 new_bounds.set_x(new_bounds.right() + kMarginBetweenItems); |
| 371 animator_->AnimateViewTo(child, new_bounds); | 363 animator_.AnimateViewTo(child, new_bounds); |
| 372 | 364 |
| 373 // Schedule to start sliding out next notification after a short delay. | 365 // Schedule to start sliding out next notification after a short delay. |
| 374 if (!clearing_all_views_.empty()) { | 366 if (!clearing_all_views_.empty()) { |
| 375 base::MessageLoop::current()->PostDelayedTask( | 367 base::MessageLoop::current()->PostDelayedTask( |
| 376 FROM_HERE, base::Bind(&MessageListView::AnimateClearingOneNotification, | 368 FROM_HERE, base::Bind(&MessageListView::AnimateClearingOneNotification, |
| 377 weak_ptr_factory_.GetWeakPtr()), | 369 weak_ptr_factory_.GetWeakPtr()), |
| 378 base::TimeDelta::FromMilliseconds( | 370 base::TimeDelta::FromMilliseconds( |
| 379 kAnimateClearingNextNotificationDelayMS)); | 371 kAnimateClearingNextNotificationDelayMS)); |
| 380 } | 372 } |
| 381 } | 373 } |
| 382 | 374 |
| 383 } // namespace message_center | 375 } // namespace message_center |
| OLD | NEW |