Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / app_list / views / search_result_page_view.cc
blobe428812700783db2868463ee356acdefef7d05cd
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/search_result_page_view.h"
7 #include <algorithm>
9 #include "ui/app_list/app_list_constants.h"
10 #include "ui/app_list/app_list_switches.h"
11 #include "ui/app_list/app_list_view_delegate.h"
12 #include "ui/app_list/views/app_list_main_view.h"
13 #include "ui/app_list/views/search_box_view.h"
14 #include "ui/app_list/views/search_result_list_view.h"
15 #include "ui/app_list/views/search_result_tile_item_list_view.h"
16 #include "ui/gfx/shadow_value.h"
17 #include "ui/views/background.h"
18 #include "ui/views/layout/box_layout.h"
19 #include "ui/views/layout/fill_layout.h"
20 #include "ui/views/shadow_border.h"
22 namespace app_list {
24 namespace {
26 const int kGroupSpacing = 6;
27 const int kTopPadding = 8;
29 // The z-height of the search box and cards in this view.
30 const int kSearchResultZHeight = 1;
32 // A container view that ensures the card background and the shadow are painted
33 // in the correct order.
34 class SearchCardView : public views::View {
35 public:
36 explicit SearchCardView(views::View* content_view) {
37 SetBorder(make_scoped_ptr(
38 new views::ShadowBorder(GetShadowForZHeight(kSearchResultZHeight))));
39 SetLayoutManager(new views::FillLayout());
40 content_view->set_background(
41 views::Background::CreateSolidBackground(kCardBackgroundColor));
42 AddChildView(content_view);
45 ~SearchCardView() override {}
48 } // namespace
50 SearchResultPageView::SearchResultPageView() : selected_index_(0) {
51 if (switches::IsExperimentalAppListEnabled()) {
52 gfx::ShadowValue shadow = GetShadowForZHeight(kSearchResultZHeight);
53 scoped_ptr<views::Border> border(new views::ShadowBorder(shadow));
55 gfx::Insets insets = gfx::Insets(kTopPadding, kExperimentalSearchBoxPadding,
56 0, kExperimentalSearchBoxPadding);
57 insets += -border->GetInsets();
59 views::BoxLayout* layout =
60 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, kGroupSpacing);
61 layout->set_inside_border_insets(insets);
63 SetLayoutManager(layout);
64 } else {
65 SetLayoutManager(new views::FillLayout);
69 SearchResultPageView::~SearchResultPageView() {
72 void SearchResultPageView::SetSelection(bool select) {
73 if (select)
74 SetSelectedIndex(0, false);
75 else
76 ClearSelectedIndex();
79 void SearchResultPageView::AddSearchResultContainerView(
80 AppListModel::SearchResults* results_model,
81 SearchResultContainerView* result_container) {
82 views::View* view_to_add = result_container;
83 if (switches::IsExperimentalAppListEnabled())
84 view_to_add = new SearchCardView(result_container);
86 AddChildView(view_to_add);
87 result_container_views_.push_back(result_container);
88 result_container->SetResults(results_model);
89 result_container->set_delegate(this);
92 bool SearchResultPageView::OnKeyPressed(const ui::KeyEvent& event) {
93 if (HasSelection() &&
94 result_container_views_.at(selected_index_)->OnKeyPressed(event)) {
95 return true;
98 int dir = 0;
99 bool directional_movement = false;
100 switch (event.key_code()) {
101 case ui::VKEY_TAB:
102 dir = event.IsShiftDown() ? -1 : 1;
103 break;
104 case ui::VKEY_UP:
105 dir = -1;
106 directional_movement = true;
107 break;
108 case ui::VKEY_DOWN:
109 dir = 1;
110 directional_movement = true;
111 break;
112 default:
113 return false;
116 // Find the next result container with results.
117 int new_selected = selected_index_;
118 do {
119 new_selected += dir;
120 } while (IsValidSelectionIndex(new_selected) &&
121 result_container_views_[new_selected]->num_results() == 0);
123 if (IsValidSelectionIndex(new_selected)) {
124 SetSelectedIndex(new_selected, directional_movement);
125 return true;
128 return false;
131 void SearchResultPageView::ClearSelectedIndex() {
132 if (HasSelection())
133 result_container_views_[selected_index_]->ClearSelectedIndex();
135 selected_index_ = -1;
138 void SearchResultPageView::SetSelectedIndex(int index,
139 bool directional_movement) {
140 bool from_bottom = index < selected_index_;
142 // Reset the old selected view's selection.
143 ClearSelectedIndex();
145 selected_index_ = index;
146 // Set the new selected view's selection to its first result.
147 result_container_views_[selected_index_]->OnContainerSelected(
148 from_bottom, directional_movement);
151 bool SearchResultPageView::IsValidSelectionIndex(int index) {
152 return index >= 0 && index < static_cast<int>(result_container_views_.size());
155 void SearchResultPageView::OnSearchResultContainerResultsChanged() {
156 DCHECK(!result_container_views_.empty());
158 // Only sort and layout the containers when they have all updated.
159 for (SearchResultContainerView* view : result_container_views_) {
160 if (view->UpdateScheduled()) {
161 return;
165 SearchResultContainerView* old_selection =
166 HasSelection() ? result_container_views_[selected_index_] : nullptr;
168 // Truncate the currently selected container's selection if necessary. If
169 // there are no results, the selection will be cleared below.
170 if (old_selection && old_selection->num_results() > 0 &&
171 old_selection->selected_index() >= old_selection->num_results()) {
172 old_selection->SetSelectedIndex(old_selection->num_results() - 1);
175 if (switches::IsExperimentalAppListEnabled()) {
176 // Sort the result container views by their score.
177 std::sort(result_container_views_.begin(), result_container_views_.end(),
178 [](const SearchResultContainerView* a,
179 const SearchResultContainerView* b) -> bool {
180 return a->container_score() > b->container_score();
183 int result_y_index = 0;
184 for (size_t i = 0; i < result_container_views_.size(); ++i) {
185 SearchResultContainerView* view = result_container_views_[i];
186 ReorderChildView(view->parent(), i);
188 view->NotifyFirstResultYIndex(result_y_index);
190 result_y_index += view->GetYSize();
194 Layout();
196 SearchResultContainerView* new_selection = nullptr;
197 if (HasSelection() &&
198 result_container_views_[selected_index_]->num_results() > 0) {
199 new_selection = result_container_views_[selected_index_];
202 // If there was no previous selection or the new view at the selection index
203 // is different from the old one, update the selected view.
204 if (!HasSelection() || old_selection != new_selection) {
205 if (old_selection)
206 old_selection->ClearSelectedIndex();
208 int new_selection_index = new_selection ? selected_index_ : 0;
209 // Clear the current selection so that the selection always comes in from
210 // the top.
211 ClearSelectedIndex();
212 SetSelectedIndex(new_selection_index, false);
216 gfx::Rect SearchResultPageView::GetPageBoundsForState(
217 AppListModel::State state) const {
218 gfx::Rect onscreen_bounds = GetDefaultContentsBounds();
219 switch (state) {
220 case AppListModel::STATE_SEARCH_RESULTS:
221 return onscreen_bounds;
222 default:
223 return GetAboveContentsOffscreenBounds(onscreen_bounds.size());
227 void SearchResultPageView::OnAnimationUpdated(double progress,
228 AppListModel::State from_state,
229 AppListModel::State to_state) {
230 if (from_state != AppListModel::STATE_SEARCH_RESULTS &&
231 to_state != AppListModel::STATE_SEARCH_RESULTS) {
232 return;
235 gfx::Rect onscreen_bounds(
236 GetPageBoundsForState(AppListModel::STATE_SEARCH_RESULTS));
237 set_clip_insets(bounds().InsetsFrom(onscreen_bounds));
240 int SearchResultPageView::GetSearchBoxZHeight() const {
241 return switches::IsExperimentalAppListEnabled()
242 ? kSearchResultZHeight
243 : AppListPage::GetSearchBoxZHeight();
246 void SearchResultPageView::OnHidden() {
247 ClearSelectedIndex();
250 } // namespace app_list