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"
33 const int kTopMargin
= 84;
34 const int kInstantContainerSpacing
= 11;
35 const int kSearchBoxAndTilesSpacing
= 40;
36 const int kStartPageSearchBoxWidth
= 480;
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
{
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_
; }
62 DISALLOW_COPY_AND_ASSIGN(SearchBoxSpacerView
);
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.
81 AddChildView(tiles_container_
);
83 SetResults(view_delegate_
->GetModel()->results());
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
));
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() {
139 void StartPageView::UpdateForTesting() {
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() {
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
))
176 switch (event
.key_code()) {
184 // Down selects the first tile if nothing is selected.
185 if (!IsValidSelectionIndex(selected_index()))
189 dir
= event
.IsShiftDown() ? -1 : 1;
198 if (!IsValidSelectionIndex(selected_index())) {
199 SetSelectedIndex(dir
== -1 ? num_results() - 1 : 0);
203 int selection_index
= selected_index() + dir
;
204 if (IsValidSelectionIndex(selection_index
)) {
205 SetSelectedIndex(selection_index
);
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
)
227 if (app_list_main_view_
->contents_view()->ShouldShowCustomPageClickzone()) {
228 custom_page_clickzone
->ShowInactive();
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();
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
)
263 views::Background::CreateSolidBackground(kSelectedColor
));
264 tiles_container_
->child_at(new_selected
)->SchedulePaint();
268 } // namespace app_list