diff options
author | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-13 00:58:26 +0000 |
---|---|---|
committer | xiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-13 00:58:26 +0000 |
commit | 5e29e3518a298650a1a054ebe5a45941f1a27160 (patch) | |
tree | bc36dd0a5b2f9ee62f4b653b12d5ab1a6f74ceed /ash | |
parent | 4840bf6d92cb6405da7ff1f051ac5964e3bf154e (diff) | |
download | chromium_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.cc | 43 | ||||
-rw-r--r-- | ash/app_list/app_list_item_view.h | 24 | ||||
-rw-r--r-- | ash/app_list/app_list_model_view.cc | 90 | ||||
-rw-r--r-- | ash/app_list/app_list_model_view.h | 12 |
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); }; |