summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-13 00:58:26 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-13 00:58:26 +0000
commit5e29e3518a298650a1a054ebe5a45941f1a27160 (patch)
treebc36dd0a5b2f9ee62f4b653b12d5ab1a6f74ceed /ash
parent4840bf6d92cb6405da7ff1f051ac5964e3bf154e (diff)
downloadchromium_src-5e29e3518a298650a1a054ebe5a45941f1a27160.zip
chromium_src-5e29e3518a298650a1a054ebe5a45941f1a27160.tar.gz
chromium_src-5e29e3518a298650a1a054ebe5a45941f1a27160.tar.bz2
ash: Add keyboard support to app list.
- Make AppListModelView focusable; - Arrow keys to navigate around app list; BUG=117070 TEST=Verify arrow keys could move around in app list. Review URL: http://codereview.chromium.org/9664075 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126279 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/app_list/app_list_item_view.cc43
-rw-r--r--ash/app_list/app_list_item_view.h24
-rw-r--r--ash/app_list/app_list_model_view.cc90
-rw-r--r--ash/app_list/app_list_model_view.h12
4 files changed, 152 insertions, 17 deletions
diff --git a/ash/app_list/app_list_item_view.cc b/ash/app_list/app_list_item_view.cc
index e47305a..92c0c22 100644
--- a/ash/app_list/app_list_item_view.cc
+++ b/ash/app_list/app_list_item_view.cc
@@ -5,6 +5,7 @@
#include "ash/app_list/app_list_item_view.h"
#include "ash/app_list/app_list_item_model.h"
+#include "ash/app_list/app_list_model_view.h"
#include "ash/app_list/drop_shadow_label.h"
#include "base/utf_string_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -24,7 +25,12 @@ namespace {
const int kIconTitleSpacing = 5;
const SkColor kTitleColor = SK_ColorWHITE;
-const SkColor kHoverColor = SkColorSetARGB(0x33, 0xFF, 0xFF, 0xFF); // 0.2 white
+
+// 0.2 white
+const SkColor kHoverAndPushedColor = SkColorSetARGB(0x33, 0xFF, 0xFF, 0xFF);
+
+// 0.1 white
+const SkColor kSelectedColor = SkColorSetARGB(0x20, 0xFF, 0xFF, 0xFF);
gfx::Font GetTitleFont() {
static gfx::Font* font = NULL;
@@ -56,12 +62,15 @@ class StaticImageView : public views::ImageView {
// static
const char AppListItemView::kViewClassName[] = "ash/app_list/AppListItemView";
-AppListItemView::AppListItemView(AppListItemModel* model,
+AppListItemView::AppListItemView(AppListModelView* list_model_view,
+ AppListItemModel* model,
views::ButtonListener* listener)
: CustomButton(listener),
model_(model),
+ list_model_view_(list_model_view),
icon_(new StaticImageView),
- title_(new DropShadowLabel) {
+ title_(new DropShadowLabel),
+ selected_(false) {
title_->SetFont(GetTitleFont());
title_->SetBackgroundColor(0);
title_->SetEnabledColor(kTitleColor);
@@ -75,12 +84,21 @@ AppListItemView::AppListItemView(AppListItemModel* model,
model_->AddObserver(this);
set_context_menu_controller(this);
+ set_request_focus_on_press(false);
}
AppListItemView::~AppListItemView() {
model_->RemoveObserver(this);
}
+void AppListItemView::SetSelected(bool selected) {
+ if (selected == selected_)
+ return;
+
+ selected_ = selected;
+ SchedulePaint();
+}
+
void AppListItemView::ItemIconChanged() {
icon_->SetImage(model_->icon());
}
@@ -119,11 +137,15 @@ void AppListItemView::Layout() {
void AppListItemView::OnPaint(gfx::Canvas* canvas) {
gfx::Rect rect(GetContentsBounds());
+
if (hover_animation_->is_animating()) {
- int alpha = SkColorGetA(kHoverColor) * hover_animation_->GetCurrentValue();
- canvas->FillRect(rect, SkColorSetA(kHoverColor, alpha));
- } else if (state() == BS_HOT) {
- canvas->FillRect(rect, kHoverColor);
+ int alpha = SkColorGetA(kHoverAndPushedColor) *
+ hover_animation_->GetCurrentValue();
+ canvas->FillRect(rect, SkColorSetA(kHoverAndPushedColor, alpha));
+ } else if (state() == BS_HOT || state() == BS_PUSHED) {
+ canvas->FillRect(rect, kHoverAndPushedColor);
+ } else if (selected_) {
+ canvas->FillRect(rect, kSelectedColor);
}
}
@@ -144,4 +166,11 @@ void AppListItemView::ShowContextMenuForView(views::View* source,
return;
}
+void AppListItemView::StateChanged() {
+ if (state() == BS_HOT || state() == BS_PUSHED)
+ list_model_view_->SetSelectedItem(this);
+ else
+ list_model_view_->ClearSelectedItem(this);
+}
+
} // namespace ash
diff --git a/ash/app_list/app_list_item_view.h b/ash/app_list/app_list_item_view.h
index 39ef59d..3f2123d 100644
--- a/ash/app_list/app_list_item_view.h
+++ b/ash/app_list/app_list_item_view.h
@@ -7,7 +7,6 @@
#pragma once
#include "ash/app_list/app_list_item_model_observer.h"
-#include "ash/ash_export.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/context_menu_controller.h"
#include "ui/views/controls/button/custom_button.h"
@@ -23,15 +22,22 @@ class MenuRunner;
namespace ash {
class AppListItemModel;
+class AppListModelView;
-class ASH_EXPORT AppListItemView : public views::CustomButton,
- public views::ContextMenuController,
- public AppListItemModelObserver {
+class AppListItemView : public views::CustomButton,
+ public views::ContextMenuController,
+ public AppListItemModelObserver {
public:
- AppListItemView(AppListItemModel* model,
+ AppListItemView(AppListModelView* list_model_view,
+ AppListItemModel* model,
views::ButtonListener* listener);
virtual ~AppListItemView();
+ void SetSelected(bool selected);
+ bool selected() const {
+ return selected_;
+ }
+
AppListItemModel* model() const {
return model_;
}
@@ -46,7 +52,7 @@ class ASH_EXPORT AppListItemView : public views::CustomButton,
// Internal class name.
static const char kViewClassName[];
- protected:
+ private:
// AppListItemModelObserver overrides:
virtual void ItemIconChanged() OVERRIDE;
virtual void ItemTitleChanged() OVERRIDE;
@@ -57,19 +63,23 @@ class ASH_EXPORT AppListItemView : public views::CustomButton,
virtual void Layout() OVERRIDE;
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
- private:
// views::ContextMenuController overrides:
virtual void ShowContextMenuForView(views::View* source,
const gfx::Point& point) OVERRIDE;
+ // views::CustomButton overrides:
+ virtual void StateChanged() OVERRIDE;
+
AppListItemModel* model_;
+ AppListModelView* list_model_view_;
views::ImageView* icon_;
views::Label* title_;
scoped_ptr<views::MenuRunner> context_menu_runner_;
gfx::Size icon_size_;
+ bool selected_;
DISALLOW_COPY_AND_ASSIGN(AppListItemView);
};
diff --git a/ash/app_list/app_list_model_view.cc b/ash/app_list/app_list_model_view.cc
index 7722e5b..b37414c 100644
--- a/ash/app_list/app_list_model_view.cc
+++ b/ash/app_list/app_list_model_view.cc
@@ -52,7 +52,10 @@ gfx::Size CalculateTileSize(const gfx::Size& content_size, int num_of_tiles) {
AppListModelView::AppListModelView(views::ButtonListener* listener)
: model_(NULL),
- listener_(listener) {
+ listener_(listener),
+ selected_item_index_(-1),
+ items_per_col_(0) {
+ set_focusable(true);
}
AppListModelView::~AppListModelView() {
@@ -71,18 +74,50 @@ void AppListModelView::SetModel(AppListModel* model) {
Update();
}
+void AppListModelView::SetSelectedItem(AppListItemView* item) {
+ int index = GetIndexOf(item);
+ if (index >= 0)
+ SetSelectedItemByIndex(index);
+}
+
+void AppListModelView::ClearSelectedItem(AppListItemView* item) {
+ int index = GetIndexOf(item);
+ if (index == selected_item_index_)
+ SetSelectedItemByIndex(-1);
+}
+
void AppListModelView::Update() {
+ selected_item_index_ = -1;
RemoveAllChildViews(true);
if (!model_ || model_->item_count() == 0)
return;
for (int i = 0; i < model_->item_count(); ++i)
- AddChildView(new AppListItemView(model_->GetItem(i), listener_));
+ AddChildView(new AppListItemView(this, model_->GetItem(i), listener_));
Layout();
SchedulePaint();
}
+AppListItemView* AppListModelView::GetItemViewAtIndex(int index) {
+ return static_cast<AppListItemView*>(child_at(index));
+}
+
+void AppListModelView::SetSelectedItemByIndex(int index) {
+ if (selected_item_index_ == index)
+ return;
+
+ if (selected_item_index_ >= 0)
+ GetItemViewAtIndex(selected_item_index_)->SetSelected(false);
+
+ if (index < 0 || index >= child_count()) {
+ selected_item_index_ = -1;
+ } else {
+ selected_item_index_ = index;
+ GetItemViewAtIndex(selected_item_index_)->SetSelected(true);
+ }
+}
+
int AppListModelView::SetTileIconSizeAndGetMaxWidth(int icon_dimension) {
gfx::Size icon_size(icon_dimension, icon_dimension);
int max_tile_width = 0;
@@ -99,11 +134,14 @@ int AppListModelView::SetTileIconSizeAndGetMaxWidth(int icon_dimension) {
void AppListModelView::Layout() {
gfx::Rect rect(GetContentsBounds());
- if (rect.IsEmpty())
+ if (rect.IsEmpty()) {
+ items_per_col_ = 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();
// Sets tile's icons size and caps tile width to the max tile width.
int max_tile_width = SetTileIconSizeAndGetMaxWidth(
@@ -126,6 +164,52 @@ void AppListModelView::Layout() {
}
}
+bool AppListModelView::OnKeyPressed(const views::KeyEvent& event) {
+ bool handled = false;
+ if (selected_item_index_ >= 0)
+ handled = GetItemViewAtIndex(selected_item_index_)->OnKeyPressed(event);
+
+ if (!handled) {
+ switch (event.key_code()) {
+ case ui::VKEY_LEFT:
+ SetSelectedItemByIndex(std::max(selected_item_index_ - items_per_col_,
+ 0));
+ return true;
+ case ui::VKEY_RIGHT:
+ if (selected_item_index_ < 0) {
+ SetSelectedItemByIndex(0);
+ } else {
+ SetSelectedItemByIndex(std::min(selected_item_index_ + items_per_col_,
+ 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;
+ }
+ }
+
+ return handled;
+}
+
+bool AppListModelView::OnKeyReleased(const views::KeyEvent& event) {
+ bool handled = false;
+ if (selected_item_index_ >= 0)
+ handled = GetItemViewAtIndex(selected_item_index_)->OnKeyReleased(event);
+
+ return handled;
+}
+
+void AppListModelView::OnPaintFocusBorder(gfx::Canvas* canvas) {
+ // Override to not paint focus frame.
+}
+
void AppListModelView::ListItemsAdded(int start, int count) {
Update();
}
diff --git a/ash/app_list/app_list_model_view.h b/ash/app_list/app_list_model_view.h
index 31832fa..af856f4 100644
--- a/ash/app_list/app_list_model_view.h
+++ b/ash/app_list/app_list_model_view.h
@@ -15,6 +15,7 @@ class ButtonListener;
namespace ash {
+class AppListItemView;
class AppListModel;
// AppListModelView displays the UI for an AppListModel.
@@ -27,14 +28,22 @@ class AppListModelView : public views::View,
// Sets |model| to use. Note this does not take ownership of |model|.
void SetModel(AppListModel* model);
+ void SetSelectedItem(AppListItemView* item);
+ void ClearSelectedItem(AppListItemView* item);
+
private:
// Updates from model.
void Update();
+ AppListItemView* GetItemViewAtIndex(int index);
+ void SetSelectedItemByIndex(int index);
int SetTileIconSizeAndGetMaxWidth(int icon_dimension);
// Overridden from views::View:
virtual void Layout() OVERRIDE;
+ virtual bool OnKeyPressed(const views::KeyEvent& event) OVERRIDE;
+ virtual bool OnKeyReleased(const views::KeyEvent& event) OVERRIDE;
+ virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE;
// Overridden from ListModelObserver:
virtual void ListItemsAdded(int start, int count) OVERRIDE;
@@ -44,6 +53,9 @@ class AppListModelView : public views::View,
AppListModel* model_; // Owned by parent AppListView.
views::ButtonListener* listener_;
+ int selected_item_index_;
+ int items_per_col_;
+
DISALLOW_COPY_AND_ASSIGN(AppListModelView);
};