Chromium Code Reviews| 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 |