1 // Copyright (c) 2012 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/contents_view.h"
9 #include "base/logging.h"
10 #include "ui/app_list/app_list_constants.h"
11 #include "ui/app_list/app_list_switches.h"
12 #include "ui/app_list/app_list_view_delegate.h"
13 #include "ui/app_list/pagination_model.h"
14 #include "ui/app_list/views/app_list_folder_view.h"
15 #include "ui/app_list/views/app_list_main_view.h"
16 #include "ui/app_list/views/apps_container_view.h"
17 #include "ui/app_list/views/apps_grid_view.h"
18 #include "ui/app_list/views/search_result_list_view.h"
19 #include "ui/app_list/views/start_page_view.h"
20 #include "ui/events/event.h"
21 #include "ui/views/animation/bounds_animator.h"
22 #include "ui/views/view_model.h"
23 #include "ui/views/view_model_utils.h"
29 // Indexes of interesting views in ViewModel of ContentsView.
30 const int kIndexAppsContainer
= 0;
31 const int kIndexSearchResults
= 1;
32 const int kIndexStartPage
= 2;
34 const int kMinMouseWheelToSwitchPage
= 20;
35 const int kMinScrollToSwitchPage
= 20;
36 const int kMinHorizVelocityToSwitchPage
= 800;
38 const double kFinishTransitionThreshold
= 0.33;
40 AppsContainerView
* GetAppsContainerView(views::ViewModel
* model
) {
41 return static_cast<AppsContainerView
*>(model
->view_at(kIndexAppsContainer
));
44 SearchResultListView
* GetSearchResultListView(views::ViewModel
* model
) {
45 return static_cast<SearchResultListView
*>(
46 model
->view_at(kIndexSearchResults
));
49 StartPageView
* GetStartPageView(views::ViewModel
* model
) {
50 return static_cast<StartPageView
*>(model
->view_at(kIndexStartPage
));
55 ContentsView::ContentsView(AppListMainView
* app_list_main_view
,
56 PaginationModel
* pagination_model
,
58 AppListViewDelegate
* view_delegate
)
59 : show_state_(SHOW_APPS
),
60 pagination_model_(pagination_model
),
61 start_page_view_(NULL
),
62 app_list_main_view_(app_list_main_view
),
63 view_model_(new views::ViewModel
),
64 bounds_animator_(new views::BoundsAnimator(this)) {
66 pagination_model_
->SetTransitionDurations(
67 kPageTransitionDurationInMs
,
68 kOverscrollPageTransitionDurationMs
);
70 apps_container_view_
=
71 new AppsContainerView(app_list_main_view
, pagination_model
, model
);
72 AddChildView(apps_container_view_
);
73 view_model_
->Add(apps_container_view_
, kIndexAppsContainer
);
75 SearchResultListView
* search_results_view
= new SearchResultListView(
76 app_list_main_view
, view_delegate
);
77 AddChildView(search_results_view
);
78 view_model_
->Add(search_results_view
, kIndexSearchResults
);
80 if (app_list::switches::IsExperimentalAppListEnabled()) {
81 start_page_view_
= new StartPageView(app_list_main_view
, view_delegate
);
82 AddChildView(start_page_view_
);
83 view_model_
->Add(start_page_view_
, kIndexStartPage
);
86 GetSearchResultListView(view_model_
.get())->SetResults(model
->results());
89 ContentsView::~ContentsView() {
92 void ContentsView::CancelDrag() {
93 if (apps_container_view_
->apps_grid_view()->has_dragged_view())
94 apps_container_view_
->apps_grid_view()->EndDrag(true);
95 if (apps_container_view_
->app_list_folder_view()
97 ->has_dragged_view()) {
98 apps_container_view_
->app_list_folder_view()->items_grid_view()->EndDrag(
103 void ContentsView::SetDragAndDropHostOfCurrentAppList(
104 ApplicationDragAndDropHost
* drag_and_drop_host
) {
105 apps_container_view_
->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host
);
108 void ContentsView::SetShowState(ShowState show_state
) {
109 if (show_state_
== show_state
)
112 show_state_
= show_state
;
116 void ContentsView::ShowStateChanged() {
117 SearchResultListView
* results_view
=
118 GetSearchResultListView(view_model_
.get());
119 // TODO(xiyuan): Highlight default match instead of the first.
120 if (show_state_
== SHOW_SEARCH_RESULTS
&& results_view
->visible())
121 results_view
->SetSelectedIndex(0);
122 results_view
->UpdateAutoLaunchState();
124 // Notify parent AppListMainView of show state change.
125 app_list_main_view_
->OnContentsViewShowStateChanged();
127 if (show_state_
== SHOW_START_PAGE
)
128 GetStartPageView(view_model_
.get())->Reset();
130 AnimateToIdealBounds();
133 void ContentsView::CalculateIdealBounds() {
134 gfx::Rect
rect(GetContentsBounds());
138 if (app_list::switches::IsExperimentalAppListEnabled()) {
139 int incoming_view_index
= 0;
140 switch (show_state_
) {
142 incoming_view_index
= kIndexAppsContainer
;
144 case SHOW_SEARCH_RESULTS
:
145 incoming_view_index
= kIndexSearchResults
;
147 case SHOW_START_PAGE
:
148 incoming_view_index
= kIndexStartPage
;
154 gfx::Rect
incoming_target(rect
);
155 gfx::Rect
outgoing_target(rect
);
156 outgoing_target
.set_x(-outgoing_target
.width());
158 for (int i
= 0; i
< view_model_
->view_size(); ++i
) {
159 view_model_
->set_ideal_bounds(i
,
160 i
== incoming_view_index
? incoming_target
166 gfx::Rect
container_frame(rect
);
167 gfx::Rect
results_frame(rect
);
169 // Offsets apps grid and result list based on |show_state_|.
170 // SearchResultListView is on top of apps grid. Visible view is left in
171 // visible area and invisible ones is put out of the visible area.
172 int contents_area_height
= rect
.height();
173 switch (show_state_
) {
175 results_frame
.Offset(0, -contents_area_height
);
177 case SHOW_SEARCH_RESULTS
:
178 container_frame
.Offset(0, contents_area_height
);
181 NOTREACHED() << "Unknown show_state_ " << show_state_
;
185 view_model_
->set_ideal_bounds(kIndexAppsContainer
, container_frame
);
186 view_model_
->set_ideal_bounds(kIndexSearchResults
, results_frame
);
189 void ContentsView::AnimateToIdealBounds() {
190 CalculateIdealBounds();
191 for (int i
= 0; i
< view_model_
->view_size(); ++i
) {
192 bounds_animator_
->AnimateViewTo(view_model_
->view_at(i
),
193 view_model_
->ideal_bounds(i
));
197 void ContentsView::ShowSearchResults(bool show
) {
198 SetShowState(show
? SHOW_SEARCH_RESULTS
: SHOW_APPS
);
201 void ContentsView::ShowFolderContent(AppListFolderItem
* item
) {
202 apps_container_view_
->ShowActiveFolder(item
);
205 void ContentsView::Prerender() {
206 const int selected_page
= std::max(0, pagination_model_
->selected_page());
207 apps_container_view_
->apps_grid_view()->Prerender(selected_page
);
210 gfx::Size
ContentsView::GetPreferredSize() const {
211 const gfx::Size container_size
= GetAppsContainerView(view_model_
.get())->
212 apps_grid_view()->GetPreferredSize();
213 const gfx::Size results_size
=
214 GetSearchResultListView(view_model_
.get())->GetPreferredSize();
216 int width
= std::max(container_size
.width(), results_size
.width());
217 int height
= std::max(container_size
.height(), results_size
.height());
218 return gfx::Size(width
, height
);
221 void ContentsView::Layout() {
222 CalculateIdealBounds();
223 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_
);
226 bool ContentsView::OnKeyPressed(const ui::KeyEvent
& event
) {
227 switch (show_state_
) {
229 return GetAppsContainerView(view_model_
.get())->OnKeyPressed(event
);
230 case SHOW_SEARCH_RESULTS
:
231 return GetSearchResultListView(view_model_
.get())->OnKeyPressed(event
);
232 case SHOW_START_PAGE
:
233 return GetStartPageView(view_model_
.get())->OnKeyPressed(event
);
235 NOTREACHED() << "Unknown show state " << show_state_
;
240 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent
& event
) {
241 if (show_state_
!= SHOW_APPS
)
245 if (abs(event
.x_offset()) > abs(event
.y_offset()))
246 offset
= event
.x_offset();
248 offset
= event
.y_offset();
250 if (abs(offset
) > kMinMouseWheelToSwitchPage
) {
251 if (!pagination_model_
->has_transition()) {
252 pagination_model_
->SelectPageRelative(
253 offset
> 0 ? -1 : 1, true);
261 void ContentsView::OnGestureEvent(ui::GestureEvent
* event
) {
262 if (show_state_
!= SHOW_APPS
)
265 switch (event
->type()) {
266 case ui::ET_GESTURE_SCROLL_BEGIN
:
267 pagination_model_
->StartScroll();
270 case ui::ET_GESTURE_SCROLL_UPDATE
:
271 // event->details.scroll_x() > 0 means moving contents to right. That is,
272 // transitioning to previous page.
273 pagination_model_
->UpdateScroll(
274 event
->details().scroll_x() / GetContentsBounds().width());
277 case ui::ET_GESTURE_SCROLL_END
:
278 pagination_model_
->EndScroll(pagination_model_
->
279 transition().progress
< kFinishTransitionThreshold
);
282 case ui::ET_SCROLL_FLING_START
: {
283 pagination_model_
->EndScroll(true);
284 if (fabs(event
->details().velocity_x()) > kMinHorizVelocityToSwitchPage
) {
285 pagination_model_
->SelectPageRelative(
286 event
->details().velocity_x() < 0 ? 1 : -1,
297 void ContentsView::OnScrollEvent(ui::ScrollEvent
* event
) {
298 if (show_state_
!= SHOW_APPS
||
299 event
->type() == ui::ET_SCROLL_FLING_CANCEL
) {
304 if (std::abs(event
->x_offset()) > std::abs(event
->y_offset()))
305 offset
= event
->x_offset();
307 offset
= event
->y_offset();
309 if (std::abs(offset
) > kMinScrollToSwitchPage
) {
310 if (!pagination_model_
->has_transition()) {
311 pagination_model_
->SelectPageRelative(offset
> 0 ? -1 : 1,
315 event
->StopPropagation();
319 } // namespace app_list