| 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 "base/location.h" | 6 #include "base/location.h" |
| 7 #include "base/single_thread_task_runner.h" | 7 #include "base/single_thread_task_runner.h" |
| 8 #include "base/threading/thread_task_runner_handle.h" | 8 #include "base/threading/thread_task_runner_handle.h" |
| 9 #include "ui/gfx/animation/slide_animation.h" | 9 #include "ui/gfx/animation/slide_animation.h" |
| 10 #include "ui/message_center/message_center_style.h" | 10 #include "ui/message_center/message_center_style.h" |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 | 168 |
| 169 void MessageListView::ReorderChildLayers(ui::Layer* parent_layer) { | 169 void MessageListView::ReorderChildLayers(ui::Layer* parent_layer) { |
| 170 // Reorder children to stack the last child layer at the top. Otherwise | 170 // Reorder children to stack the last child layer at the top. Otherwise |
| 171 // upper notification may be hidden by the lower one. | 171 // upper notification may be hidden by the lower one. |
| 172 for (int i = 0; i < child_count(); ++i) { | 172 for (int i = 0; i < child_count(); ++i) { |
| 173 if (child_at(i)->layer()) | 173 if (child_at(i)->layer()) |
| 174 parent_layer->StackAtBottom(child_at(i)->layer()); | 174 parent_layer->StackAtBottom(child_at(i)->layer()); |
| 175 } | 175 } |
| 176 } | 176 } |
| 177 | 177 |
| 178 void MessageListView::UpdateFixedHeight(int requested_height, |
| 179 bool prevent_scroll) { |
| 180 int previous_fixed_height = fixed_height_; |
| 181 int min_height; |
| 182 |
| 183 // When the |prevent_scroll| flag is set, we use |fixed_height_|, which is the |
| 184 // bottom position of the visible rect. It's to keep the current visible |
| 185 // window, in other words, not to be scrolled, when the visible rect has a |
| 186 // blank area at the bottom. |
| 187 // Otherwise (in else block), we use the height of the visible rect to make |
| 188 // the height of the message list as small as possible. |
| 189 if (prevent_scroll) { |
| 190 // TODO(yoshiki): Consider the case with scrolling. If the message center |
| 191 // has scrollbar and its height is maximum, we may not need to keep the |
| 192 // height of the list in the scroll view. |
| 193 min_height = fixed_height_; |
| 194 } else { |
| 195 if (scroller_) { |
| 196 gfx::Rect visible_rect = scroller_->GetVisibleRect(); |
| 197 min_height = visible_rect.height(); |
| 198 } else { |
| 199 // Fallback for testing. |
| 200 min_height = fixed_height_; |
| 201 } |
| 202 } |
| 203 fixed_height_ = std::max(min_height, requested_height); |
| 204 |
| 205 if (previous_fixed_height != fixed_height_) { |
| 206 PreferredSizeChanged(); |
| 207 } |
| 208 } |
| 209 |
| 178 void MessageListView::SetRepositionTarget(const gfx::Rect& target) { | 210 void MessageListView::SetRepositionTarget(const gfx::Rect& target) { |
| 179 reposition_top_ = std::max(target.y(), 0); | 211 reposition_top_ = std::max(target.y(), 0); |
| 180 fixed_height_ = GetHeightForWidth(width()); | 212 UpdateFixedHeight(GetHeightForWidth(width()), false); |
| 181 } | 213 } |
| 182 | 214 |
| 183 void MessageListView::ResetRepositionSession() { | 215 void MessageListView::ResetRepositionSession() { |
| 184 // Don't call DoUpdateIfPossible(), but let Layout() do the task without | 216 // Don't call DoUpdateIfPossible(), but let Layout() do the task without |
| 185 // animation. Reset will cause the change of the bubble size itself, and | 217 // animation. Reset will cause the change of the bubble size itself, and |
| 186 // animation from the old location will look weird. | 218 // animation from the old location will look weird. |
| 187 if (reposition_top_ >= 0) { | 219 if (reposition_top_ >= 0) { |
| 188 has_deferred_task_ = false; | 220 has_deferred_task_ = false; |
| 189 // cancel cause OnBoundsAnimatorDone which deletes |deleted_when_done_|. | 221 // cancel cause OnBoundsAnimatorDone which deletes |deleted_when_done_|. |
| 190 animator_.Cancel(); | 222 animator_.Cancel(); |
| 191 for (auto* view : deleting_views_) | 223 for (auto* view : deleting_views_) |
| 192 delete view; | 224 delete view; |
| 193 deleting_views_.clear(); | 225 deleting_views_.clear(); |
| 194 adding_views_.clear(); | 226 adding_views_.clear(); |
| 195 } | 227 } |
| 196 | 228 |
| 197 reposition_top_ = -1; | 229 reposition_top_ = -1; |
| 198 fixed_height_ = 0; | 230 |
| 231 UpdateFixedHeight(fixed_height_, false); |
| 199 } | 232 } |
| 200 | 233 |
| 201 void MessageListView::ClearAllClosableNotifications( | 234 void MessageListView::ClearAllClosableNotifications( |
| 202 const gfx::Rect& visible_scroll_rect) { | 235 const gfx::Rect& visible_scroll_rect) { |
| 203 for (int i = 0; i < child_count(); ++i) { | 236 for (int i = 0; i < child_count(); ++i) { |
| 204 // Safe cast since all views in MessageListView are MessageViews. | 237 // Safe cast since all views in MessageListView are MessageViews. |
| 205 MessageView* child = (MessageView*)child_at(i); | 238 MessageView* child = (MessageView*)child_at(i); |
| 206 if (!child->visible()) | 239 if (!child->visible()) |
| 207 continue; | 240 continue; |
| 208 if (gfx::IntersectRects(child->bounds(), visible_scroll_rect).IsEmpty()) | 241 if (gfx::IntersectRects(child->bounds(), visible_scroll_rect).IsEmpty()) |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 return; | 316 return; |
| 284 } | 317 } |
| 285 | 318 |
| 286 int new_height = GetHeightForWidth(child_area.width() + GetInsets().width()); | 319 int new_height = GetHeightForWidth(child_area.width() + GetInsets().width()); |
| 287 SetSize(gfx::Size(child_area.width() + GetInsets().width(), new_height)); | 320 SetSize(gfx::Size(child_area.width() + GetInsets().width(), new_height)); |
| 288 | 321 |
| 289 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 322 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 290 switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)) | 323 switches::kEnableMessageCenterAlwaysScrollUpUponNotificationRemoval)) |
| 291 AnimateNotificationsBelowTarget(); | 324 AnimateNotificationsBelowTarget(); |
| 292 else | 325 else |
| 293 AnimateNotificationsAboveTarget(); | 326 AnimateNotifications(); |
| 294 | 327 |
| 295 adding_views_.clear(); | 328 adding_views_.clear(); |
| 296 deleting_views_.clear(); | 329 deleting_views_.clear(); |
| 297 | 330 |
| 298 if (!animator_.IsAnimating() && GetWidget()) | 331 if (!animator_.IsAnimating() && GetWidget()) |
| 299 GetWidget()->SynthesizeMouseMoveEvent(); | 332 GetWidget()->SynthesizeMouseMoveEvent(); |
| 300 } | 333 } |
| 301 | 334 |
| 335 // TODO(yoshiki): Remove this method. It is no longer maintained. |
| 302 void MessageListView::AnimateNotificationsBelowTarget() { | 336 void MessageListView::AnimateNotificationsBelowTarget() { |
| 303 int target_index = -1; | 337 int target_index = -1; |
| 304 int padding = kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); | 338 int padding = kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); |
| 305 gfx::Rect child_area = GetContentsBounds(); | 339 gfx::Rect child_area = GetContentsBounds(); |
| 306 if (reposition_top_ >= 0) { | 340 if (reposition_top_ >= 0) { |
| 307 for (int i = 0; i < child_count(); ++i) { | 341 for (int i = 0; i < child_count(); ++i) { |
| 308 views::View* child = child_at(i); | 342 views::View* child = child_at(i); |
| 309 if (child->y() >= reposition_top_) { | 343 if (child->y() >= reposition_top_) { |
| 310 // Find the target. | 344 // Find the target. |
| 311 target_index = i; | 345 target_index = i; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 DCHECK_EQ(heights.size(), deleting.size()); | 389 DCHECK_EQ(heights.size(), deleting.size()); |
| 356 // Calculate the vertical length between the top of message list and the top | 390 // Calculate the vertical length between the top of message list and the top |
| 357 // of target. This is to shrink or expand the height of the message list | 391 // of target. This is to shrink or expand the height of the message list |
| 358 // when the notifications above the target is changed. | 392 // when the notifications above the target is changed. |
| 359 int vertical_gap_to_target_from_top = GetInsets().top(); | 393 int vertical_gap_to_target_from_top = GetInsets().top(); |
| 360 for (int i = 0; i < target_index; i++) { | 394 for (int i = 0; i < target_index; i++) { |
| 361 if (!deleting[i]) | 395 if (!deleting[i]) |
| 362 vertical_gap_to_target_from_top += heights[i] + padding; | 396 vertical_gap_to_target_from_top += heights[i] + padding; |
| 363 } | 397 } |
| 364 | 398 |
| 365 // If the calculated length is changed from |repositon_top_|, it means that | 399 // If the calculated length is expanded from |repositon_top_|, it means that |
| 366 // some of items above the target are updated and their height are changed. | 400 // some of items above the target are updated and their height increased. |
| 367 // Adjust the vertical length above the target. | 401 // Adjust the vertical length above the target. |
| 368 fixed_height_ -= reposition_top_ - vertical_gap_to_target_from_top; | 402 if (vertical_gap_to_target_from_top > reposition_top_) { |
| 369 reposition_top_ = vertical_gap_to_target_from_top; | 403 fixed_height_ += vertical_gap_to_target_from_top - reposition_top_; |
| 404 reposition_top_ = vertical_gap_to_target_from_top; |
| 405 } |
| 406 |
| 407 // TODO(yoshiki): Scroll the parent container to keep the physical position |
| 408 // of the target notification when the scrolling is caused by a size change |
| 409 // of notification above. |
| 370 | 410 |
| 371 std::vector<int> positions; | 411 std::vector<int> positions; |
| 372 positions.reserve(heights.size()); | 412 positions.reserve(heights.size()); |
| 373 // Layout the items above the target. | 413 // Layout the items above the target. |
| 374 int y = GetInsets().top(); | 414 int y = GetInsets().top(); |
| 375 for (int i = 0; i < target_index; i++) { | 415 for (int i = 0; i < target_index; i++) { |
| 376 positions.push_back(y); | 416 positions.push_back(y); |
| 377 if (!deleting[i]) | 417 if (!deleting[i]) |
| 378 y += heights[i] + padding; | 418 y += heights[i] + padding; |
| 379 } | 419 } |
| 380 DCHECK_EQ(y, reposition_top_); | 420 DCHECK_EQ(y, vertical_gap_to_target_from_top); |
| 421 DCHECK_LE(y, reposition_top_); |
| 381 | 422 |
| 382 // Match the top with |reposition_top_|. | 423 // Match the top with |reposition_top_|. |
| 383 y = reposition_top_; | 424 y = reposition_top_; |
| 384 // Layout the target and the items below the target. | 425 // Layout the target and the items below the target. |
| 385 for (int i = target_index; i < int(heights.size()); i++) { | 426 for (int i = target_index; i < int(heights.size()); i++) { |
| 386 positions.push_back(y); | 427 positions.push_back(y); |
| 387 if (!deleting[i]) | 428 if (!deleting[i]) |
| 388 y += heights[i] + padding; | 429 y += heights[i] + padding; |
| 389 } | 430 } |
| 390 // If the target view, or any views below it expand they might exceed | 431 |
| 391 // |fixed_height_|. Rather than letting them push out the bottom and be | 432 // Update the fixed height. |requested_height| is the height to have all |
| 392 // clipped, instead increase |fixed_height_|. | 433 // notifications in the list and to keep the vertical position of the target |
| 393 fixed_height_ = std::max(fixed_height_, y - padding + GetInsets().bottom()); | 434 // notification. It may not just a total of all the notification heights if |
| 435 // the target exists. |
| 436 int requested_height = y - padding + GetInsets().bottom(); |
| 437 UpdateFixedHeight(requested_height, true); |
| 394 | 438 |
| 395 return positions; | 439 return positions; |
| 396 } | 440 } |
| 397 | 441 |
| 398 void MessageListView::AnimateNotificationsAboveTarget() { | 442 void MessageListView::AnimateNotifications() { |
| 399 int target_index = -1; | 443 int target_index = -1; |
| 400 int padding = kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); | 444 int padding = kMarginBetweenItems - MessageView::GetShadowInsets().bottom(); |
| 401 gfx::Rect child_area = GetContentsBounds(); | 445 gfx::Rect child_area = GetContentsBounds(); |
| 402 if (reposition_top_ >= 0) { | 446 if (reposition_top_ >= 0) { |
| 403 // Find the target item. | 447 // Find the target item. |
| 404 for (int i = 0; i < child_count(); ++i) { | 448 for (int i = 0; i < child_count(); ++i) { |
| 405 views::View* child = child_at(i); | 449 views::View* child = child_at(i); |
| 406 if (child->y() >= reposition_top_ && | 450 if (child->y() >= reposition_top_ && |
| 407 deleting_views_.find(child) == deleting_views_.end()) { | 451 deleting_views_.find(child) == deleting_views_.end()) { |
| 408 // Find the target. | 452 // Find the target. |
| 409 target_index = i; | 453 target_index = i; |
| 410 break; | 454 break; |
| 411 } | 455 } |
| 412 } | 456 } |
| 413 // If no items are below |reposition_top_|, use the last item as the target. | |
| 414 if (target_index == -1) { | |
| 415 target_index = child_count() - 1; | |
| 416 for (; target_index != -1; target_index--) { | |
| 417 views::View* target_view = child_at(target_index); | |
| 418 if (deleting_views_.find(target_view) == deleting_views_.end()) | |
| 419 break; | |
| 420 } | |
| 421 } | |
| 422 } | 457 } |
| 423 | 458 |
| 424 if (target_index != -1) { | 459 if (target_index != -1) { |
| 425 std::vector<int> heights; | 460 std::vector<int> heights; |
| 426 std::vector<bool> deleting; | 461 std::vector<bool> deleting; |
| 427 heights.reserve(child_count()); | 462 heights.reserve(child_count()); |
| 428 deleting.reserve(child_count()); | 463 deleting.reserve(child_count()); |
| 429 for (int i = 0; i < child_count(); i++) { | 464 for (int i = 0; i < child_count(); i++) { |
| 430 views::View* child = child_at(i); | 465 views::View* child = child_at(i); |
| 431 heights.push_back(child->GetHeightForWidth(child_area.width())); | 466 heights.push_back(child->GetHeightForWidth(child_area.width())); |
| 432 deleting.push_back(deleting_views_.find(child) != deleting_views_.end()); | 467 deleting.push_back(deleting_views_.find(child) != deleting_views_.end()); |
| 433 } | 468 } |
| 434 std::vector<int> ys = | 469 std::vector<int> ys = |
| 435 ComputeRepositionOffsets(heights, deleting, target_index, padding); | 470 ComputeRepositionOffsets(heights, deleting, target_index, padding); |
| 436 for (int i = 0; i < child_count(); ++i) { | 471 for (int i = 0; i < child_count(); ++i) { |
| 437 AnimateChild(child_at(i), ys[i], heights[i], true /* animate_on_move */); | 472 bool above_target = (i < target_index); |
| 473 AnimateChild(child_at(i), ys[i], heights[i], |
| 474 !above_target /* animate_on_move */); |
| 438 } | 475 } |
| 439 } else { | 476 } else { |
| 440 // Layout all the items. | 477 // Layout all the items. |
| 441 int y = GetInsets().top(); | 478 int y = GetInsets().top(); |
| 442 for (int i = 0; i < child_count(); ++i) { | 479 for (int i = 0; i < child_count(); ++i) { |
| 443 views::View* child = child_at(i); | 480 views::View* child = child_at(i); |
| 444 int height = child->GetHeightForWidth(child_area.width()); | 481 int height = child->GetHeightForWidth(child_area.width()); |
| 445 if (AnimateChild(child, y, height, true)) | 482 if (AnimateChild(child, y, height, true)) |
| 446 y += height + padding; | 483 y += height + padding; |
| 447 } | 484 } |
| 448 fixed_height_ = y - padding + GetInsets().bottom(); | 485 int new_height = y - padding + GetInsets().bottom(); |
| 486 UpdateFixedHeight(new_height, false); |
| 449 } | 487 } |
| 450 } | 488 } |
| 451 | 489 |
| 452 bool MessageListView::AnimateChild(views::View* child, | 490 bool MessageListView::AnimateChild(views::View* child, |
| 453 int top, | 491 int top, |
| 454 int height, | 492 int height, |
| 455 bool animate_on_move) { | 493 bool animate_on_move) { |
| 456 gfx::Rect child_area = GetContentsBounds(); | 494 gfx::Rect child_area = GetContentsBounds(); |
| 457 if (adding_views_.find(child) != adding_views_.end()) { | 495 if (adding_views_.find(child) != adding_views_.end()) { |
| 458 child->SetBounds(child_area.right(), top, child_area.width(), height); | 496 child->SetBounds(child_area.right(), top, child_area.width(), height); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 base::TimeDelta::FromMilliseconds( | 533 base::TimeDelta::FromMilliseconds( |
| 496 kAnimateClearingNextNotificationDelayMS)); | 534 kAnimateClearingNextNotificationDelayMS)); |
| 497 } | 535 } |
| 498 } | 536 } |
| 499 | 537 |
| 500 void MessageListView::SetRepositionTargetForTest(const gfx::Rect& target_rect) { | 538 void MessageListView::SetRepositionTargetForTest(const gfx::Rect& target_rect) { |
| 501 SetRepositionTarget(target_rect); | 539 SetRepositionTarget(target_rect); |
| 502 } | 540 } |
| 503 | 541 |
| 504 } // namespace message_center | 542 } // namespace message_center |
| OLD | NEW |