// 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/app_list/contents_view.h" #include #include "ui/app_list/app_list_view.h" #include "ui/app_list/apps_grid_view.h" #include "ui/app_list/page_switcher.h" #include "ui/app_list/search_result_list_view.h" #include "ui/views/animation/bounds_animator.h" #include "ui/views/view_model.h" #include "ui/views/view_model_utils.h" namespace app_list { namespace { const int kPreferredIconDimension = 48; const int kPreferredCols = 4; const int kPreferredRows = 4; // Indexes of interesting views in ViewModel of ContentsView. const int kIndexAppsGrid = 0; const int kIndexPageSwitcher = 1; const int kIndexSearchResults = 2; // Helpers to get certain child view from |model|. AppsGridView* GetAppsGridView(views::ViewModel* model) { return static_cast(model->view_at(kIndexAppsGrid)); } PageSwitcher* GetPageSwitcherView(views::ViewModel* model) { return static_cast(model->view_at(kIndexPageSwitcher)); } SearchResultListView* GetSearchResultListView(views::ViewModel* model) { return static_cast( model->view_at(kIndexSearchResults)); } } // namespace ContentsView::ContentsView(AppListView* app_list_view, PaginationModel* pagination_model) : show_state_(SHOW_APPS), view_model_(new views::ViewModel), ALLOW_THIS_IN_INITIALIZER_LIST( bounds_animator_(new views::BoundsAnimator(this))) { AppsGridView* apps_grid_view = new AppsGridView(app_list_view, pagination_model); apps_grid_view->SetLayout(kPreferredIconDimension, kPreferredCols, kPreferredRows); AddChildView(apps_grid_view); view_model_->Add(apps_grid_view, kIndexAppsGrid); PageSwitcher* page_switcher_view = new PageSwitcher(pagination_model); AddChildView(page_switcher_view); view_model_->Add(page_switcher_view, kIndexPageSwitcher); SearchResultListView* search_results_view = new SearchResultListView( app_list_view); AddChildView(search_results_view); view_model_->Add(search_results_view, kIndexSearchResults); } ContentsView::~ContentsView() { } void ContentsView::SetModel(AppListModel* model) { if (model) { GetAppsGridView(view_model_.get())->SetModel(model->apps()); GetSearchResultListView(view_model_.get())->SetResults(model->results()); } else { GetAppsGridView(view_model_.get())->SetModel(NULL); GetSearchResultListView(view_model_.get())->SetResults(NULL); } } void ContentsView::SetShowState(ShowState show_state) { if (show_state_ == show_state) return; show_state_ = show_state; ShowStateChanged(); } void ContentsView::ShowStateChanged() { if (show_state_ == SHOW_SEARCH_RESULTS) { // TODO(xiyuan): Highlight default match instead of the first. SearchResultListView* results_view = GetSearchResultListView(view_model_.get()); if (results_view->visible()) results_view->SetSelectedIndex(0); } AnimateToIdealBounds(); } void ContentsView::CalculateIdealBounds() { gfx::Rect rect(GetContentsBounds()); if (rect.IsEmpty()) return; const int x = rect.x(); const int width = rect.width(); // AppsGridView and PageSwitcher uses a vertical box layout. int y = rect.y(); const int grid_height = GetAppsGridView(view_model_.get())->GetPreferredSize().height(); gfx::Rect grid_frame(gfx::Point(x, y), gfx::Size(width, grid_height)); grid_frame = rect.Intersect(grid_frame); y = grid_frame.bottom(); const int page_switcher_height = rect.bottom() - y; gfx::Rect page_switcher_frame(gfx::Point(x, y), gfx::Size(width, page_switcher_height)); page_switcher_frame = rect.Intersect(page_switcher_frame); // SearchResultListView occupies the whole space when visible. gfx::Rect results_frame(rect); // Offsets apps grid, page switcher and result list based on |show_state_|. // SearchResultListView is on top of apps grid + page switcher. Visible view // is left in visible area and invisible ones is put out of the visible area. int contents_area_height = rect.height(); switch (show_state_) { case SHOW_APPS: results_frame.Offset(0, -contents_area_height); break; case SHOW_SEARCH_RESULTS: grid_frame.Offset(0, contents_area_height); page_switcher_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(kIndexPageSwitcher, page_switcher_frame); view_model_->set_ideal_bounds(kIndexSearchResults, results_frame); } void ContentsView::AnimateToIdealBounds() { CalculateIdealBounds(); for (int i = 0; i < view_model_->view_size(); ++i) { bounds_animator_->AnimateViewTo(view_model_->view_at(i), view_model_->ideal_bounds(i)); } } void ContentsView::ShowSearchResults(bool show) { SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS); } gfx::Size ContentsView::GetPreferredSize() { const gfx::Size grid_size = GetAppsGridView(view_model_.get())->GetPreferredSize(); const gfx::Size page_switcher_size = GetPageSwitcherView(view_model_.get())->GetPreferredSize(); const gfx::Size results_size = GetSearchResultListView(view_model_.get())->GetPreferredSize(); int width = std::max( std::max(grid_size.width(), page_switcher_size.width()), results_size.width()); int height = std::max(grid_size.height() + page_switcher_size.height(), results_size.height()); return gfx::Size(width, height); } void ContentsView::Layout() { CalculateIdealBounds(); views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); } bool ContentsView::OnKeyPressed(const views::KeyEvent& event) { switch (show_state_) { case SHOW_APPS: return GetAppsGridView(view_model_.get())->OnKeyPressed(event); case SHOW_SEARCH_RESULTS: return GetSearchResultListView(view_model_.get())->OnKeyPressed(event); default: NOTREACHED() << "Unknown show state " << show_state_; } return false; } bool ContentsView::OnMouseWheel(const views::MouseWheelEvent& event) { if (show_state_ == SHOW_APPS) return GetAppsGridView(view_model_.get())->OnMouseWheel(event); return false; } } // namespace app_list