diff options
author | jennyz@chromium.org <jennyz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-22 22:17:46 +0000 |
---|---|---|
committer | jennyz@chromium.org <jennyz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-22 22:17:46 +0000 |
commit | efac0b1fd0c64df92be06cb909e6bfbc835cfe3a (patch) | |
tree | d283bc7773b415fd447525f3ab29cf224ec8d7bb /ui/app_list | |
parent | 22b15624afe497a9b65d32a3365375405a33903d (diff) | |
download | chromium_src-efac0b1fd0c64df92be06cb909e6bfbc835cfe3a.zip chromium_src-efac0b1fd0c64df92be06cb909e6bfbc835cfe3a.tar.gz chromium_src-efac0b1fd0c64df92be06cb909e6bfbc835cfe3a.tar.bz2 |
Implement app list folder management page UI, including the following feature:
1. Clicking on a folder item in the app list grid will open the app list folder management page to show the folder name and items in the folder.
2. User can click on the back button on folder management page to navigate back to the app list page.
3. User can change the app list folder name on folder management page.
BUG=303224
TBR=sky
Review URL: https://codereview.chromium.org/27777002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230227 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/app_list')
-rw-r--r-- | ui/app_list/app_list.gyp | 7 | ||||
-rw-r--r-- | ui/app_list/app_list_constants.cc | 1 | ||||
-rw-r--r-- | ui/app_list/app_list_constants.h | 1 | ||||
-rw-r--r-- | ui/app_list/app_list_folder_item.cc | 9 | ||||
-rw-r--r-- | ui/app_list/views/app_list_folder_view.cc | 94 | ||||
-rw-r--r-- | ui/app_list/views/app_list_folder_view.h | 70 | ||||
-rw-r--r-- | ui/app_list/views/app_list_main_view.cc | 7 | ||||
-rw-r--r-- | ui/app_list/views/app_list_main_view.h | 2 | ||||
-rw-r--r-- | ui/app_list/views/app_list_view.h | 1 | ||||
-rw-r--r-- | ui/app_list/views/apps_container_view.cc | 93 | ||||
-rw-r--r-- | ui/app_list/views/apps_container_view.h | 66 | ||||
-rw-r--r-- | ui/app_list/views/apps_grid_view.cc | 49 | ||||
-rw-r--r-- | ui/app_list/views/apps_grid_view.h | 7 | ||||
-rw-r--r-- | ui/app_list/views/apps_grid_view_unittest.cc | 1 | ||||
-rw-r--r-- | ui/app_list/views/contents_view.cc | 51 | ||||
-rw-r--r-- | ui/app_list/views/contents_view.h | 7 | ||||
-rw-r--r-- | ui/app_list/views/folder_header_view.cc | 179 | ||||
-rw-r--r-- | ui/app_list/views/folder_header_view.h | 76 | ||||
-rw-r--r-- | ui/app_list/views/folder_header_view_delegate.h | 27 |
19 files changed, 690 insertions, 58 deletions
diff --git a/ui/app_list/app_list.gyp b/ui/app_list/app_list.gyp index 007d64c..f269fb8 100644 --- a/ui/app_list/app_list.gyp +++ b/ui/app_list/app_list.gyp @@ -75,9 +75,13 @@ 'search_result.h', 'signin_delegate.cc', 'signin_delegate.h', + 'views/apps_container_view.cc', + 'views/apps_container_view.h', 'views/app_list_background.cc', 'views/app_list_background.h', 'views/app_list_drag_and_drop_host.h', + 'views/app_list_folder_view.cc', + 'views/app_list_folder_view.h', 'views/app_list_item_view.cc', 'views/app_list_item_view.h', 'views/app_list_main_view.cc', @@ -93,6 +97,9 @@ 'views/cached_label.h', 'views/contents_view.cc', 'views/contents_view.h', + 'views/folder_header_view.cc', + 'views/folder_header_view.h', + 'views/folder_header_view_delegate.h', 'views/page_switcher.cc', 'views/page_switcher.h', 'views/progress_bar_view.cc', diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc index 7fbf15c..b0a80af 100644 --- a/ui/app_list/app_list_constants.cc +++ b/ui/app_list/app_list_constants.cc @@ -36,6 +36,7 @@ const int kOverscrollPageTransitionDurationMs = 50; // Preferred number of columns and rows in apps grid. const int kPreferredCols = 4; const int kPreferredRows = 4; +const int kPreferredIconDimension = 48; // Font style for app item labels. const ui::ResourceBundle::FontStyle kItemTextFontStyle = diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h index 337fb67..217ebc7 100644 --- a/ui/app_list/app_list_constants.h +++ b/ui/app_list/app_list_constants.h @@ -35,6 +35,7 @@ APP_LIST_EXPORT extern const int kOverscrollPageTransitionDurationMs; APP_LIST_EXPORT extern const int kPreferredCols; APP_LIST_EXPORT extern const int kPreferredRows; +APP_LIST_EXPORT extern const int kPreferredIconDimension; APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle; diff --git a/ui/app_list/app_list_folder_item.cc b/ui/app_list/app_list_folder_item.cc index 0868d62..95e5530 100644 --- a/ui/app_list/app_list_folder_item.cc +++ b/ui/app_list/app_list_folder_item.cc @@ -15,7 +15,7 @@ const int kIconDimension = 48; const size_t kNumTopApps = 4; const int kItemIconDimension = 16; -// Genearats 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. class FolderImageSource : public gfx::CanvasImageSource { public: typedef std::vector<gfx::ImageSkia> Icons; @@ -45,11 +45,11 @@ class FolderImageSource : public gfx::CanvasImageSource { virtual void Draw(gfx::Canvas* canvas) OVERRIDE { // Draw folder circle. gfx::Point center = gfx::Point(size().width() / 2 , size().height() / 2); - const SkColor kCirclColor = SkColorSetRGB(0xE1, 0xE1, 0xE1); + const SkColor kCircleColor = SkColorSetRGB(0xE1, 0xE1, 0xE1); SkPaint paint; paint.setStyle(SkPaint::kFill_Style); paint.setAntiAlias(true); - paint.setColor(kCirclColor); + paint.setColor(kCircleColor); canvas->DrawCircle(center, size().width() / 2, paint); if (icons_.size() == 0) @@ -144,8 +144,7 @@ std::string AppListFolderItem::GetSortOrder() const { } void AppListFolderItem::Activate(int event_flags) { - // TODO(stevenjb/jennyz): Implement. - VLOG(1) << "AppListFolderItem::Activate"; + // Folder handling is implemented by the View, so do nothing. } // static diff --git a/ui/app_list/views/app_list_folder_view.cc b/ui/app_list/views/app_list_folder_view.cc new file mode 100644 index 0000000..a7e2aa1 --- /dev/null +++ b/ui/app_list/views/app_list_folder_view.cc @@ -0,0 +1,94 @@ +// Copyright 2013 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/app_list/views/app_list_folder_view.h" + +#include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_folder_item.h" +#include "ui/app_list/app_list_model.h" +#include "ui/app_list/pagination_model.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_grid_view.h" +#include "ui/app_list/views/contents_view.h" +#include "ui/app_list/views/folder_header_view.h" +#include "ui/views/view_model.h" +#include "ui/views/view_model_utils.h" + +namespace app_list { + +namespace { + +// Indexes of interesting views in ViewModel of AppListFolderView. +const int kIndexFolderHeader = 0; +const int kIndexChildItems = 1; + +} // namespace + +AppListFolderView::AppListFolderView(AppsContainerView* container_view, + AppListModel* model, + AppListMainView* app_list_main_view, + content::WebContents* start_page_contents) + : container_view_(container_view), + folder_header_view_(new FolderHeaderView(this)), + view_model_(new views::ViewModel), + folder_item_(NULL), + pagination_model_(new PaginationModel) { + AddChildView(folder_header_view_); + view_model_->Add(folder_header_view_, kIndexFolderHeader); + + items_grid_view_ = new AppsGridView( + app_list_main_view, pagination_model_.get(), NULL); + items_grid_view_->SetLayout(kPreferredIconDimension, + kPreferredCols, + kPreferredRows); + items_grid_view_->SetModel(model); + AddChildView(items_grid_view_); + view_model_->Add(items_grid_view_, kIndexChildItems); +} + +AppListFolderView::~AppListFolderView() { +} + +void AppListFolderView::SetAppListFolderItem(AppListFolderItem* folder) { + folder_item_ = folder; + items_grid_view_->SetApps(folder_item_->apps()); + folder_header_view_->SetFolderItem(folder_item_); +} + +gfx::Size AppListFolderView::GetPreferredSize() { + const gfx::Size header_size = folder_header_view_->GetPreferredSize(); + const gfx::Size grid_size = items_grid_view_->GetPreferredSize(); + int width = std::max(header_size.width(), grid_size.width()); + int height = header_size.height() + grid_size.height(); + return gfx::Size(width, height); +} + +void AppListFolderView::Layout() { + CalculateIdealBounds(); + views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); +} + +void AppListFolderView::CalculateIdealBounds() { + gfx::Rect rect(GetContentsBounds()); + if (rect.IsEmpty()) + return; + + gfx::Rect header_frame(rect); + gfx::Size size = folder_header_view_->GetPreferredSize(); + header_frame.set_height(size.height()); + view_model_->set_ideal_bounds(kIndexFolderHeader, header_frame); + + gfx::Rect grid_frame(rect); + grid_frame.set_y(header_frame.height()); + view_model_->set_ideal_bounds(kIndexChildItems, grid_frame); +} + +void AppListFolderView::NavigateBack(AppListFolderItem* item, + const ui::Event& event_flags) { + container_view_->ShowApps(); +} + +} // namespace app_list + diff --git a/ui/app_list/views/app_list_folder_view.h b/ui/app_list/views/app_list_folder_view.h new file mode 100644 index 0000000..ffa91e7 --- /dev/null +++ b/ui/app_list/views/app_list_folder_view.h @@ -0,0 +1,70 @@ +// Copyright 2013 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_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_ +#define UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_ + +#include "ui/app_list/views/folder_header_view.h" +#include "ui/app_list/views/folder_header_view_delegate.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/view.h" + +namespace content { +class WebContents; +} + +namespace views { +class ViewModel; +} + +namespace app_list { + +class AppsContainerView; +class AppsGridView; +class AppListFolderItem; +class AppListMainView; +class AppListModel; +class FolderHeaderView; +class PaginationModel; + +class AppListFolderView : public views::View, + public FolderHeaderViewDelegate { + public: + AppListFolderView(AppsContainerView* container_view, + AppListModel* model, + AppListMainView* app_list_main_view, + content::WebContents* start_page_contents); + virtual ~AppListFolderView(); + + void SetAppListFolderItem(AppListFolderItem* folder); + + // Overridden from views::View: + virtual gfx::Size GetPreferredSize() OVERRIDE; + virtual void Layout() OVERRIDE; + + private: + void CalculateIdealBounds(); + + // Overridden from FolderHeaderViewDelegate: + virtual void NavigateBack(AppListFolderItem* item, + const ui::Event& event_flags) OVERRIDE; + + AppsContainerView* container_view_; // Not owned. + FolderHeaderView* folder_header_view_; // Owned by views hierarchy. + AppsGridView* items_grid_view_; // Owned by the views hierarchy. + + scoped_ptr<views::ViewModel> view_model_; + + AppListFolderItem* folder_item_; // Not owned. + + scoped_ptr<PaginationModel> pagination_model_; + + DISALLOW_COPY_AND_ASSIGN(AppListFolderView); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_APP_LIST_FOLDER_VIEW_H_ + + diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc index 792c5bd..0a83325 100644 --- a/ui/app_list/views/app_list_main_view.cc +++ b/ui/app_list/views/app_list_main_view.cc @@ -12,6 +12,7 @@ #include "base/message_loop/message_loop.h" #include "base/strings/string_util.h" #include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_folder_item.h" #include "ui/app_list/app_list_item_model.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/app_list_view_delegate.h" @@ -190,7 +191,11 @@ void AppListMainView::OnItemIconLoaded(IconLoader* loader) { } void AppListMainView::ActivateApp(AppListItemModel* item, int event_flags) { - item->Activate(event_flags); + // TODO(jennyz): Activate the folder via AppListModel notification. + if (item->GetAppType() == AppListFolderItem::kAppType) + contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item)); + else + item->Activate(event_flags); } void AppListMainView::GetShortcutPathForApp( diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h index 0c9a738..b9a5cdc 100644 --- a/ui/app_list/views/app_list_main_view.h +++ b/ui/app_list/views/app_list_main_view.h @@ -56,6 +56,8 @@ class AppListMainView : public views::View, void SetDragAndDropHostOfCurrentAppList( ApplicationDragAndDropHost* drag_and_drop_host); + ContentsView* contents_view() { return contents_view_; } + private: class IconLoader; diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h index 3856494..9f95482 100644 --- a/ui/app_list/views/app_list_view.h +++ b/ui/app_list/views/app_list_view.h @@ -104,6 +104,7 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView, #endif AppListModel* model() { return model_.get(); } + AppListMainView* app_list_main_view() { return app_list_main_view_; } private: void InitAsBubbleInternal(gfx::NativeView parent, diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc new file mode 100644 index 0000000..ea520b6 --- /dev/null +++ b/ui/app_list/views/apps_container_view.cc @@ -0,0 +1,93 @@ +// Copyright 2013 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/app_list/views/apps_container_view.h" + +#include "ui/app_list/app_list_constants.h" +#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_main_view.h" +#include "ui/app_list/views/apps_grid_view.h" + +namespace app_list { + +AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view, + PaginationModel* pagination_model, + AppListModel* model, + content::WebContents* start_page_contents) + : model_(model), + show_state_(SHOW_APPS) { + apps_grid_view_ = new AppsGridView( + app_list_main_view, pagination_model, start_page_contents); + apps_grid_view_->SetLayout(kPreferredIconDimension, + kPreferredCols, + kPreferredRows); + AddChildView(apps_grid_view_); + + app_list_folder_view_ = new AppListFolderView( + this, + model, + app_list_main_view, + start_page_contents); + AddChildView(app_list_folder_view_); + + apps_grid_view_->SetModel(model_); + apps_grid_view_->SetApps(model_->apps()); +} + +AppsContainerView::~AppsContainerView() { +} + +void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) { + app_list_folder_view_->SetAppListFolderItem(folder_item); + SetShowState(SHOW_ACTIVE_FOLDER); +} + +void AppsContainerView::ShowApps() { + SetShowState(SHOW_APPS); +} + +gfx::Size AppsContainerView::GetPreferredSize() { + const gfx::Size grid_size = apps_grid_view_->GetPreferredSize(); + const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize(); + + int width = std::max(grid_size.width(), folder_view_size.width()); + int height = std::max(grid_size.height(), folder_view_size.height()); + return gfx::Size(width, height); +} + +void AppsContainerView::Layout() { + gfx::Rect rect(GetContentsBounds()); + if (rect.IsEmpty()) + return; + + switch(show_state_) { + case SHOW_APPS: + app_list_folder_view_->SetVisible(false); + apps_grid_view_->SetBoundsRect(rect); + apps_grid_view_->SetVisible(true); + break; + case SHOW_ACTIVE_FOLDER: + apps_grid_view_->SetVisible(false); + app_list_folder_view_->SetBoundsRect(rect); + app_list_folder_view_->SetVisible(true); + break; + default: + NOTREACHED(); + } +} + +void AppsContainerView::SetShowState(ShowState show_state) { + if (show_state_ == show_state) + return; + + show_state_ = show_state; + Layout(); +} + +} // namespace app_list + + + diff --git a/ui/app_list/views/apps_container_view.h b/ui/app_list/views/apps_container_view.h new file mode 100644 index 0000000..625aec9 --- /dev/null +++ b/ui/app_list/views/apps_container_view.h @@ -0,0 +1,66 @@ +// Copyright 2013 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_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_ +#define UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_ + +#include "ui/views/view.h" + +namespace content { +class WebContents; +} + +namespace app_list { + +class AppsGridView; +class AppListFolderItem; +class AppListFolderView; +class AppListMainView; +class AppListModel; +class ContentsView; +class PaginationModel; + +// AppsContainerView contains a root level AppsGridView to render the root level +// 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. +class AppsContainerView : public views::View { + public: + AppsContainerView(AppListMainView* app_list_main_view, + PaginationModel* pagination_model, + AppListModel* model, + content::WebContents* start_page_contents); + virtual ~AppsContainerView(); + + // Shows the active folder content specified by |folder_item|. + void ShowActiveFolder(AppListFolderItem* folder_item); + + // Shows the apps list from root. + void ShowApps(); + + // Overridden from views::View: + virtual gfx::Size GetPreferredSize() OVERRIDE; + virtual void Layout() OVERRIDE; + + AppsGridView* apps_grid_view() { return apps_grid_view_; } + + private: + enum ShowState { + SHOW_APPS, + SHOW_ACTIVE_FOLDER, + }; + + void SetShowState(ShowState show_state); + + AppListModel* model_; + AppsGridView* apps_grid_view_; // Owned by views hierarchy. + AppListFolderView* app_list_folder_view_; // Owned by views hierarchy. + ShowState show_state_; + + DISALLOW_COPY_AND_ASSIGN(AppsContainerView); +}; + +} // namespace app_list + + +#endif // UI_APP_LIST_VIEWS_APPS_CONTAINER_VIEW_H_ diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc index 491883e42..e252664 100644 --- a/ui/app_list/views/apps_grid_view.cc +++ b/ui/app_list/views/apps_grid_view.cc @@ -237,6 +237,7 @@ AppsGridView::AppsGridView(AppsGridViewDelegate* delegate, PaginationModel* pagination_model, content::WebContents* start_page_contents) : model_(NULL), + apps_(NULL), delegate_(delegate), pagination_model_(pagination_model), page_switcher_view_(new PageSwitcher(pagination_model)), @@ -272,11 +273,12 @@ AppsGridView::~AppsGridView() { if (drag_view_) EndDrag(true); - if (model_) { + if (model_) model_->RemoveObserver(this); - model_->apps()->RemoveObserver(this); - } pagination_model_->RemoveObserver(this); + + if (apps_) + apps_->RemoveObserver(this); } void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) { @@ -291,16 +293,22 @@ void AppsGridView::SetLayout(int icon_size, int cols, int rows_per_page) { } void AppsGridView::SetModel(AppListModel* model) { - if (model_) { + if (model_) model_->RemoveObserver(this); - model_->apps()->RemoveObserver(this); - } model_ = model; - if (model_) { + if (model_) model_->AddObserver(this); - model_->apps()->AddObserver(this); - } + + Update(); +} + +void AppsGridView::SetApps(AppListModel::Apps* apps) { + if (apps_) + apps_->RemoveObserver(this); + + apps_ = apps; + apps_->AddObserver(this); Update(); } @@ -625,17 +633,14 @@ void AppsGridView::ViewHierarchyChanged( } } -// static -AppsGridView* AppsGridView::GetLastGridViewForTest() { - return last_created_grid_view_for_test; -} - void AppsGridView::Update() { DCHECK(!selected_view_ && !drag_view_); + if (!apps_) + return; view_model_.Clear(); - if (model_ && model_->apps()->item_count()) - ListItemsAdded(0, model_->apps()->item_count()); + if (apps_ && apps_->item_count()) + ListItemsAdded(0, apps_->item_count()); } void AppsGridView::UpdatePaging() { @@ -648,7 +653,7 @@ void AppsGridView::UpdatePaging() { void AppsGridView::UpdatePulsingBlockViews() { const int available_slots = - tiles_per_page() - model_->apps()->item_count() % tiles_per_page(); + tiles_per_page() - apps_->item_count() % tiles_per_page(); const int desired = model_->status() == AppListModel::STATUS_SYNCING ? available_slots : 0; @@ -670,9 +675,9 @@ void AppsGridView::UpdatePulsingBlockViews() { } views::View* AppsGridView::CreateViewForItemAtIndex(size_t index) { - DCHECK_LT(index, model_->apps()->item_count()); + DCHECK_LT(index, apps_->item_count()); AppListItemView* view = new AppListItemView(this, - model_->apps()->GetItemAt(index)); + apps_->GetItemAt(index)); view->SetIconSize(icon_size_); #if defined(USE_AURA) view->SetPaintToLayer(true); @@ -1107,10 +1112,10 @@ void AppsGridView::MoveItemInModel(views::View* item_view, if (target_model_index == current_model_index) return; - model_->apps()->RemoveObserver(this); - model_->apps()->Move(current_model_index, target_model_index); + apps_->RemoveObserver(this); + apps_->Move(current_model_index, target_model_index); view_model_.Move(current_model_index, target_model_index); - model_->apps()->AddObserver(this); + apps_->AddObserver(this); if (pagination_model_->selected_page() != target.page) pagination_model_->SelectPage(target.page, false); diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h index 8d996a6..31f2fed 100644 --- a/ui/app_list/views/apps_grid_view.h +++ b/ui/app_list/views/apps_grid_view.h @@ -78,6 +78,9 @@ class APP_LIST_EXPORT AppsGridView : public views::View, // Sets |model| to use. Note this does not take ownership of |model|. void SetModel(AppListModel* model); + // Set |apps| to renders. Note this does not take ownership of |apps|. + void SetApps(AppListModel::Apps* apps); + void SetSelectedView(views::View* view); void ClearSelectedView(views::View* view); bool IsSelectedView(const views::View* view) const; @@ -131,9 +134,6 @@ class APP_LIST_EXPORT AppsGridView : public views::View, // Stops the timer that triggers a page flip during a drag. void StopPageFlipTimer(); - // Get the last grid view which was created. - static AppsGridView* GetLastGridViewForTest(); - // Return the view model for test purposes. const views::ViewModel* view_model_for_test() const { return &view_model_; } @@ -272,6 +272,7 @@ class APP_LIST_EXPORT AppsGridView : public views::View, void SetViewHidden(views::View* view, bool hide, bool immediate); AppListModel* model_; // Owned by AppListView. + AppListModel::Apps* apps_; // Not owned. AppsGridViewDelegate* delegate_; PaginationModel* pagination_model_; // Owned by AppListController. PageSwitcher* page_switcher_view_; // Owned by views hierarchy. diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc index a6ef2ff..6cdec0d6 100644 --- a/ui/app_list/views/apps_grid_view_unittest.cc +++ b/ui/app_list/views/apps_grid_view_unittest.cc @@ -106,6 +106,7 @@ class AppsGridViewTest : public testing::Test { apps_grid_view_->SetLayout(kIconDimension, kCols, kRows); apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight))); apps_grid_view_->SetModel(model_.get()); + apps_grid_view_->SetApps(model_->apps()); test_api_.reset(new AppsGridViewTestApi(apps_grid_view_.get())); } diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc index 017c38c..225c119 100644 --- a/ui/app_list/views/contents_view.cc +++ b/ui/app_list/views/contents_view.cc @@ -11,6 +11,7 @@ #include "ui/app_list/app_list_view_delegate.h" #include "ui/app_list/pagination_model.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_grid_view.h" #include "ui/app_list/views/search_result_list_view.h" #include "ui/events/event.h" @@ -22,10 +23,8 @@ namespace app_list { namespace { -const int kPreferredIconDimension = 48; - // Indexes of interesting views in ViewModel of ContentsView. -const int kIndexAppsGrid = 0; +const int kIndexAppsContainer = 0; const int kIndexSearchResults = 1; const int kMinMouseWheelToSwitchPage = 20; @@ -34,9 +33,8 @@ const int kMinHorizVelocityToSwitchPage = 800; const double kFinishTransitionThreshold = 0.33; -// Helpers to get certain child view from |model|. -AppsGridView* GetAppsGridView(views::ViewModel* model) { - return static_cast<AppsGridView*>(model->view_at(kIndexAppsGrid)); +AppsContainerView* GetAppsContainerView(views::ViewModel* model) { + return static_cast<AppsContainerView*>(model->view_at(kIndexAppsContainer)); } SearchResultListView* GetSearchResultListView(views::ViewModel* model) { @@ -59,20 +57,16 @@ ContentsView::ContentsView(AppListMainView* app_list_main_view, kPageTransitionDurationInMs, kOverscrollPageTransitionDurationMs); - apps_grid_view_ = new AppsGridView( - app_list_main_view, pagination_model, start_page_contents); - apps_grid_view_->SetLayout(kPreferredIconDimension, - kPreferredCols, - kPreferredRows); - AddChildView(apps_grid_view_); - view_model_->Add(apps_grid_view_, kIndexAppsGrid); + apps_container_view_ = new AppsContainerView( + app_list_main_view, pagination_model, model, start_page_contents); + AddChildView(apps_container_view_); + view_model_->Add(apps_container_view_, kIndexAppsContainer); SearchResultListView* search_results_view = new SearchResultListView( app_list_main_view); AddChildView(search_results_view); view_model_->Add(search_results_view, kIndexSearchResults); - GetAppsGridView(view_model_.get())->SetModel(model); GetSearchResultListView(view_model_.get())->SetResults(model->results()); } @@ -80,13 +74,14 @@ ContentsView::~ContentsView() { } void ContentsView::CancelDrag() { - if (apps_grid_view_ && apps_grid_view_->has_dragged_view()) - apps_grid_view_->EndDrag(true); + if (apps_container_view_->apps_grid_view()->has_dragged_view()) + apps_container_view_->apps_grid_view()->EndDrag(true); } void ContentsView::SetDragAndDropHostOfCurrentAppList( ApplicationDragAndDropHost* drag_and_drop_host) { - apps_grid_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); + apps_container_view_->apps_grid_view()-> + SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); } void ContentsView::SetShowState(ShowState show_state) { @@ -114,7 +109,7 @@ void ContentsView::CalculateIdealBounds() { if (rect.IsEmpty()) return; - gfx::Rect grid_frame(rect); + gfx::Rect container_frame(rect); gfx::Rect results_frame(rect); // Offsets apps grid and result list based on |show_state_|. @@ -126,14 +121,14 @@ void ContentsView::CalculateIdealBounds() { results_frame.Offset(0, -contents_area_height); break; case SHOW_SEARCH_RESULTS: - grid_frame.Offset(0, contents_area_height); + container_frame.Offset(0, contents_area_height); break; default: NOTREACHED() << "Unknown show_state_ " << show_state_; break; } - view_model_->set_ideal_bounds(kIndexAppsGrid, grid_frame); + view_model_->set_ideal_bounds(kIndexAppsContainer, container_frame); view_model_->set_ideal_bounds(kIndexSearchResults, results_frame); } @@ -149,19 +144,23 @@ void ContentsView::ShowSearchResults(bool show) { SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS); } +void ContentsView::ShowFolderContent(AppListFolderItem* item) { + apps_container_view_->ShowActiveFolder(item); +} + void ContentsView::Prerender() { const int selected_page = std::max(0, pagination_model_->selected_page()); - GetAppsGridView(view_model_.get())->Prerender(selected_page); + apps_container_view_->apps_grid_view()->Prerender(selected_page); } gfx::Size ContentsView::GetPreferredSize() { - const gfx::Size grid_size = - GetAppsGridView(view_model_.get())->GetPreferredSize(); + const gfx::Size container_size = GetAppsContainerView(view_model_.get())-> + apps_grid_view()->GetPreferredSize(); const gfx::Size results_size = GetSearchResultListView(view_model_.get())->GetPreferredSize(); - int width = std::max(grid_size.width(), results_size.width()); - int height = std::max(grid_size.height(), results_size.height()); + int width = std::max(container_size.width(), results_size.width()); + int height = std::max(container_size.height(), results_size.height()); return gfx::Size(width, height); } @@ -173,7 +172,7 @@ void ContentsView::Layout() { bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) { switch (show_state_) { case SHOW_APPS: - return GetAppsGridView(view_model_.get())->OnKeyPressed(event); + return GetAppsContainerView(view_model_.get())->OnKeyPressed(event); case SHOW_SEARCH_RESULTS: return GetSearchResultListView(view_model_.get())->OnKeyPressed(event); default: diff --git a/ui/app_list/views/contents_view.h b/ui/app_list/views/contents_view.h index 4c2c6fe..1f3f938 100644 --- a/ui/app_list/views/contents_view.h +++ b/ui/app_list/views/contents_view.h @@ -23,9 +23,11 @@ namespace app_list { class AppsGridView; class ApplicationDragAndDropHost; +class AppListFolderItem; class AppListMainView; class AppListModel; class AppListViewDelegate; +class AppsContainerView; class PaginationModel; // A view to manage sub views under the search box (apps grid view + page @@ -49,9 +51,12 @@ class ContentsView : public views::View { ApplicationDragAndDropHost* drag_and_drop_host); void ShowSearchResults(bool show); + void ShowFolderContent(AppListFolderItem* folder); void Prerender(); + AppsContainerView* apps_container_view() { return apps_container_view_; } + private: enum ShowState { SHOW_APPS, @@ -80,7 +85,7 @@ class ContentsView : public views::View { ShowState show_state_; PaginationModel* pagination_model_; // Owned by AppListController. - AppsGridView* apps_grid_view_; // Owned by the view. + AppsContainerView* apps_container_view_; // Owned by the views hierarchy. scoped_ptr<views::ViewModel> view_model_; scoped_ptr<views::BoundsAnimator> bounds_animator_; diff --git a/ui/app_list/views/folder_header_view.cc b/ui/app_list/views/folder_header_view.cc new file mode 100644 index 0000000..6874e86 --- /dev/null +++ b/ui/app_list/views/folder_header_view.cc @@ -0,0 +1,179 @@ +// Copyright 2013 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/app_list/views/folder_header_view.h" + +#include "base/strings/utf_string_conversions.h" +#include "grit/ui_resources.h" +#include "grit/ui_strings.h" +#include "ui/app_list/app_list_constants.h" +#include "ui/app_list/app_list_folder_item.h" +#include "ui/app_list/views/app_list_folder_view.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/textfield/textfield.h" + +namespace app_list { + +namespace { + +const int kPreferredWidth = 360; +const int kPreferredHeight = 48; +const int kIconDimension = 32; +const int kPadding = 14; +const int kFolderNameWidth = 150; +const int kFolderNameHeight = 30; +const int kBottomSeparatorWidth = 380; +const int kBottomSeparatorHeight = 1; + +const SkColor kHintTextColor = SkColorSetRGB(0xA0, 0xA0, 0xA0); + +} // namespace + +class FolderHeaderView::FolderNameView : public views::Textfield { + public: + FolderNameView() { + set_border(views::Border::CreateEmptyBorder(1, 1, 1, 1)); + } + + virtual ~FolderNameView() { + } + + // Overridden from views::View: + virtual gfx::Size GetPreferredSize() OVERRIDE { + return gfx::Size(kFolderNameWidth, kFolderNameHeight); + } + + virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE { + const SkColor kFocusBorderColor = SkColorSetRGB(64, 128, 250); + if (HasFocus() && focusable()) { + gfx::Rect rect = GetLocalBounds(); + rect.Inset(0, 0, 1, 1); + canvas->DrawRect(rect, kFocusBorderColor); + } + } + + private: + DISALLOW_COPY_AND_ASSIGN(FolderNameView); +}; + +FolderHeaderView::FolderHeaderView(FolderHeaderViewDelegate* delegate) + : folder_item_(NULL), + back_button_(new views::ImageButton(this)), + folder_name_view_(new FolderNameView), + delegate_(delegate) { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + back_button_->SetImage(views::ImageButton::STATE_NORMAL, + rb.GetImageSkiaNamed(IDR_APP_LIST_FOLDER_BACK_NORMAL)); + back_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER, + views::ImageButton::ALIGN_MIDDLE); + AddChildView(back_button_); + + folder_name_view_->SetFont(rb.GetFont(ui::ResourceBundle::MediumFont)); + folder_name_view_->set_placeholder_text_color(kHintTextColor); + folder_name_view_->set_placeholder_text( + rb.GetLocalizedString(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER)); + folder_name_view_->RemoveBorder(); + folder_name_view_->SetBackgroundColor(kContentsBackgroundColor); + folder_name_view_->SetController(this); + AddChildView(folder_name_view_); +} + +FolderHeaderView::~FolderHeaderView() { + if (folder_item_) + folder_item_->RemoveObserver(this); +} + +void FolderHeaderView::SetFolderItem(AppListFolderItem* folder_item) { + if (folder_item_) + folder_item_->RemoveObserver(this); + + folder_item_ = folder_item; + if (!folder_item_) + return; + folder_item_->AddObserver(this); + + Update(); +} + +void FolderHeaderView::Update() { + if (!folder_item_) + return; + + folder_name_view_->SetText(UTF8ToUTF16(folder_item_->title())); +} + +gfx::Size FolderHeaderView::GetPreferredSize() { + return gfx::Size(kPreferredWidth, kPreferredHeight); +} + +void FolderHeaderView::Layout() { + gfx::Rect rect(GetContentsBounds()); + if (rect.IsEmpty()) + return; + + gfx::Rect back_bounds(rect); + back_bounds.set_width(kIconDimension + 2 * kPadding); + back_button_->SetBoundsRect(back_bounds); + + gfx::Rect text_bounds(rect); + int text_width = folder_name_view_->GetPreferredSize().width(); + text_bounds.set_x(back_bounds.x() + (rect.width() - text_width) / 2); + text_bounds.set_width(text_width); + text_bounds.ClampToCenteredSize(gfx::Size(text_bounds.width(), + folder_name_view_->GetPreferredSize().height())); + folder_name_view_->SetBoundsRect(text_bounds); +} + +void FolderHeaderView::OnPaint(gfx::Canvas* canvas) { + views::View::OnPaint(canvas); + + gfx::Rect rect(GetContentsBounds()); + if (rect.IsEmpty()) + return; + + // Draw bottom separator line. + rect.set_x((rect.width() - kBottomSeparatorWidth) / 2 + rect.x()); + rect.set_y(rect.y() + rect.height() - kBottomSeparatorHeight); + rect.set_width(kBottomSeparatorWidth); + rect.set_height(kBottomSeparatorHeight); + canvas->FillRect(rect, kTopSeparatorColor); +} + +void FolderHeaderView::ContentsChanged(views::Textfield* sender, + const base::string16& new_contents) { + // Temporarily remove from observer to ignore data change caused by us. + if (!folder_item_) + return; + + folder_item_->RemoveObserver(this); + std::string name = UTF16ToUTF8(folder_name_view_->text()); + folder_item_->SetTitleAndFullName(name, name); + folder_item_->AddObserver(this); +} + +void FolderHeaderView::ButtonPressed(views::Button* sender, + const ui::Event& event) { + delegate_->NavigateBack(folder_item_, event); +} + +void FolderHeaderView::ItemIconChanged() { +} + +void FolderHeaderView::ItemTitleChanged() { + Update(); +} + +void FolderHeaderView::ItemHighlightedChanged() { +} + +void FolderHeaderView::ItemIsInstallingChanged() { +} + +void FolderHeaderView::ItemPercentDownloadedChanged() { +} + +} // namespace app_list + diff --git a/ui/app_list/views/folder_header_view.h b/ui/app_list/views/folder_header_view.h new file mode 100644 index 0000000..ea03510 --- /dev/null +++ b/ui/app_list/views/folder_header_view.h @@ -0,0 +1,76 @@ +// Copyright 2013 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_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_ +#define UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_ + +#include <string> + +#include "ui/app_list/app_list_item_model_observer.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/textfield/textfield_controller.h" +#include "ui/views/view.h" + +namespace views { +class ImageButton; +} // namespace views + +namespace app_list { + +class AppListFolderItem; +class AppListFolderView; +class FolderHeaderViewDelegate; + +// FolderHeaderView contains a back button and an editable folder name field. +class FolderHeaderView : public views::View, + public views::TextfieldController, + public views::ButtonListener, + public AppListItemModelObserver { + public: + explicit FolderHeaderView(FolderHeaderViewDelegate* delegate); + virtual ~FolderHeaderView(); + + void SetFolderItem(AppListFolderItem* folder_item); + + // Overridden from views::View: + virtual gfx::Size GetPreferredSize() OVERRIDE; + + private: + class FolderNameView; + + // Updates UI. + void Update(); + + // Overriden from views::View: + virtual void Layout() OVERRIDE; + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; + + // Overridden from views::TextfieldController: + virtual void ContentsChanged(views::Textfield* sender, + const base::string16& new_contents) OVERRIDE; + + // Overridden from views::ButtonListener: + virtual void ButtonPressed(views::Button* sender, + const ui::Event& event) OVERRIDE; + + // Overridden from AppListItemModelObserver: + virtual void ItemIconChanged() OVERRIDE; + virtual void ItemTitleChanged() OVERRIDE; + virtual void ItemHighlightedChanged() OVERRIDE; + virtual void ItemIsInstallingChanged() OVERRIDE; + virtual void ItemPercentDownloadedChanged() OVERRIDE; + + AppListFolderItem* folder_item_; // Not owned. + + views::ImageButton* back_button_; // Owned by views hierarchy. + FolderNameView* folder_name_view_; // Owned by views hierarchy. + + FolderHeaderViewDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(FolderHeaderView); +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_H_ diff --git a/ui/app_list/views/folder_header_view_delegate.h b/ui/app_list/views/folder_header_view_delegate.h new file mode 100644 index 0000000..e8591b6 --- /dev/null +++ b/ui/app_list/views/folder_header_view_delegate.h @@ -0,0 +1,27 @@ +// Copyright 2013 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_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_ +#define UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_ + +namespace app_list { + +class AppListFolderItem; + +class FolderHeaderViewDelegate { + public: + // Invoked when the back button on the folder header view is clicked. + // |item| is the folder item which FolderHeaderview represents. + // |event_flags| contains the flags of the keyboard/mouse event that triggers + // the request. + virtual void NavigateBack(AppListFolderItem* item, + const ui::Event& event_flags) = 0; + + protected: + virtual ~FolderHeaderViewDelegate() {} +}; + +} // namespace app_list + +#endif // UI_APP_LIST_VIEWS_FOLDER_HEADER_VIEW_DELEGATE_H_ |