Commit 4c5a957f authored by jennyz@chromium.org's avatar jennyz@chromium.org

Implement animation UI for opening/closing an app list folder.

BUG=332506

Review URL: https://codereview.chromium.org/140203003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245314 0039d316-1c4b-4281-b951-d872f2087c98
parent 34da86a6
...@@ -36,11 +36,23 @@ const int kPageTransitionDurationInMs = 180; ...@@ -36,11 +36,23 @@ const int kPageTransitionDurationInMs = 180;
// Duration in milliseconds for over scroll page transition. // Duration in milliseconds for over scroll page transition.
const int kOverscrollPageTransitionDurationMs = 50; const int kOverscrollPageTransitionDurationMs = 50;
// Duration in milliseconds for the target page transition when opening or
// closing a folder.
const int kFolderTransitionInDurationMs = 200;
// Duration in milliseconds for fading out the old page when opening or
// closing a folder.
const int kFolderTransitionOutDurationMs = 30;
// Preferred number of columns and rows in apps grid. // Preferred number of columns and rows in apps grid.
const int kPreferredCols = 4; const int kPreferredCols = 4;
const int kPreferredRows = 4; const int kPreferredRows = 4;
const int kPreferredIconDimension = 48; const int kPreferredIconDimension = 48;
// Number of the top items in a folder, which are shown inside the folder icon
// and animated when opening and closing a folder.
const size_t kNumFolderTopItems = 4;
// Font style for app item labels. // Font style for app item labels.
const ui::ResourceBundle::FontStyle kItemTextFontStyle = const ui::ResourceBundle::FontStyle kItemTextFontStyle =
ui::ResourceBundle::SmallBoldFont; ui::ResourceBundle::SmallBoldFont;
......
...@@ -34,11 +34,15 @@ APP_LIST_EXPORT extern const SkColor kFolderBubbleColor; ...@@ -34,11 +34,15 @@ APP_LIST_EXPORT extern const SkColor kFolderBubbleColor;
APP_LIST_EXPORT extern const int kPageTransitionDurationInMs; APP_LIST_EXPORT extern const int kPageTransitionDurationInMs;
APP_LIST_EXPORT extern const int kOverscrollPageTransitionDurationMs; APP_LIST_EXPORT extern const int kOverscrollPageTransitionDurationMs;
APP_LIST_EXPORT extern const int kFolderTransitionInDurationMs;
APP_LIST_EXPORT extern const int kFolderTransitionOutDurationMs;
APP_LIST_EXPORT extern const int kPreferredCols; APP_LIST_EXPORT extern const int kPreferredCols;
APP_LIST_EXPORT extern const int kPreferredRows; APP_LIST_EXPORT extern const int kPreferredRows;
APP_LIST_EXPORT extern const int kPreferredIconDimension; APP_LIST_EXPORT extern const int kPreferredIconDimension;
APP_LIST_EXPORT extern const size_t kNumFolderTopItems;
APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle; APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle;
} // namespace app_list } // namespace app_list
......
...@@ -14,8 +14,6 @@ namespace app_list { ...@@ -14,8 +14,6 @@ namespace app_list {
namespace { namespace {
const int kIconDimension = 48;
const size_t kNumTopApps = 4;
const int kItemIconDimension = 16; const int kItemIconDimension = 16;
// Generates the folder icon with the top 4 child item icons laid in 2x2 tile. // Generates the folder icon with the top 4 child item icons laid in 2x2 tile.
...@@ -27,7 +25,7 @@ class FolderImageSource : public gfx::CanvasImageSource { ...@@ -27,7 +25,7 @@ class FolderImageSource : public gfx::CanvasImageSource {
: gfx::CanvasImageSource(size, false), : gfx::CanvasImageSource(size, false),
icons_(icons), icons_(icons),
size_(size) { size_(size) {
DCHECK(icons.size() <= kNumTopApps); DCHECK(icons.size() <= kNumFolderTopItems);
} }
virtual ~FolderImageSource() {} virtual ~FolderImageSource() {}
...@@ -57,30 +55,16 @@ class FolderImageSource : public gfx::CanvasImageSource { ...@@ -57,30 +55,16 @@ class FolderImageSource : public gfx::CanvasImageSource {
if (icons_.size() == 0) if (icons_.size() == 0)
return; return;
// Tiled icon coordinates. // Draw top items' icons.
const int delta_to_center = 1;
const gfx::Size item_icon_size = const gfx::Size item_icon_size =
gfx::Size(kItemIconDimension, kItemIconDimension); gfx::Size(kItemIconDimension, kItemIconDimension);
int left_x = center.x() - item_icon_size.width() - delta_to_center; Rects top_icon_bounds =
int top_y = center.y() - item_icon_size.height() - delta_to_center; AppListFolderItem::GetTopIconsBounds(gfx::Rect(size()));
int right_x = center.x() + delta_to_center;
int bottom_y = center.y() + delta_to_center; for (size_t i= 0; i < kNumFolderTopItems && i < icons_.size(); ++i) {
DrawIcon(canvas, icons_[i], item_icon_size,
// top left icon top_icon_bounds[i].x(), top_icon_bounds[i].y());
size_t i = 0; }
DrawIcon(canvas, icons_[i++], item_icon_size, left_x, top_y);
// top right icon
if (i < icons_.size())
DrawIcon(canvas, icons_[i++], item_icon_size, right_x, top_y);
// left bottm icon
if (i < icons_.size())
DrawIcon(canvas, icons_[i++], item_icon_size, left_x, bottom_y);
// right bottom icon
if (i < icons_.size())
DrawIcon(canvas, icons_[i], item_icon_size, right_x, bottom_y);
} }
Icons icons_; Icons icons_;
...@@ -108,13 +92,19 @@ void AppListFolderItem::UpdateIcon() { ...@@ -108,13 +92,19 @@ void AppListFolderItem::UpdateIcon() {
for (size_t i = 0; i < top_items_.size(); ++i) for (size_t i = 0; i < top_items_.size(); ++i)
top_icons.push_back(top_items_[i]->icon()); top_icons.push_back(top_items_[i]->icon());
const gfx::Size icon_size = gfx::Size(kIconDimension, kIconDimension); const gfx::Size icon_size =
gfx::Size(kPreferredIconDimension, kPreferredIconDimension);
gfx::ImageSkia icon = gfx::ImageSkia( gfx::ImageSkia icon = gfx::ImageSkia(
new FolderImageSource(top_icons, icon_size), new FolderImageSource(top_icons, icon_size),
icon_size); icon_size);
SetIcon(icon, false); SetIcon(icon, false);
} }
const gfx::ImageSkia& AppListFolderItem::GetTopIcon(size_t item_index) {
DCHECK(item_index <= top_items_.size());
return top_items_[item_index]->icon();
}
void AppListFolderItem::Activate(int event_flags) { void AppListFolderItem::Activate(int event_flags) {
// Folder handling is implemented by the View, so do nothing. // Folder handling is implemented by the View, so do nothing.
} }
...@@ -122,6 +112,38 @@ void AppListFolderItem::Activate(int event_flags) { ...@@ -122,6 +112,38 @@ void AppListFolderItem::Activate(int event_flags) {
// static // static
const char AppListFolderItem::kAppType[] = "FolderItem"; const char AppListFolderItem::kAppType[] = "FolderItem";
// static
Rects AppListFolderItem::GetTopIconsBounds(
const gfx::Rect& folder_icon_bounds) {
const int delta_to_center = 1;
gfx::Point icon_center = folder_icon_bounds.CenterPoint();
Rects top_icon_bounds;
// Get the top left icon bounds.
int left_x = icon_center.x() - kItemIconDimension - delta_to_center;
int top_y = icon_center.y() - kItemIconDimension - delta_to_center;
gfx::Rect top_left(left_x, top_y, kItemIconDimension, kItemIconDimension);
top_icon_bounds.push_back(top_left);
// Get the top right icon bounds.
int right_x = icon_center.x() + delta_to_center;
gfx::Rect top_right(right_x, top_y, kItemIconDimension, kItemIconDimension);
top_icon_bounds.push_back(top_right);
// Get the bottom left icon bounds.
int bottom_y = icon_center.y() + delta_to_center;
gfx::Rect bottom_left(
left_x, bottom_y, kItemIconDimension, kItemIconDimension);
top_icon_bounds.push_back(bottom_left);
// Get the bottom right icon bounds.
gfx::Rect bottom_right(
right_x, bottom_y, kItemIconDimension, kItemIconDimension);
top_icon_bounds.push_back(bottom_right);
return top_icon_bounds;
}
const char* AppListFolderItem::GetAppType() const { const char* AppListFolderItem::GetAppType() const {
return AppListFolderItem::kAppType; return AppListFolderItem::kAppType;
} }
...@@ -149,20 +171,20 @@ void AppListFolderItem::ItemPercentDownloadedChanged() { ...@@ -149,20 +171,20 @@ void AppListFolderItem::ItemPercentDownloadedChanged() {
void AppListFolderItem::OnListItemAdded(size_t index, void AppListFolderItem::OnListItemAdded(size_t index,
AppListItem* item) { AppListItem* item) {
if (index <= kNumTopApps) if (index <= kNumFolderTopItems)
UpdateTopItems(); UpdateTopItems();
} }
void AppListFolderItem::OnListItemRemoved(size_t index, void AppListFolderItem::OnListItemRemoved(size_t index,
AppListItem* item) { AppListItem* item) {
if (index <= kNumTopApps) if (index <= kNumFolderTopItems)
UpdateTopItems(); UpdateTopItems();
} }
void AppListFolderItem::OnListItemMoved(size_t from_index, void AppListFolderItem::OnListItemMoved(size_t from_index,
size_t to_index, size_t to_index,
AppListItem* item) { AppListItem* item) {
if (from_index <= kNumTopApps || to_index <= kNumTopApps) if (from_index <= kNumFolderTopItems || to_index <= kNumFolderTopItems)
UpdateTopItems(); UpdateTopItems();
} }
...@@ -172,7 +194,7 @@ void AppListFolderItem::UpdateTopItems() { ...@@ -172,7 +194,7 @@ void AppListFolderItem::UpdateTopItems() {
top_items_.clear(); top_items_.clear();
for (size_t i = 0; for (size_t i = 0;
i < kNumTopApps && i < item_list_->item_count(); ++i) { i < kNumFolderTopItems && i < item_list_->item_count(); ++i) {
AppListItem* item = item_list_->item_at(i); AppListItem* item = item_list_->item_at(i);
item->AddObserver(this); item->AddObserver(this);
top_items_.push_back(item); top_items_.push_back(item);
......
...@@ -12,11 +12,14 @@ ...@@ -12,11 +12,14 @@
#include "ui/app_list/app_list_item.h" #include "ui/app_list/app_list_item.h"
#include "ui/app_list/app_list_item_list_observer.h" #include "ui/app_list/app_list_item_list_observer.h"
#include "ui/app_list/app_list_item_observer.h" #include "ui/app_list/app_list_item_observer.h"
#include "ui/gfx/geometry/rect.h"
namespace app_list { namespace app_list {
class AppListItemList; class AppListItemList;
typedef std::vector<gfx::Rect> Rects;
// AppListFolderItem implements the model/controller for folders. // AppListFolderItem implements the model/controller for folders.
class APP_LIST_EXPORT AppListFolderItem : public AppListItem, class APP_LIST_EXPORT AppListFolderItem : public AppListItem,
public AppListItemListObserver, public AppListItemListObserver,
...@@ -28,10 +31,18 @@ class APP_LIST_EXPORT AppListFolderItem : public AppListItem, ...@@ -28,10 +31,18 @@ class APP_LIST_EXPORT AppListFolderItem : public AppListItem,
// Updates the folder's icon. // Updates the folder's icon.
void UpdateIcon(); void UpdateIcon();
// Returns the icon of one of the top items with |item_index|.
const gfx::ImageSkia& GetTopIcon(size_t item_index);
AppListItemList* item_list() { return item_list_.get(); } AppListItemList* item_list() { return item_list_.get(); }
static const char kAppType[]; static const char kAppType[];
// Calculates the top item icons' bounds inside |folder_icon_bounds|.
// Returns the bounds of top item icons in sequence of top left, top right,
// bottom left, bottom right.
static Rects GetTopIconsBounds(const gfx::Rect& folder_icon_bounds);
private: private:
// AppListItem // AppListItem
virtual void Activate(int event_flags) OVERRIDE; virtual void Activate(int event_flags) OVERRIDE;
......
...@@ -10,11 +10,13 @@ ...@@ -10,11 +10,13 @@
#include "ui/app_list/app_list_folder_item.h" #include "ui/app_list/app_list_folder_item.h"
#include "ui/app_list/app_list_model.h" #include "ui/app_list/app_list_model.h"
#include "ui/app_list/pagination_model.h" #include "ui/app_list/pagination_model.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/app_list_main_view.h"
#include "ui/app_list/views/apps_container_view.h" #include "ui/app_list/views/apps_container_view.h"
#include "ui/app_list/views/apps_grid_view.h" #include "ui/app_list/views/apps_grid_view.h"
#include "ui/app_list/views/contents_view.h" #include "ui/app_list/views/contents_view.h"
#include "ui/app_list/views/folder_header_view.h" #include "ui/app_list/views/folder_header_view.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/events/event.h" #include "ui/events/event.h"
#include "ui/views/view_model.h" #include "ui/views/view_model.h"
#include "ui/views/view_model_utils.h" #include "ui/views/view_model_utils.h"
...@@ -50,6 +52,11 @@ AppListFolderView::AppListFolderView(AppsContainerView* container_view, ...@@ -50,6 +52,11 @@ AppListFolderView::AppListFolderView(AppsContainerView* container_view,
items_grid_view_->SetModel(model); items_grid_view_->SetModel(model);
AddChildView(items_grid_view_); AddChildView(items_grid_view_);
view_model_->Add(items_grid_view_, kIndexChildItems); view_model_->Add(items_grid_view_, kIndexChildItems);
#if defined(USE_AURA)
SetPaintToLayer(true);
SetFillsBoundsOpaquely(false);
#endif
} }
AppListFolderView::~AppListFolderView() { AppListFolderView::~AppListFolderView() {
...@@ -63,6 +70,27 @@ void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) { ...@@ -63,6 +70,27 @@ void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) {
folder_header_view_->SetFolderItem(folder_item_); folder_header_view_->SetFolderItem(folder_item_);
} }
void AppListFolderView::ScheduleShowHideAnimation(bool show) {
// Stop any previous animation.
layer()->GetAnimator()->StopAnimating();
// Hide the top items temporarily if showing the view for opening the folder.
if (show)
items_grid_view_->SetTopItemViewsVisible(false);
// Set initial state.
SetVisible(true);
layer()->SetOpacity(show ? 0.0f : 1.0f);
ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
animation.SetTweenType(gfx::Tween::EASE_IN_2);
animation.AddObserver(this);
animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
show ? kFolderTransitionInDurationMs : kFolderTransitionOutDurationMs));
layer()->SetOpacity(show ? 1.0f : 0.0f);
}
gfx::Size AppListFolderView::GetPreferredSize() { gfx::Size AppListFolderView::GetPreferredSize() {
const gfx::Size header_size = folder_header_view_->GetPreferredSize(); const gfx::Size header_size = folder_header_view_->GetPreferredSize();
const gfx::Size grid_size = items_grid_view_->GetPreferredSize(); const gfx::Size grid_size = items_grid_view_->GetPreferredSize();
...@@ -80,6 +108,15 @@ bool AppListFolderView::OnKeyPressed(const ui::KeyEvent& event) { ...@@ -80,6 +108,15 @@ bool AppListFolderView::OnKeyPressed(const ui::KeyEvent& event) {
return items_grid_view_->OnKeyPressed(event); return items_grid_view_->OnKeyPressed(event);
} }
void AppListFolderView::OnImplicitAnimationsCompleted() {
// Show the top items when the opening folder animation is done.
if (layer()->opacity() == 1.0f)
items_grid_view_->SetTopItemViewsVisible(true);
if (layer()->opacity() == 0.0f)
SetVisible(false);
}
void AppListFolderView::CalculateIdealBounds() { void AppListFolderView::CalculateIdealBounds() {
gfx::Rect rect(GetContentsBounds()); gfx::Rect rect(GetContentsBounds());
if (rect.IsEmpty()) if (rect.IsEmpty())
...@@ -95,9 +132,24 @@ void AppListFolderView::CalculateIdealBounds() { ...@@ -95,9 +132,24 @@ void AppListFolderView::CalculateIdealBounds() {
view_model_->set_ideal_bounds(kIndexChildItems, grid_frame); view_model_->set_ideal_bounds(kIndexChildItems, grid_frame);
} }
gfx::Rect AppListFolderView::GetItemIconBoundsAt(int index) {
AppListItemView* item_view = items_grid_view_->GetItemViewAt(index);
// Icon bounds relative to AppListItemView.
const gfx::Rect icon_bounds = item_view->GetIconBounds();
gfx::Rect to_apps_grid_view = item_view->ConvertRectToParent(icon_bounds);
gfx::Rect to_folder =
items_grid_view_->ConvertRectToParent(to_apps_grid_view);
// Get the icon image's bound.
to_folder.ClampToCenteredSize(
gfx::Size(kPreferredIconDimension, kPreferredIconDimension));
return to_folder;
}
void AppListFolderView::NavigateBack(AppListFolderItem* item, void AppListFolderView::NavigateBack(AppListFolderItem* item,
const ui::Event& event_flags) { const ui::Event& event_flags) {
container_view_->ShowApps(); container_view_->ShowApps(item);
} }
} // namespace app_list } // namespace app_list
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "ui/app_list/views/folder_header_view.h" #include "ui/app_list/views/folder_header_view.h"
#include "ui/app_list/views/folder_header_view_delegate.h" #include "ui/app_list/views/folder_header_view_delegate.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
#include "ui/views/view.h" #include "ui/views/view.h"
...@@ -29,7 +30,8 @@ class FolderHeaderView; ...@@ -29,7 +30,8 @@ class FolderHeaderView;
class PaginationModel; class PaginationModel;
class AppListFolderView : public views::View, class AppListFolderView : public views::View,
public FolderHeaderViewDelegate { public FolderHeaderViewDelegate,
public ui::ImplicitAnimationObserver {
public: public:
AppListFolderView(AppsContainerView* container_view, AppListFolderView(AppsContainerView* container_view,
AppListModel* model, AppListModel* model,
...@@ -39,11 +41,21 @@ class AppListFolderView : public views::View, ...@@ -39,11 +41,21 @@ class AppListFolderView : public views::View,
void SetAppListFolderItem(AppListFolderItem* folder); void SetAppListFolderItem(AppListFolderItem* folder);
// Overridden from views::View: // Schedules an animation to show or hide the view.
void ScheduleShowHideAnimation(bool show);
// Gets icon image bounds of the item at |index|, relative to
// AppListFolderView.
gfx::Rect GetItemIconBoundsAt(int index);
// views::View overrides:
virtual gfx::Size GetPreferredSize() OVERRIDE; virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual void Layout() OVERRIDE; virtual void Layout() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
// ui::ImplicitAnimationObserver overrides:
virtual void OnImplicitAnimationsCompleted() OVERRIDE;
private: private:
void CalculateIdealBounds(); void CalculateIdealBounds();
......
...@@ -47,7 +47,7 @@ const int kLeftRightPaddingChars = 1; ...@@ -47,7 +47,7 @@ const int kLeftRightPaddingChars = 1;
const float kDraggingIconScale = 1.5f; const float kDraggingIconScale = 1.5f;
// Delay in milliseconds of when the dragging UI should be shown for mouse drag. // Delay in milliseconds of when the dragging UI should be shown for mouse drag.
const int kMouseDragUIDelayInMs = 100; const int kMouseDragUIDelayInMs = 200;
} // namespace } // namespace
...@@ -127,7 +127,7 @@ void AppListItemView::UpdateIcon() { ...@@ -127,7 +127,7 @@ void AppListItemView::UpdateIcon() {
icon_shadows_)); icon_shadows_));
icon_->SetImage(shadow); icon_->SetImage(shadow);
return; return;
}; }
icon_->SetImage(resized); icon_->SetImage(resized);
} }
...@@ -269,7 +269,6 @@ void AppListItemView::Layout() { ...@@ -269,7 +269,6 @@ void AppListItemView::Layout() {
gfx::Rect icon_bounds(rect.x(), y, rect.width(), icon_size_.height()); gfx::Rect icon_bounds(rect.x(), y, rect.width(), icon_size_.height());
icon_bounds.Inset(gfx::ShadowValue::GetMargin(icon_shadows_)); icon_bounds.Inset(gfx::ShadowValue::GetMargin(icon_shadows_));
icon_->SetBoundsRect(icon_bounds); icon_->SetBoundsRect(icon_bounds);
const gfx::Size title_size = title_->GetPreferredSize(); const gfx::Size title_size = title_->GetPreferredSize();
gfx::Rect title_bounds(rect.x() + (rect.width() - title_size.width()) / 2, gfx::Rect title_bounds(rect.x() + (rect.width() - title_size.width()) / 2,
y + icon_size_.height() + kIconTitleSpacing, y + icon_size_.height() + kIconTitleSpacing,
...@@ -463,4 +462,8 @@ void AppListItemView::OnSyncDragEnd() { ...@@ -463,4 +462,8 @@ void AppListItemView::OnSyncDragEnd() {
SetUIState(UI_STATE_NORMAL); SetUIState(UI_STATE_NORMAL);
} }
const gfx::Rect& AppListItemView::GetIconBounds() const {
return icon_->bounds();
}
} // namespace app_list } // namespace app_list
...@@ -61,6 +61,9 @@ class APP_LIST_EXPORT AppListItemView : public views::CustomButton, ...@@ -61,6 +61,9 @@ class APP_LIST_EXPORT AppListItemView : public views::CustomButton,
// ending, so the runner of the drag should call this. // ending, so the runner of the drag should call this.
void OnSyncDragEnd(); void OnSyncDragEnd();
// Returns the icon bounds relative to AppListItemView.
const gfx::Rect& GetIconBounds() const;
private: private:
enum UIState { enum UIState {
UI_STATE_NORMAL, // Normal UI (icon + label) UI_STATE_NORMAL, // Normal UI (icon + label)
......
...@@ -10,12 +10,107 @@ ...@@ -10,12 +10,107 @@
#include "ui/app_list/app_list_folder_item.h" #include "ui/app_list/app_list_folder_item.h"
#include "ui/app_list/pagination_model.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_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/app_list_main_view.h"
#include "ui/app_list/views/apps_grid_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/events/event.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/views/controls/image_view.h"
namespace app_list { 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:
TopIconAnimationView(const gfx::ImageSkia& icon,
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);
#endif
}
virtual ~TopIconAnimationView() {}
void AddObserver(TopIconAnimationObserver* observer) {
observers_.AddObserver(observer);
}
void RemoveObserver(TopIconAnimationObserver* observer) {
observers_.RemoveObserver(observer);
}
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);
}
private:
// views::View overrides:
virtual gfx::Size GetPreferredSize() OVERRIDE {
return icon_size_;
}
virtual void Layout() OVERRIDE {
icon_->SetBoundsRect(GetContentsBounds());
}
// ui::ImplicitAnimationObserver overrides:
virtual void OnImplicitAnimationsCompleted() OVERRIDE {
SetVisible(false);
FOR_EACH_OBSERVER(TopIconAnimationObserver,
observers_,
OnTopIconAnimationsComplete(this));
}
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, AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view,
PaginationModel* pagination_model, PaginationModel* pagination_model,
AppListModel* model, AppListModel* model,
...@@ -46,9 +141,14 @@ AppsContainerView::~AppsContainerView() { ...@@ -46,9 +141,14 @@ AppsContainerView::~AppsContainerView() {
void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) { void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) {
app_list_folder_view_->SetAppListFolderItem(folder_item); app_list_folder_view_->SetAppListFolderItem(folder_item);
SetShowState(SHOW_ACTIVE_FOLDER); 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); SetShowState(SHOW_APPS);
} }
...@@ -68,14 +168,14 @@ void AppsContainerView::Layout() { ...@@ -68,14 +168,14 @@ void AppsContainerView::Layout() {
switch (show_state_) { switch (show_state_) {
case SHOW_APPS: case SHOW_APPS:
app_list_folder_view_->SetVisible(false); app_list_folder_view_->ScheduleShowHideAnimation(false);
apps_grid_view_->SetBoundsRect(rect); apps_grid_view_->SetBoundsRect(rect);
apps_grid_view_->SetVisible(true); apps_grid_view_->ScheduleShowHideAnimation(true);
break; break;
case SHOW_ACTIVE_FOLDER: case SHOW_ACTIVE_FOLDER:
apps_grid_view_->SetVisible(false); apps_grid_view_->ScheduleShowHideAnimation(false);
app_list_folder_view_->SetBoundsRect(rect); app_list_folder_view_->SetBoundsRect(rect);
app_list_folder_view_->SetVisible(true); app_list_folder_view_->ScheduleShowHideAnimation(true);
break; break;
default: default:
NOTREACHED(); NOTREACHED();
...@@ -89,6 +189,31 @@ bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) { ...@@ -89,6 +189,31 @@ bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) {
return app_list_folder_view_->OnKeyPressed(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) { void AppsContainerView::SetShowState(ShowState show_state) {
if (show_state_ == show_state) if (show_state_ == show_state)
return; return;
...@@ -97,4 +222,38 @@ void AppsContainerView::SetShowState(ShowState show_state) { ...@@ -97,4 +222,38 @@ void AppsContainerView::SetShowState(ShowState show_state) {
Layout(); Layout();
} }
Rects 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)));
static_cast<TopIconAnimationView*>(top_icon_views_[i])->TransformView();
}
}
} // namespace app_list } // namespace app_list
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_ #ifndef UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
#define UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_ #define UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_
#include "ui/app_list/app_list_folder_item.h"
#include "ui/views/view.h" #include "ui/views/view.h"
namespace content { namespace content {
...@@ -21,10 +22,24 @@ class AppListModel; ...@@ -21,10 +22,24 @@ class AppListModel;
class ContentsView; class ContentsView;
class PaginationModel; class PaginationModel;
class TopIconAnimationObserver {
public:
// Called when top icon animation completes.
virtual void OnTopIconAnimationsComplete(views::View* icon_view) {}
protected:
TopIconAnimationObserver() {}
virtual ~TopIconAnimationObserver() {}
private:
DISALLOW_COPY_AND_ASSIGN(TopIconAnimationObserver);
};
// AppsContainerView contains a root level AppsGridView to render the root level // AppsContainerView contains a root level AppsGridView to render the root level
// app items, and a AppListFolderView to render the app items inside the // app items, and a AppListFolderView to render the app items inside the
// active folder. Only one if them is visible to user at any time. // active folder. Only one if them is visible to user at any time.
class AppsContainerView : public views::View { class AppsContainerView : public views::View,
public TopIconAnimationObserver {
public: public:
AppsContainerView(AppListMainView* app_list_main_view, AppsContainerView(AppListMainView* app_list_main_view,
PaginationModel* pagination_model, PaginationModel* pagination_model,
...@@ -35,14 +50,18 @@ class AppsContainerView : public views::View { ...@@ -35,14 +50,18 @@ class AppsContainerView : public views::View {
// Shows the active folder content specified by |folder_item|. // Shows the active folder content specified by |folder_item|.
void ShowActiveFolder(AppListFolderItem* folder_item); void ShowActiveFolder(AppListFolderItem* folder_item);
// Shows the apps list from root. // Shows the root level apps list. This is called when UI navigate back from
void ShowApps(); // a folder view with |folder_item|.
void ShowApps(AppListFolderItem* folder_item);
// Overridden from views::View: // Overridden from views::View:
virtual gfx::Size GetPreferredSize() OVERRIDE; virtual gfx::Size GetPreferredSize() OVERRIDE;
virtual void Layout() OVERRIDE; virtual void Layout() OVERRIDE;
virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE; virtual bool OnKeyPressed(const ui::KeyEvent& event) OVERRIDE;
// Overridden from TopIconAnimationObserver.
virtual void OnTopIconAnimationsComplete(views::View* icon_view) OVERRIDE;
AppsGridView* apps_grid_view() { return apps_grid_view_; } AppsGridView* apps_grid_view() { return apps_grid_view_; }
private: private:
...@@ -53,11 +72,26 @@ class AppsContainerView : public views::View { ...@@ -53,11 +72,26 @@ class AppsContainerView : public views::View {
void SetShowState(ShowState show_state); void SetShowState(ShowState show_state);
// Calculates the top item icon bounds in the active folder icon. The bounds
// is relative to AppsContainerView.
// Returns the bounds of top items' icon in sequence of top left, top right,
// bottom left, bottom right.
Rects GetTopItemIconBoundsInActiveFolder();
// Creates the transitional views for animating the top items in the folder
// when opening or closing a folder.
void CreateViewsForFolderTopItemsAnimation(
AppListFolderItem* active_folder, bool open_folder);
AppListModel* model_; AppListModel* model_;
AppsGridView* apps_grid_view_; // Owned by views hierarchy. AppsGridView* apps_grid_view_; // Owned by views hierarchy.
AppListFolderView* app_list_folder_view_; // Owned by views hierarchy. AppListFolderView* app_list_folder_view_; // Owned by views hierarchy.
ShowState show_state_; ShowState show_state_;
// The transitional views for animating the top items in folder
// when opening or closing a folder.
std::vector<views::View*> top_icon_views_;
DISALLOW_COPY_AND_ASSIGN(AppsContainerView); DISALLOW_COPY_AND_ASSIGN(AppsContainerView);
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "ui/app_list/app_list_switches.h" #include "ui/app_list/app_list_switches.h"
#include "ui/app_list/pagination_model.h" #include "ui/app_list/pagination_model.h"
#include "ui/app_list/views/app_list_drag_and_drop_host.h" #include "ui/app_list/views/app_list_drag_and_drop_host.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_item_view.h"
#include "ui/app_list/views/apps_grid_view_delegate.h" #include "ui/app_list/views/apps_grid_view_delegate.h"
#include "ui/app_list/views/page_switcher.h" #include "ui/app_list/views/page_switcher.h"
...@@ -347,7 +348,11 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate, ...@@ -347,7 +348,11 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate,
page_flip_target_(-1), page_flip_target_(-1),
page_flip_delay_in_ms_(kPageFlipDelayInMs), page_flip_delay_in_ms_(kPageFlipDelayInMs),
bounds_animator_(this), bounds_animator_(this),
is_root_level_(true) { is_root_level_(true),
activated_item_view_(NULL) {
SetPaintToLayer(true);
SetFillsBoundsOpaquely(false);
pagination_model_->AddObserver(this); pagination_model_->AddObserver(this);
AddChildView(page_switcher_view_); AddChildView(page_switcher_view_);
...@@ -651,6 +656,35 @@ void AppsGridView::StopPageFlipTimer() { ...@@ -651,6 +656,35 @@ void AppsGridView::StopPageFlipTimer() {
page_flip_target_ = -1; page_flip_target_ = -1;
} }
AppListItemView* AppsGridView::GetItemViewAt(int index) const {
DCHECK(index >= 0 && index < view_model_.view_size());
return static_cast<AppListItemView*>(view_model_.view_at(index));
}
void AppsGridView::SetTopItemViewsVisible(bool visible) {
int top_item_count = std::min(static_cast<int>(kNumFolderTopItems),
view_model_.view_size());
for (int i = 0; i < top_item_count; ++i)
GetItemViewAt(i)->SetVisible(visible);
}
void AppsGridView::ScheduleShowHideAnimation(bool show) {
// Stop any previous animation.
layer()->GetAnimator()->StopAnimating();
// Set initial state.
SetVisible(true);
layer()->SetOpacity(show ? 0.0f : 1.0f);
ui::ScopedLayerAnimationSettings animation(layer()->GetAnimator());
animation.AddObserver(this);
animation.SetTweenType(gfx::Tween::EASE_IN_2);
animation.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
show ? kFolderTransitionInDurationMs : kFolderTransitionOutDurationMs));
layer()->SetOpacity(show ? 1.0f : 0.0f);
}
bool AppsGridView::IsDraggedView(const views::View* view) const { bool AppsGridView::IsDraggedView(const views::View* view) const {
return drag_view_ == view; return drag_view_ == view;
} }
...@@ -1394,6 +1428,7 @@ void AppsGridView::ButtonPressed(views::Button* sender, ...@@ -1394,6 +1428,7 @@ void AppsGridView::ButtonPressed(views::Button* sender,
return; return;
if (delegate_) { if (delegate_) {
activated_item_view_ = static_cast<AppListItemView*>(sender);
delegate_->ActivateApp(static_cast<AppListItemView*>(sender)->item(), delegate_->ActivateApp(static_cast<AppListItemView*>(sender)->item(),
event.flags()); event.flags());
} }
...@@ -1501,6 +1536,11 @@ void AppsGridView::SetViewHidden(views::View* view, bool hide, bool immediate) { ...@@ -1501,6 +1536,11 @@ void AppsGridView::SetViewHidden(views::View* view, bool hide, bool immediate) {
#endif #endif
} }
void AppsGridView::OnImplicitAnimationsCompleted() {
if (layer()->opacity() == 0.0f)
SetVisible(false);
}
bool AppsGridView::EnableFolderDragDropUI() { bool AppsGridView::EnableFolderDragDropUI() {
// Enable drag and drop folder UI only if it is at the app list root level // Enable drag and drop folder UI only if it is at the app list root level
// and the switch is on and the target folder can still accept new items. // and the switch is on and the target folder can still accept new items.
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "ui/app_list/app_list_model_observer.h" #include "ui/app_list/app_list_model_observer.h"
#include "ui/app_list/pagination_model_observer.h" #include "ui/app_list/pagination_model_observer.h"
#include "ui/base/models/list_model_observer.h" #include "ui/base/models/list_model_observer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/views/animation/bounds_animator.h" #include "ui/views/animation/bounds_animator.h"
#include "ui/views/controls/button/button.h" #include "ui/views/controls/button/button.h"
#include "ui/views/view.h" #include "ui/views/view.h"
...@@ -55,7 +56,8 @@ class APP_LIST_EXPORT AppsGridView : public views::View, ...@@ -55,7 +56,8 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
public views::ButtonListener, public views::ButtonListener,
public AppListItemListObserver, public AppListItemListObserver,
public PaginationModelObserver, public PaginationModelObserver,
public AppListModelObserver { public AppListModelObserver,
public ui::ImplicitAnimationObserver {
public: public:
enum Pointer { enum Pointer {
NONE, NONE,
...@@ -138,6 +140,15 @@ class APP_LIST_EXPORT AppsGridView : public views::View, ...@@ -138,6 +140,15 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
// Stops the timer that triggers a page flip during a drag. // Stops the timer that triggers a page flip during a drag.
void StopPageFlipTimer(); void StopPageFlipTimer();
// Returns the item view of the item at |index|.
AppListItemView* GetItemViewAt(int index) const;
// Show or hide the top item views.
void SetTopItemViewsVisible(bool visible);
// Schedules an animation to show or hide the view.
void ScheduleShowHideAnimation(bool show);
// Return the view model for test purposes. // Return the view model for test purposes.
const views::ViewModel* view_model_for_test() const { return &view_model_; } const views::ViewModel* view_model_for_test() const { return &view_model_; }
...@@ -151,6 +162,10 @@ class APP_LIST_EXPORT AppsGridView : public views::View, ...@@ -151,6 +162,10 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
void set_is_root_level(bool value) { is_root_level_ = value; } void set_is_root_level(bool value) { is_root_level_ = value; }
AppListItemView* activated_item_view() const {
return activated_item_view_;
}
private: private:
friend class test::AppsGridViewTestApi; friend class test::AppsGridViewTestApi;
...@@ -291,6 +306,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View, ...@@ -291,6 +306,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
// Overridden from AppListModelObserver: // Overridden from AppListModelObserver:
virtual void OnAppListModelStatusChanged() OVERRIDE; virtual void OnAppListModelStatusChanged() OVERRIDE;
// ui::ImplicitAnimationObserver overrides:
virtual void OnImplicitAnimationsCompleted() OVERRIDE;
// Hide a given view temporarily without losing (mouse) events and / or // Hide a given view temporarily without losing (mouse) events and / or
// changing the size of it. If |immediate| is set the change will be // changing the size of it. If |immediate| is set the change will be
// immediately applied - otherwise it will change gradually. // immediately applied - otherwise it will change gradually.
...@@ -413,6 +431,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View, ...@@ -413,6 +431,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View,
// If true, AppsGridView is rending items at the root level of the app list. // If true, AppsGridView is rending items at the root level of the app list.
bool is_root_level_; bool is_root_level_;
// The most recent activated item view.
AppListItemView* activated_item_view_;
DISALLOW_COPY_AND_ASSIGN(AppsGridView); DISALLOW_COPY_AND_ASSIGN(AppsGridView);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment