Make app list recommendations into their own DisplayType.
[chromium-blink-merge.git] / ui / app_list / views / start_page_view.cc
blob26656b86a161189c4e031de03462d530917554d6
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/app_list/views/start_page_view.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "ui/app_list/app_list_constants.h"
9 #include "ui/app_list/app_list_item.h"
10 #include "ui/app_list/app_list_model.h"
11 #include "ui/app_list/app_list_view_delegate.h"
12 #include "ui/app_list/search_result.h"
13 #include "ui/app_list/views/all_apps_tile_item_view.h"
14 #include "ui/app_list/views/app_list_main_view.h"
15 #include "ui/app_list/views/contents_view.h"
16 #include "ui/app_list/views/search_box_view.h"
17 #include "ui/app_list/views/search_result_list_view.h"
18 #include "ui/app_list/views/search_result_tile_item_view.h"
19 #include "ui/app_list/views/tile_item_view.h"
20 #include "ui/gfx/canvas.h"
21 #include "ui/views/background.h"
22 #include "ui/views/controls/image_view.h"
23 #include "ui/views/controls/label.h"
24 #include "ui/views/controls/textfield/textfield.h"
25 #include "ui/views/layout/box_layout.h"
26 #include "ui/views/widget/widget.h"
28 namespace app_list {
30 namespace {
32 // Layout constants.
33 const int kTopMargin = 84;
34 const int kInstantContainerSpacing = 11;
35 const int kSearchBoxAndTilesSpacing = 40;
36 const int kStartPageSearchBoxWidth = 480;
38 // WebView constants.
39 const int kWebViewWidth = 500;
40 const int kWebViewHeight = 105;
42 // Tile container constants.
43 const size_t kNumStartPageTiles = 4;
44 const int kTileSpacing = 10;
46 // An invisible placeholder view which fills the space for the search box view
47 // in a box layout. The search box view itself is a child of the AppListView
48 // (because it is visible on many different pages).
49 class SearchBoxSpacerView : public views::View {
50 public:
51 explicit SearchBoxSpacerView(const gfx::Size& search_box_size)
52 : size_(kStartPageSearchBoxWidth, search_box_size.height()) {}
54 ~SearchBoxSpacerView() override {}
56 // Overridden from views::View:
57 gfx::Size GetPreferredSize() const override { return size_; }
59 private:
60 gfx::Size size_;
62 DISALLOW_COPY_AND_ASSIGN(SearchBoxSpacerView);
65 } // namespace
67 StartPageView::StartPageView(AppListMainView* app_list_main_view,
68 AppListViewDelegate* view_delegate)
69 : app_list_main_view_(app_list_main_view),
70 view_delegate_(view_delegate),
71 search_box_spacer_view_(new SearchBoxSpacerView(
72 app_list_main_view->search_box_view()->GetPreferredSize())),
73 instant_container_(new views::View),
74 tiles_container_(new views::View) {
75 // The view containing the start page WebContents and SearchBoxSpacerView.
76 InitInstantContainer();
77 AddChildView(instant_container_);
79 // The view containing the start page tiles.
80 InitTilesContainer();
81 AddChildView(tiles_container_);
83 SetResults(view_delegate_->GetModel()->results());
84 Reset();
87 StartPageView::~StartPageView() {
90 void StartPageView::InitInstantContainer() {
91 views::BoxLayout* instant_layout_manager = new views::BoxLayout(
92 views::BoxLayout::kVertical, 0, 0, kInstantContainerSpacing);
93 instant_layout_manager->set_inside_border_insets(
94 gfx::Insets(kTopMargin, 0, kSearchBoxAndTilesSpacing, 0));
95 instant_layout_manager->set_main_axis_alignment(
96 views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
97 instant_layout_manager->set_cross_axis_alignment(
98 views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
99 instant_container_->SetLayoutManager(instant_layout_manager);
101 views::View* web_view = view_delegate_->CreateStartPageWebView(
102 gfx::Size(kWebViewWidth, kWebViewHeight));
103 if (web_view) {
104 web_view->SetFocusable(false);
105 instant_container_->AddChildView(web_view);
108 instant_container_->AddChildView(search_box_spacer_view_);
111 void StartPageView::InitTilesContainer() {
112 views::BoxLayout* tiles_layout_manager =
113 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, kTileSpacing);
114 tiles_layout_manager->set_main_axis_alignment(
115 views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
116 tiles_container_->SetLayoutManager(tiles_layout_manager);
118 // Add SearchResultTileItemViews to the container.
119 for (size_t i = 0; i < kNumStartPageTiles; ++i) {
120 SearchResultTileItemView* tile_item = new SearchResultTileItemView();
121 tiles_container_->AddChildView(tile_item);
122 tile_item->SetTitleBackgroundColor(kLabelBackgroundColor);
123 search_result_tile_views_.push_back(tile_item);
126 // Also add a special "all apps" button to the end of the container.
127 all_apps_button_ = new AllAppsTileItemView(
128 app_list_main_view_->contents_view(),
129 view_delegate_->GetModel()->top_level_item_list());
130 all_apps_button_->UpdateIcon();
131 all_apps_button_->SetTitleBackgroundColor(kLabelBackgroundColor);
132 tiles_container_->AddChildView(all_apps_button_);
135 void StartPageView::Reset() {
136 Update();
139 void StartPageView::UpdateForTesting() {
140 Update();
143 TileItemView* StartPageView::all_apps_button() const {
144 return all_apps_button_;
147 void StartPageView::OnShow() {
148 DCHECK(app_list_main_view_->contents_view()->ShouldShowCustomPageClickzone());
149 UpdateCustomPageClickzoneVisibility();
150 ClearSelectedIndex();
153 void StartPageView::OnHide() {
154 DCHECK(
155 !app_list_main_view_->contents_view()->ShouldShowCustomPageClickzone());
156 UpdateCustomPageClickzoneVisibility();
159 void StartPageView::Layout() {
160 gfx::Rect bounds(GetContentsBounds());
161 bounds.set_height(instant_container_->GetHeightForWidth(bounds.width()));
162 instant_container_->SetBoundsRect(bounds);
164 // Tiles begin where the instant container ends.
165 bounds.set_y(bounds.bottom());
166 bounds.set_height(tiles_container_->GetHeightForWidth(bounds.width()));
167 tiles_container_->SetBoundsRect(bounds);
170 bool StartPageView::OnKeyPressed(const ui::KeyEvent& event) {
171 if (selected_index() >= 0 &&
172 tiles_container_->child_at(selected_index())->OnKeyPressed(event))
173 return true;
175 int dir = 0;
176 switch (event.key_code()) {
177 case ui::VKEY_LEFT:
178 dir = -1;
179 break;
180 case ui::VKEY_RIGHT:
181 dir = 1;
182 break;
183 case ui::VKEY_DOWN:
184 // Down selects the first tile if nothing is selected.
185 if (!IsValidSelectionIndex(selected_index()))
186 dir = 1;
187 break;
188 case ui::VKEY_TAB:
189 dir = event.IsShiftDown() ? -1 : 1;
190 break;
191 default:
192 break;
195 if (dir == 0)
196 return false;
198 if (!IsValidSelectionIndex(selected_index())) {
199 SetSelectedIndex(dir == -1 ? num_results() - 1 : 0);
200 return true;
203 int selection_index = selected_index() + dir;
204 if (IsValidSelectionIndex(selection_index)) {
205 SetSelectedIndex(selection_index);
206 return true;
209 return false;
212 void StartPageView::OnContainerSelected(bool from_bottom) {
215 gfx::Rect StartPageView::GetSearchBoxBounds() const {
216 return search_box_spacer_view_->bounds();
219 void StartPageView::UpdateCustomPageClickzoneVisibility() {
220 // This can get called before InitWidgets(), so we cannot guarantee that
221 // custom_page_clickzone_ will not be null.
222 views::Widget* custom_page_clickzone =
223 app_list_main_view_->GetCustomPageClickzone();
224 if (!custom_page_clickzone)
225 return;
227 if (app_list_main_view_->contents_view()->ShouldShowCustomPageClickzone()) {
228 custom_page_clickzone->ShowInactive();
229 return;
232 custom_page_clickzone->Hide();
235 int StartPageView::Update() {
236 std::vector<SearchResult*> display_results =
237 AppListModel::FilterSearchResultsByDisplayType(
238 results(), SearchResult::DISPLAY_RECOMMENDATION, kNumStartPageTiles);
240 // Update the tile item results.
241 for (size_t i = 0; i < search_result_tile_views_.size(); ++i) {
242 SearchResult* item = NULL;
243 if (i < display_results.size())
244 item = display_results[i];
245 search_result_tile_views_[i]->SetSearchResult(item);
248 tiles_container_->Layout();
249 Layout();
250 // Add 1 to the results size to account for the all apps button.
251 return display_results.size() + 1;
254 void StartPageView::UpdateSelectedIndex(int old_selected, int new_selected) {
255 if (old_selected >= 0) {
256 tiles_container_->child_at(old_selected)->set_background(nullptr);
257 tiles_container_->child_at(old_selected)->SchedulePaint();
260 if (new_selected >= 0) {
261 tiles_container_->child_at(new_selected)
262 ->set_background(
263 views::Background::CreateSolidBackground(kSelectedColor));
264 tiles_container_->child_at(new_selected)->SchedulePaint();
268 } // namespace app_list