Index: ui/app_list/views/apps_container_view.cc |
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc |
index 6b3054d1a4781fa22a20e53bd63e32d7804098d6..18943fc2260d512ead88d647353b95ee1a871b31 100644 |
--- a/ui/app_list/views/apps_container_view.cc |
+++ b/ui/app_list/views/apps_container_view.cc |
@@ -10,12 +10,109 @@ |
#include "ui/app_list/app_list_folder_item.h" |
#include "ui/app_list/pagination_model.h" |
#include "ui/app_list/views/app_list_folder_view.h" |
+#include "ui/app_list/views/app_list_item_view.h" |
#include "ui/app_list/views/app_list_main_view.h" |
#include "ui/app_list/views/apps_grid_view.h" |
+#include "ui/compositor/scoped_layer_animation_settings.h" |
#include "ui/events/event.h" |
+#include "ui/gfx/image/image_skia_operations.h" |
+#include "ui/views/controls/image_view.h" |
namespace app_list { |
+namespace { |
+ |
+// Transitional view used for top item icons animation when opening or closing |
+// a folder. |
+class TopIconAnimationView : public views::View, |
+ public ui::ImplicitAnimationObserver { |
+ public: |
+ |
xiyuan
2014/01/16 01:46:48
nit: nuke empty line.
jennyz
2014/01/16 17:49:52
Done.
|
+ explicit TopIconAnimationView(const gfx::ImageSkia& icon, |
xiyuan
2014/01/16 01:46:48
nit: "explicit" is not needed when ctor takes more
jennyz
2014/01/16 17:49:52
Done.
|
+ const gfx::Rect& scaled_rect, |
+ bool open_folder) |
+ : icon_size_(kPreferredIconDimension, kPreferredIconDimension), |
+ icon_(new views::ImageView), |
+ scaled_rect_(scaled_rect), |
+ open_folder_(open_folder) { |
+ DCHECK(!icon.isNull()); |
+ gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage( |
+ icon, |
+ skia::ImageOperations::RESIZE_BEST, icon_size_)); |
+ icon_->SetImage(resized); |
+ AddChildView(icon_); |
+ |
+#if defined(USE_AURA) |
+ SetPaintToLayer(true); |
+ SetFillsBoundsOpaquely(false); |
xiyuan
2014/01/16 01:46:48
nit: 2 more space indent
jennyz
2014/01/16 17:49:52
Done.
|
+#endif |
+ } |
+ virtual ~TopIconAnimationView() {} |
+ |
+ void AddObserver(TopIconAnimationObserver* observer) { |
+ observers_.AddObserver(observer); |
+ } |
+ |
+ void RemoveObserver(TopIconAnimationObserver* observer) { |
+ observers_.RemoveObserver(observer); |
+ } |
+ |
+ private: |
+ // views::View overrides: |
+ virtual gfx::Size GetPreferredSize() OVERRIDE { |
+ return icon_size_; |
+ } |
+ |
+ virtual void Layout() OVERRIDE { |
+ icon_->SetBoundsRect(GetContentsBounds()); |
+ TransformView(); |
xiyuan
2014/01/16 01:46:48
TransforView() should not be called from Layout().
jennyz
2014/01/16 17:49:52
Done.
|
+ } |
+ |
+ // ui::ImplicitAnimationObserver overrides: |
+ virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
+ SetVisible(false); |
+ FOR_EACH_OBSERVER(TopIconAnimationObserver, |
+ observers_, |
+ OnTopIconAnimationsComplete(this)); |
+ } |
+ |
+ void TransformView() { |
+ // Transform used for scaling down the icon and move it back inside to the |
+ // original folder icon. |
+ const float kIconTransformScale = 0.33333f; |
+ gfx::Transform transform; |
+ transform.Translate(scaled_rect_.x() - layer()->bounds().x(), |
+ scaled_rect_.y() - layer()->bounds().y()); |
+ transform.Scale(kIconTransformScale, kIconTransformScale); |
+ |
+ if (open_folder_) { |
+ // Transform to a scaled down icon inside the original folder icon. |
+ layer()->SetTransform(transform); |
+ } |
+ |
+ // Animate the icon to its target location and scale when opening or |
+ // closing a folder. |
+ ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); |
+ settings.AddObserver(this); |
+ settings.SetTransitionDuration( |
+ base::TimeDelta::FromMilliseconds(kFolderTransitionInDurationMs)); |
+ layer()->SetTransform(open_folder_ ? gfx::Transform() : transform); |
+ } |
+ |
+ gfx::Size icon_size_; |
+ views::ImageView* icon_; // Owned by views hierarchy. |
+ // Rect of the scaled down top item icon inside folder icon's ink bubble. |
+ gfx::Rect scaled_rect_; |
+ // True: opening folder; False: closing folder. |
+ bool open_folder_; |
+ |
+ ObserverList<TopIconAnimationObserver> observers_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(TopIconAnimationView); |
+}; |
+ |
+} // namespace |
+ |
AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view, |
PaginationModel* pagination_model, |
AppListModel* model, |
@@ -46,9 +143,14 @@ AppsContainerView::~AppsContainerView() { |
void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) { |
app_list_folder_view_->SetAppListFolderItem(folder_item); |
SetShowState(SHOW_ACTIVE_FOLDER); |
+ |
+ CreateViewsForFolderTopItemsAnimation(folder_item, true); |
} |
-void AppsContainerView::ShowApps() { |
+void AppsContainerView::ShowApps(AppListFolderItem* folder_item) { |
+ CreateViewsForFolderTopItemsAnimation(folder_item, false); |
+ // Hide the active folder view until the animation completes. |
+ apps_grid_view_->activated_item_view()->SetVisible(false); |
SetShowState(SHOW_APPS); |
} |
@@ -68,14 +170,14 @@ void AppsContainerView::Layout() { |
switch (show_state_) { |
case SHOW_APPS: |
- app_list_folder_view_->SetVisible(false); |
+ app_list_folder_view_->ScheduleAnimationToShow(false); |
apps_grid_view_->SetBoundsRect(rect); |
- apps_grid_view_->SetVisible(true); |
+ apps_grid_view_->ScheduleAnimationToShow(true); |
break; |
case SHOW_ACTIVE_FOLDER: |
- apps_grid_view_->SetVisible(false); |
+ apps_grid_view_->ScheduleAnimationToShow(false); |
app_list_folder_view_->SetBoundsRect(rect); |
- app_list_folder_view_->SetVisible(true); |
+ app_list_folder_view_->ScheduleAnimationToShow(true); |
break; |
default: |
NOTREACHED(); |
@@ -89,6 +191,31 @@ bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) { |
return app_list_folder_view_->OnKeyPressed(event); |
} |
+void AppsContainerView::OnTopIconAnimationsComplete(views::View* icon_view) { |
+ bool animations_done = true; |
+ for (size_t i = 0; i < top_icon_views_.size(); ++i) { |
+ if (top_icon_views_[i]->visible()) { |
+ animations_done = false; |
+ break; |
+ } |
+ } |
+ |
+ if (animations_done) { |
+ // Clean up the transitional views using for top item icon animation. |
+ for (size_t i = 0; i < top_icon_views_.size(); ++i) { |
+ TopIconAnimationView* icon_view = |
+ static_cast<TopIconAnimationView*>(top_icon_views_[i]); |
+ icon_view->RemoveObserver(this); |
+ delete icon_view; |
+ } |
+ top_icon_views_.clear(); |
+ |
+ // Show the folder icon when closing the folder. |
+ if (show_state_ == SHOW_APPS && apps_grid_view_->activated_item_view()) |
+ apps_grid_view_->activated_item_view()->SetVisible(true); |
+ } |
+} |
+ |
void AppsContainerView::SetShowState(ShowState show_state) { |
if (show_state_ == show_state) |
return; |
@@ -97,4 +224,37 @@ void AppsContainerView::SetShowState(ShowState show_state) { |
Layout(); |
} |
+TopIconsBounds AppsContainerView::GetTopItemIconBoundsInActiveFolder() { |
+ // Get the active folder's icon bounds relative to AppsContainerView. |
+ AppListItemView* folder_view = apps_grid_view_->activated_item_view(); |
+ gfx::Rect to_grid_view = folder_view->ConvertRectToParent( |
+ folder_view->GetIconBounds()); |
+ gfx::Rect to_container = apps_grid_view_->ConvertRectToParent(to_grid_view); |
+ |
+ return AppListFolderItem::GetTopIconsBounds(to_container); |
+} |
+ |
+void AppsContainerView::CreateViewsForFolderTopItemsAnimation( |
+ AppListFolderItem* active_folder, |
+ bool open_folder) { |
+ top_icon_views_.clear(); |
+ std::vector<gfx::Rect> top_items_bounds = |
+ GetTopItemIconBoundsInActiveFolder(); |
+ size_t top_items_count = |
+ std::min(kNumFolderTopItems, active_folder->item_list()->item_count()); |
+ for (size_t i = 0; i < top_items_count; ++i) { |
+ TopIconAnimationView* icon_view = new TopIconAnimationView( |
+ active_folder->GetTopIcon(i), top_items_bounds[i], open_folder); |
+ icon_view->AddObserver(this); |
+ top_icon_views_.push_back(icon_view); |
+ |
+ // Add the transitional views into child views, and set its bounds to the |
+ // same location of the item in the folder list view. |
+ AddChildView(top_icon_views_[i]); |
+ top_icon_views_[i]->SetBoundsRect( |
+ app_list_folder_view_->ConvertRectToParent( |
+ app_list_folder_view_->GetItemIconBoundsAt(i))); |
+ } |
+} |
+ |
} // namespace app_list |