summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 17:06:59 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 17:06:59 +0000
commit665e2b7b8351b2ce82b7279325f65876df8f5283 (patch)
tree5b3e988e926b42d1e15037448628c17997029e81
parent8cb6d6e6d51c6abd996558daad179b1c4264e93f (diff)
downloadchromium_src-665e2b7b8351b2ce82b7279325f65876df8f5283.zip
chromium_src-665e2b7b8351b2ce82b7279325f65876df8f5283.tar.gz
chromium_src-665e2b7b8351b2ce82b7279325f65876df8f5283.tar.bz2
ash: Update app list UI to match latest crwm.
- Tile app list item horizontally; - Move item title to the bottom; - Update padding for model view: 45px from left/right and 32px from top/bottom; - Change shade from 0.4 black to 0.2 black; - Update animation; - Defer app list widget activation until showing animation is finished; BUG=117238,117073 TEST=Verify fix for issue 117238. Review URL: https://chromiumcodereview.appspot.com/9677065 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126665 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/app_list/app_list.cc83
-rw-r--r--ash/app_list/app_list.h17
-rw-r--r--ash/app_list/app_list_item_view.cc42
-rw-r--r--ash/app_list/app_list_item_view.h5
-rw-r--r--ash/app_list/app_list_model_view.cc105
-rw-r--r--ash/app_list/app_list_model_view.h3
-rw-r--r--ash/app_list/app_list_view.cc40
-rw-r--r--ash/app_list/app_list_view.h4
-rw-r--r--ui/gfx/transform_util.cc19
-rw-r--r--ui/gfx/transform_util.h23
-rw-r--r--ui/gfx/transform_util_unittest.cc28
-rw-r--r--ui/ui.gyp4
-rw-r--r--ui/ui_unittests.gypi1
13 files changed, 239 insertions, 135 deletions
diff --git a/ash/app_list/app_list.cc b/ash/app_list/app_list.cc
index 0f0c612..df2c95d 100644
--- a/ash/app_list/app_list.cc
+++ b/ash/app_list/app_list.cc
@@ -13,12 +13,15 @@
#include "ui/aura/window.h"
#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/transform_util.h"
namespace ash {
namespace internal {
namespace {
+const float kDefaultContainerAnimationScaleFactor = 1.05f;
+
// Gets preferred bounds of app list window.
gfx::Rect GetPreferredBounds() {
gfx::Point cursor = gfx::Screen::GetCursorScreenPoint();
@@ -35,11 +38,11 @@ ui::Layer* GetLayer(views::Widget* widget) {
////////////////////////////////////////////////////////////////////////////////
// AppList, public:
-AppList::AppList() : is_visible_(false), widget_(NULL) {
+AppList::AppList() : is_visible_(false), view_(NULL) {
}
AppList::~AppList() {
- ResetWidget();
+ ResetView();
}
void AppList::SetVisible(bool visible) {
@@ -48,53 +51,53 @@ void AppList::SetVisible(bool visible) {
is_visible_ = visible;
- if (widget_) {
+ if (view_) {
ScheduleAnimation();
} else if (is_visible_) {
// AppListModel and AppListViewDelegate are owned by AppListView. They
// will be released with AppListView on close.
- AppListView* app_list_view = new AppListView(
+ SetView(new AppListView(
Shell::GetInstance()->delegate()->CreateAppListViewDelegate(),
- GetPreferredBounds());
- SetWidget(app_list_view->GetWidget());
+ GetPreferredBounds()));
}
}
bool AppList::IsVisible() {
- return widget_ && widget_->IsVisible();
+ return view_ && view_->GetWidget()->IsVisible();
}
////////////////////////////////////////////////////////////////////////////////
// AppList, private:
-void AppList::SetWidget(views::Widget* widget) {
- DCHECK(widget_ == NULL);
+void AppList::SetView(AppListView* view) {
+ DCHECK(view_ == NULL);
if (is_visible_) {
- widget_ = widget;
- widget_->AddObserver(this);
+ view_ = view;
+ views::Widget* widget = view_->GetWidget();
+ widget->AddObserver(this);
Shell::GetInstance()->AddRootWindowEventFilter(this);
widget->GetNativeView()->GetRootWindow()->AddRootWindowObserver(this);
- widget_->SetOpacity(0);
+ widget->SetOpacity(0);
ScheduleAnimation();
- widget_->Show();
- widget_->Activate();
+ view_->GetWidget()->Show();
} else {
- widget->Close();
+ view->GetWidget()->Close();
}
}
-void AppList::ResetWidget() {
- if (!widget_)
+void AppList::ResetView() {
+ if (!view_)
return;
- widget_->RemoveObserver(this);
- GetLayer(widget_)->GetAnimator()->RemoveObserver(this);
+ views::Widget* widget = view_->GetWidget();
+ widget->RemoveObserver(this);
+ GetLayer(widget)->GetAnimator()->RemoveObserver(this);
Shell::GetInstance()->RemoveRootWindowEventFilter(this);
- widget_->GetNativeView()->GetRootWindow()->RemoveRootWindowObserver(this);
- widget_ = NULL;
+ widget->GetNativeView()->GetRootWindow()->RemoveRootWindowObserver(this);
+ view_ = NULL;
}
void AppList::ScheduleAnimation() {
@@ -104,7 +107,7 @@ void AppList::ScheduleAnimation() {
if (!default_container)
return;
- ui::Layer* layer = GetLayer(widget_);
+ ui::Layer* layer = GetLayer(view_->GetWidget());
// Stop observing previous animation.
StopObservingImplicitAnimations();
@@ -113,11 +116,22 @@ void AppList::ScheduleAnimation() {
app_list_animation.AddObserver(this);
layer->SetOpacity(is_visible_ ? 1.0 : 0.0);
+ if (is_visible_)
+ view_->AnimateShow();
+ else
+ view_->AnimateHide();
+
ui::Layer* default_container_layer = default_container->layer();
ui::ScopedLayerAnimationSettings default_container_animation(
default_container_layer->GetAnimator());
app_list_animation.AddObserver(this);
default_container_layer->SetOpacity(is_visible_ ? 0.0 : 1.0);
+ default_container_layer->SetTransform(is_visible_ ?
+ ui::GetScaleTransform(
+ gfx::Point(default_container_layer->bounds().width() / 2,
+ default_container_layer->bounds().height() / 2),
+ kDefaultContainerAnimationScaleFactor) :
+ ui::Transform());
}
////////////////////////////////////////////////////////////////////////////////
@@ -130,9 +144,10 @@ bool AppList::PreHandleKeyEvent(aura::Window* target,
bool AppList::PreHandleMouseEvent(aura::Window* target,
aura::MouseEvent* event) {
- if (widget_ && is_visible_ && event->type() == ui::ET_MOUSE_PRESSED) {
- aura::MouseEvent translated(*event, target, widget_->GetNativeView());
- if (!widget_->GetNativeView()->ContainsPoint(translated.location()))
+ if (view_ && is_visible_ && event->type() == ui::ET_MOUSE_PRESSED) {
+ views::Widget* widget = view_->GetWidget();
+ aura::MouseEvent translated(*event, target, widget->GetNativeView());
+ if (!widget->GetNativeView()->ContainsPoint(translated.location()))
SetVisible(false);
}
return false;
@@ -152,31 +167,33 @@ ui::GestureStatus AppList::PreHandleGestureEvent(
////////////////////////////////////////////////////////////////////////////////
// AppList, ura::RootWindowObserver implementation:
void AppList::OnRootWindowResized(const gfx::Size& new_size) {
- if (widget_ && is_visible_)
- widget_->SetBounds(gfx::Rect(new_size));
+ if (view_&& is_visible_)
+ view_->GetWidget()->SetBounds(gfx::Rect(new_size));
}
////////////////////////////////////////////////////////////////////////////////
// AppList, ui::ImplicitAnimationObserver implementation:
void AppList::OnImplicitAnimationsCompleted() {
- if (!is_visible_ )
- widget_->Close();
+ if (is_visible_ )
+ view_->GetWidget()->Activate();
+ else
+ view_->GetWidget()->Close();
}
////////////////////////////////////////////////////////////////////////////////
// AppList, views::Widget::Observer implementation:
void AppList::OnWidgetClosing(views::Widget* widget) {
- DCHECK(widget_ == widget);
+ DCHECK(view_->GetWidget() == widget);
if (is_visible_)
SetVisible(false);
- ResetWidget();
+ ResetView();
}
void AppList::OnWidgetActivationChanged(views::Widget* widget, bool active) {
- DCHECK(widget_ == widget);
- if (widget_ && is_visible_ && !active)
+ DCHECK(view_->GetWidget() == widget);
+ if (view_ && is_visible_ && !active)
SetVisible(false);
}
diff --git a/ash/app_list/app_list.h b/ash/app_list/app_list.h
index a786c35..c7e29f0 100644
--- a/ash/app_list/app_list.h
+++ b/ash/app_list/app_list.h
@@ -14,6 +14,9 @@
#include "ui/views/widget/widget.h"
namespace ash {
+
+class AppListView;
+
namespace internal {
// AppList is a controller that manages app list UI for shell. To show the UI,
@@ -35,12 +38,12 @@ class AppList : public aura::EventFilter,
bool IsVisible();
private:
- // Sets app list widget. If we are in visible mode, start showing animation.
- // Otherwise, we just close the widget.
- void SetWidget(views::Widget* widget);
+ // Sets app list view. If we are in visible mode, start showing animation.
+ // Otherwise, we just close it.
+ void SetView(AppListView* view);
- // Forgets the widget.
- void ResetWidget();
+ // Forgets the view.
+ void ResetView();
// Starts show/hide animation.
void ScheduleAnimation();
@@ -70,8 +73,8 @@ class AppList : public aura::EventFilter,
// Whether we should show or hide app list widget.
bool is_visible_;
- // App list widget we get from ShellDelegate.
- views::Widget* widget_;
+ // The AppListView this class manages, owned by its widget.
+ AppListView* view_;
DISALLOW_COPY_AND_ASSIGN(AppList);
};
diff --git a/ash/app_list/app_list_item_view.cc b/ash/app_list/app_list_item_view.cc
index 92c0c22..bac1724 100644
--- a/ash/app_list/app_list_item_view.cc
+++ b/ash/app_list/app_list_item_view.cc
@@ -22,7 +22,9 @@ namespace ash {
namespace {
-const int kIconTitleSpacing = 5;
+const int kPadding = 10;
+const int kIconTitleSpacing = 10;
+const int kMinLabelWidth = 150;
const SkColor kTitleColor = SK_ColorWHITE;
@@ -74,7 +76,6 @@ AppListItemView::AppListItemView(AppListModelView* list_model_view,
title_->SetFont(GetTitleFont());
title_->SetBackgroundColor(0);
title_->SetEnabledColor(kTitleColor);
- title_->SetHorizontalAlignment(views::Label::ALIGN_LEFT);
AddChildView(icon_);
AddChildView(title_);
@@ -91,6 +92,16 @@ AppListItemView::~AppListItemView() {
model_->RemoveObserver(this);
}
+// static
+gfx::Size AppListItemView::GetPreferredSizeForIconSize(
+ const gfx::Size& icon_size) {
+ gfx::Size size(
+ std::max(icon_size.width() + icon_size.width() / 2, kMinLabelWidth),
+ icon_size.height() + kIconTitleSpacing + GetTitleFont().GetHeight());
+ size.Enlarge(2 * kPadding, 2 * kPadding);
+ return size;
+}
+
void AppListItemView::SetSelected(bool selected) {
if (selected == selected_)
return;
@@ -112,27 +123,24 @@ std::string AppListItemView::GetClassName() const {
}
gfx::Size AppListItemView::GetPreferredSize() {
- gfx::Size title_size = title_->GetPreferredSize();
-
- gfx::Size preferred_size(
- icon_size_.width() + kIconTitleSpacing + title_size.width(),
- std::max(icon_size_.height(), title_size.height()));
- preferred_size.Enlarge(2 * kPadding, 2 * kPadding);
- return preferred_size;
+ return GetPreferredSizeForIconSize(icon_size_);
}
void AppListItemView::Layout() {
gfx::Rect rect(GetContentsBounds());
+ rect.Inset(kPadding, kPadding);
+ gfx::Size title_size = title_->GetPreferredSize();
icon_->SetImageSize(icon_size_);
- icon_->SetBounds(rect.x() + kPadding, rect.y(),
- icon_size_.width(), rect.height());
-
- title_->SetBounds(
- icon_->bounds().right() + kIconTitleSpacing,
- rect.y(),
- rect.right() - kPadding - icon_->bounds().right() - kIconTitleSpacing,
- rect.height());
+ icon_->SetBounds(rect.x(),
+ rect.y(),
+ rect.width(),
+ icon_size_.height());
+
+ title_->SetBounds(rect.x(),
+ icon_->bounds().bottom() + kIconTitleSpacing,
+ rect.width(),
+ title_size.height());
}
void AppListItemView::OnPaint(gfx::Canvas* canvas) {
diff --git a/ash/app_list/app_list_item_view.h b/ash/app_list/app_list_item_view.h
index 3f2123d..cdc315a 100644
--- a/ash/app_list/app_list_item_view.h
+++ b/ash/app_list/app_list_item_view.h
@@ -33,6 +33,8 @@ class AppListItemView : public views::CustomButton,
views::ButtonListener* listener);
virtual ~AppListItemView();
+ static gfx::Size GetPreferredSizeForIconSize(const gfx::Size& icon_size);
+
void SetSelected(bool selected);
bool selected() const {
return selected_;
@@ -46,9 +48,6 @@ class AppListItemView : public views::CustomButton,
icon_size_ = size;
}
- // Icon padding
- static const int kPadding = 5;
-
// Internal class name.
static const char kViewClassName[];
diff --git a/ash/app_list/app_list_model_view.cc b/ash/app_list/app_list_model_view.cc
index b37414c..7ff7741 100644
--- a/ash/app_list/app_list_model_view.cc
+++ b/ash/app_list/app_list_model_view.cc
@@ -6,46 +6,31 @@
#include "ash/app_list/app_list_item_view.h"
#include "ash/app_list/app_list_model.h"
-#include "base/utf_string_conversions.h"
namespace ash {
namespace {
-// Minimum label width.
-const int kMinLabelWidth = 150;
-
-// Calculate preferred tile size for given |content_size| and |num_of_tiles|.
-gfx::Size CalculateTileSize(const gfx::Size& content_size, int num_of_tiles) {
+// Calculate preferred icon size for given |content_size| and |num_of_tiles|.
+gfx::Size CalculateIconSize(const gfx::Size& content_size, int num_of_tiles) {
// Icon sizes to try.
- const int kIconSizes[] = { 64, 48, 32, 16 };
-
- int tile_height = 0;
- int tile_width = 0;
- int rows = 0;
- int cols = 0;
+ const int kIconSizes[] = { 64, 48, 32 };
// Chooses the biggest icon size that could fit all tiles.
+ gfx::Size icon_size;
for (size_t i = 0; i < arraysize(kIconSizes); ++i) {
- int icon_size = kIconSizes[i];
- tile_height = icon_size + 2 * AppListItemView::kPadding;
- tile_width = icon_size + std::min(kMinLabelWidth, icon_size * 2) +
- 2 * AppListItemView::kPadding;
-
- rows = std::max(content_size.height() / tile_height, 1);
- cols = std::min(content_size.width() / tile_width,
- (num_of_tiles - 1) / rows + 1);
+ icon_size.SetSize(kIconSizes[i], kIconSizes[i]);
+ gfx::Size tile_size = AppListItemView::GetPreferredSizeForIconSize(
+ icon_size);
+
+ int cols = std::max(content_size.width() / tile_size.width(), 1);
+ int rows = std::min(content_size.height() / tile_size.height(),
+ (num_of_tiles - 1) / cols + 1);
if (rows * cols >= num_of_tiles)
break;
}
- if (rows && cols) {
- // Adjusts tile width to fit |content_size| as much as possible.
- tile_width = std::max(tile_width, content_size.width() / cols);
- return gfx::Size(tile_width, tile_height);
- }
-
- return gfx::Size();
+ return icon_size;
}
} // namespace
@@ -54,7 +39,7 @@ AppListModelView::AppListModelView(views::ButtonListener* listener)
: model_(NULL),
listener_(listener),
selected_item_index_(-1),
- items_per_col_(0) {
+ items_per_row_(0) {
set_focusable(true);
}
@@ -118,48 +103,34 @@ void AppListModelView::SetSelectedItemByIndex(int index) {
}
}
-int AppListModelView::SetTileIconSizeAndGetMaxWidth(int icon_dimension) {
- gfx::Size icon_size(icon_dimension, icon_dimension);
- int max_tile_width = 0;
- for (int i = 0; i < child_count(); ++i) {
- views::View* view = child_at(i);
- static_cast<AppListItemView*>(view)->set_icon_size(icon_size);
- gfx::Size preferred_size = view->GetPreferredSize();
- if (preferred_size.width() > max_tile_width)
- max_tile_width = preferred_size.width();
- }
-
- return max_tile_width;
-}
-
void AppListModelView::Layout() {
gfx::Rect rect(GetContentsBounds());
if (rect.IsEmpty()) {
- items_per_col_ = 0;
+ items_per_row_ = 0;
return;
}
- // Gets |tile_size| based on content rect and number of tiles.
- gfx::Size tile_size = CalculateTileSize(rect.size(), child_count());
- items_per_col_ = rect.height() / tile_size.height();
+ // Gets |icon_size| based on content rect and number of tiles.
+ gfx::Size icon_size = CalculateIconSize(rect.size(), child_count());
- // Sets tile's icons size and caps tile width to the max tile width.
- int max_tile_width = SetTileIconSizeAndGetMaxWidth(
- tile_size.height() - 2 * AppListItemView::kPadding);
- if (max_tile_width && tile_size.width() > max_tile_width)
- tile_size.set_width(max_tile_width);
+ gfx::Size tile_size = AppListItemView::GetPreferredSizeForIconSize(icon_size);
+ int cols = std::max(rect.width() / tile_size.width(), 1);
+ tile_size.set_width(rect.width() / cols);
+ items_per_row_ = rect.width() / tile_size.width();
- // Layouts tiles.
- int col_bottom = rect.bottom();
+ // Layouts items.
+ int right = rect.right();
gfx::Rect current_tile(rect.origin(), tile_size);
for (int i = 0; i < child_count(); ++i) {
views::View* view = child_at(i);
+ static_cast<AppListItemView*>(view)->set_icon_size(icon_size);
view->SetBoundsRect(current_tile);
+ view->SetVisible(rect.Contains(current_tile));
- current_tile.Offset(0, tile_size.height());
- if (current_tile.bottom() >= col_bottom) {
- current_tile.set_x(current_tile.x() + tile_size.width());
- current_tile.set_y(rect.y());
+ current_tile.Offset(tile_size.width(), 0);
+ if (current_tile.right() > right) {
+ current_tile.set_x(rect.x());
+ current_tile.set_y(current_tile.y() + tile_size.height());
}
}
}
@@ -172,24 +143,24 @@ bool AppListModelView::OnKeyPressed(const views::KeyEvent& event) {
if (!handled) {
switch (event.key_code()) {
case ui::VKEY_LEFT:
- SetSelectedItemByIndex(std::max(selected_item_index_ - items_per_col_,
- 0));
+ SetSelectedItemByIndex(std::max(selected_item_index_ - 1, 0));
return true;
case ui::VKEY_RIGHT:
+ SetSelectedItemByIndex(std::min(selected_item_index_ + 1,
+ child_count() - 1));
+ return true;
+ case ui::VKEY_UP:
+ SetSelectedItemByIndex(std::max(selected_item_index_ - items_per_row_,
+ 0));
+ return true;
+ case ui::VKEY_DOWN:
if (selected_item_index_ < 0) {
SetSelectedItemByIndex(0);
} else {
- SetSelectedItemByIndex(std::min(selected_item_index_ + items_per_col_,
+ SetSelectedItemByIndex(std::min(selected_item_index_ + items_per_row_,
child_count() - 1));
}
return true;
- case ui::VKEY_UP:
- SetSelectedItemByIndex(std::max(selected_item_index_ - 1, 0));
- return true;
- case ui::VKEY_DOWN:
- SetSelectedItemByIndex(std::min(selected_item_index_ + 1,
- child_count() - 1));
- return true;
default:
break;
}
diff --git a/ash/app_list/app_list_model_view.h b/ash/app_list/app_list_model_view.h
index af856f4..a5273f3 100644
--- a/ash/app_list/app_list_model_view.h
+++ b/ash/app_list/app_list_model_view.h
@@ -37,7 +37,6 @@ class AppListModelView : public views::View,
AppListItemView* GetItemViewAtIndex(int index);
void SetSelectedItemByIndex(int index);
- int SetTileIconSizeAndGetMaxWidth(int icon_dimension);
// Overridden from views::View:
virtual void Layout() OVERRIDE;
@@ -54,7 +53,7 @@ class AppListModelView : public views::View,
views::ButtonListener* listener_;
int selected_item_index_;
- int items_per_col_;
+ int items_per_row_;
DISALLOW_COPY_AND_ASSIGN(AppListModelView);
};
diff --git a/ash/app_list/app_list_view.cc b/ash/app_list/app_list_view.cc
index c68312e..83ac1d2 100644
--- a/ash/app_list/app_list_view.cc
+++ b/ash/app_list/app_list_view.cc
@@ -9,7 +9,10 @@
#include "ash/app_list/app_list_model_view.h"
#include "ash/app_list/app_list_view_delegate.h"
#include "ash/shell.h"
+#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/screen.h"
+#include "ui/gfx/transform_util.h"
#include "ui/views/background.h"
#include "ui/views/widget/widget.h"
@@ -18,10 +21,13 @@ namespace ash {
namespace {
// Margins in pixels from work area edges.
-const int kMargin = 50;
+const int kLeftRightMargin = 45;
+const int kTopBottomMargin = 32;
-// 0.4 black
-const SkColor kBackgroundColor = SkColorSetARGB(0x66, 0, 0, 0);
+// 0.2 black
+const SkColor kBackgroundColor = SkColorSetARGB(0x33, 0, 0, 0);
+
+const float kModelViewAnimationScaleFactor = 0.9f;
} // namespace
@@ -37,6 +43,21 @@ AppListView::AppListView(
AppListView::~AppListView() {
}
+void AppListView::AnimateShow() {
+ ui::Layer* layer = model_view_->layer();
+ ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
+ model_view_->SetTransform(ui::Transform());
+}
+
+void AppListView::AnimateHide() {
+ ui::Layer* layer = model_view_->layer();
+ ui::ScopedLayerAnimationSettings animation(layer->GetAnimator());
+ model_view_->SetTransform(
+ ui::GetScaleTransform(gfx::Point(model_view_->width() / 2,
+ model_view_->height() / 2),
+ kModelViewAnimationScaleFactor));
+}
+
void AppListView::Close() {
if (GetWidget()->IsVisible())
Shell::GetInstance()->ToggleAppList();
@@ -44,6 +65,8 @@ void AppListView::Close() {
void AppListView::Init(const gfx::Rect& bounds) {
model_view_ = new AppListModelView(this);
+ model_view_->SetPaintToLayer(true);
+ model_view_->layer()->SetFillsBoundsOpaquely(false);
AddChildView(model_view_);
views::Widget::InitParams widget_params(
@@ -57,6 +80,15 @@ void AppListView::Init(const gfx::Rect& bounds) {
widget->SetContentsView(this);
widget->SetBounds(bounds);
+ // Turns off default animation.
+ widget->SetVisibilityChangedAnimationsEnabled(false);
+
+ // Sets initial transform. AnimateShow changes it back to identity transform.
+ model_view_->SetTransform(
+ ui::GetScaleTransform(gfx::Point(model_view_->width() / 2,
+ model_view_->height() / 2),
+ kModelViewAnimationScaleFactor));
+
UpdateModel();
}
@@ -88,7 +120,7 @@ void AppListView::Layout() {
workarea.Offset(-origin.x(), -origin.y());
rect = rect.Intersect(workarea);
- rect.Inset(kMargin, kMargin);
+ rect.Inset(kLeftRightMargin, kTopBottomMargin);
model_view_->SetBoundsRect(rect);
}
diff --git a/ash/app_list/app_list_view.h b/ash/app_list/app_list_view.h
index 528f26c..619d341 100644
--- a/ash/app_list/app_list_view.h
+++ b/ash/app_list/app_list_view.h
@@ -30,7 +30,9 @@ class AppListView : public views::WidgetDelegateView,
const gfx::Rect& bounds);
virtual ~AppListView();
- // Closes app list.
+ void AnimateShow();
+ void AnimateHide();
+
void Close();
private:
diff --git a/ui/gfx/transform_util.cc b/ui/gfx/transform_util.cc
new file mode 100644
index 0000000..e5fc484
--- /dev/null
+++ b/ui/gfx/transform_util.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/transform_util.h"
+
+#include "ui/gfx/point.h"
+
+namespace ui {
+
+Transform GetScaleTransform(const gfx::Point& anchor, float scale) {
+ ui::Transform transform;
+ transform.ConcatScale(scale, scale);
+ transform.ConcatTranslate(anchor.x() * (1 - scale),
+ anchor.y() * (1 - scale));
+ return transform;
+}
+
+} // namespace ui
diff --git a/ui/gfx/transform_util.h b/ui/gfx/transform_util.h
new file mode 100644
index 0000000..02fb0a8
--- /dev/null
+++ b/ui/gfx/transform_util.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_TRANSFORM_UTIL_H_
+#define UI_GFX_TRANSFORM_UTIL_H_
+#pragma once
+
+#include "ui/base/ui_export.h"
+#include "ui/gfx/transform.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace ui {
+
+// Returns a scale transform at |anchor| point.
+UI_EXPORT Transform GetScaleTransform(const gfx::Point& anchor, float scale);
+
+} // namespace ui
+
+#endif // UI_GFX_TRANSFORM_UTIL_H_
diff --git a/ui/gfx/transform_util_unittest.cc b/ui/gfx/transform_util_unittest.cc
new file mode 100644
index 0000000..06ef062
--- /dev/null
+++ b/ui/gfx/transform_util_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/transform_util.h"
+
+#include "ui/gfx/point.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(TransformUtilTest, GetScaleTransform) {
+ const gfx::Point kAnchor(20, 40);
+ const float kScale = 0.5f;
+
+ ui::Transform scale = ui::GetScaleTransform(kAnchor, kScale);
+
+ const int kOffset = 10;
+ for (int sign_x = -1; sign_x <= 1; ++sign_x) {
+ for (int sign_y = -1; sign_y <= 1; ++sign_y) {
+ gfx::Point test(kAnchor.x() + sign_x * kOffset,
+ kAnchor.y() + sign_y * kOffset);
+ scale.TransformPoint(test);
+
+ EXPECT_EQ(gfx::Point(kAnchor.x() + sign_x * kOffset * kScale,
+ kAnchor.y() + sign_y * kOffset * kScale),
+ test);
+ }
+ }
+}
diff --git a/ui/ui.gyp b/ui/ui.gyp
index b037ea9..96d5e18 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -360,8 +360,10 @@
'gfx/skia_util.h',
'gfx/skia_utils_gtk.cc',
'gfx/skia_utils_gtk.h',
- 'gfx/transform.h',
'gfx/transform.cc',
+ 'gfx/transform.h',
+ 'gfx/transform_util.cc',
+ 'gfx/transform_util.h',
],
'conditions': [
# TODO(asvitkine): Switch all platforms to use_canvas_skia_skia.cc.
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
index d8979f0..75664f8f 100644
--- a/ui/ui_unittests.gypi
+++ b/ui/ui_unittests.gypi
@@ -94,6 +94,7 @@
'gfx/skia_util_unittest.cc',
'gfx/test_suite.cc',
'gfx/test_suite.h',
+ 'gfx/transform_util_unittest.cc',
'<(SHARED_INTERMEDIATE_DIR)/ui/gfx/gfx_resources.rc',
],
'include_dirs': [