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 content::WebContents
* start_page_contents
=
82 view_delegate
->GetStartPageContents();
84 new StartPageView(app_list_main_view
, start_page_contents
);
85 AddChildView(start_page_view_
);
86 view_model_
->Add(start_page_view_
, kIndexStartPage
);
89 GetSearchResultListView(view_model_
.get())->SetResults(model
->results());
92 ContentsView::~ContentsView() {
95 void ContentsView::CancelDrag() {
96 if (apps_container_view_
->apps_grid_view()->has_dragged_view())
97 apps_container_view_
->apps_grid_view()->EndDrag(true);
98 if (apps_container_view_
->app_list_folder_view()
100 ->has_dragged_view()) {
101 apps_container_view_
->app_list_folder_view()->items_grid_view()->EndDrag(
106 void ContentsView::SetDragAndDropHostOfCurrentAppList(
107 ApplicationDragAndDropHost
* drag_and_drop_host
) {
108 apps_container_view_
->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host
);
111 void ContentsView::SetShowState(ShowState show_state
) {
112 if (show_state_
== show_state
)
115 show_state_
= show_state
;
119 void ContentsView::ShowStateChanged() {
120 SearchResultListView
* results_view
=
121 GetSearchResultListView(view_model_
.get());
122 // TODO(xiyuan): Highlight default match instead of the first.
123 if (show_state_
== SHOW_SEARCH_RESULTS
&& results_view
->visible())
124 results_view
->SetSelectedIndex(0);
125 results_view
->UpdateAutoLaunchState();
127 // Notify parent AppListMainView of show state change.
128 app_list_main_view_
->OnContentsViewShowStateChanged();
130 if (show_state_
== SHOW_START_PAGE
)
131 GetStartPageView(view_model_
.get())->Reset();
133 AnimateToIdealBounds();
136 void ContentsView::CalculateIdealBounds() {
137 gfx::Rect
rect(GetContentsBounds());
141 if (app_list::switches::IsExperimentalAppListEnabled()) {
142 int incoming_view_index
= 0;
143 switch (show_state_
) {
145 incoming_view_index
= kIndexAppsContainer
;
147 case SHOW_SEARCH_RESULTS
:
148 incoming_view_index
= kIndexSearchResults
;
150 case SHOW_START_PAGE
:
151 incoming_view_index
= kIndexStartPage
;
157 gfx::Rect
incoming_target(rect
);
158 gfx::Rect
outgoing_target(rect
);
159 outgoing_target
.set_x(-outgoing_target
.width());
161 for (int i
= 0; i
< view_model_
->view_size(); ++i
) {
162 view_model_
->set_ideal_bounds(i
,
163 i
== incoming_view_index
? incoming_target
169 gfx::Rect
container_frame(rect
);
170 gfx::Rect
results_frame(rect
);
172 // Offsets apps grid and result list based on |show_state_|.
173 // SearchResultListView is on top of apps grid. Visible view is left in
174 // visible area and invisible ones is put out of the visible area.
175 int contents_area_height
= rect
.height();
176 switch (show_state_
) {
178 results_frame
.Offset(0, -contents_area_height
);
180 case SHOW_SEARCH_RESULTS
:
181 container_frame
.Offset(0, contents_area_height
);
184 NOTREACHED() << "Unknown show_state_ " << show_state_
;
188 view_model_
->set_ideal_bounds(kIndexAppsContainer
, container_frame
);
189 view_model_
->set_ideal_bounds(kIndexSearchResults
, results_frame
);
192 void ContentsView::AnimateToIdealBounds() {
193 CalculateIdealBounds();
194 for (int i
= 0; i
< view_model_
->view_size(); ++i
) {
195 bounds_animator_
->AnimateViewTo(view_model_
->view_at(i
),
196 view_model_
->ideal_bounds(i
));
200 void ContentsView::ShowSearchResults(bool show
) {
201 SetShowState(show
? SHOW_SEARCH_RESULTS
: SHOW_APPS
);
204 void ContentsView::ShowFolderContent(AppListFolderItem
* item
) {
205 apps_container_view_
->ShowActiveFolder(item
);
208 void ContentsView::Prerender() {
209 const int selected_page
= std::max(0, pagination_model_
->selected_page());
210 apps_container_view_
->apps_grid_view()->Prerender(selected_page
);
213 gfx::Size
ContentsView::GetPreferredSize() const {
214 const gfx::Size container_size
= GetAppsContainerView(view_model_
.get())->
215 apps_grid_view()->GetPreferredSize();
216 const gfx::Size results_size
=
217 GetSearchResultListView(view_model_
.get())->GetPreferredSize();
219 int width
= std::max(container_size
.width(), results_size
.width());
220 int height
= std::max(container_size
.height(), results_size
.height());
221 return gfx::Size(width
, height
);
224 void ContentsView::Layout() {
225 CalculateIdealBounds();
226 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_
);
229 bool ContentsView::OnKeyPressed(const ui::KeyEvent
& event
) {
230 switch (show_state_
) {
232 return GetAppsContainerView(view_model_
.get())->OnKeyPressed(event
);
233 case SHOW_SEARCH_RESULTS
:
234 return GetSearchResultListView(view_model_
.get())->OnKeyPressed(event
);
235 case SHOW_START_PAGE
:
236 return GetStartPageView(view_model_
.get())->OnKeyPressed(event
);
238 NOTREACHED() << "Unknown show state " << show_state_
;
243 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent
& event
) {
244 if (show_state_
!= SHOW_APPS
)
248 if (abs(event
.x_offset()) > abs(event
.y_offset()))
249 offset
= event
.x_offset();
251 offset
= event
.y_offset();
253 if (abs(offset
) > kMinMouseWheelToSwitchPage
) {
254 if (!pagination_model_
->has_transition()) {
255 pagination_model_
->SelectPageRelative(
256 offset
> 0 ? -1 : 1, true);
264 void ContentsView::OnGestureEvent(ui::GestureEvent
* event
) {
265 if (show_state_
!= SHOW_APPS
)
268 switch (event
->type()) {
269 case ui::ET_GESTURE_SCROLL_BEGIN
:
270 pagination_model_
->StartScroll();
273 case ui::ET_GESTURE_SCROLL_UPDATE
:
274 // event->details.scroll_x() > 0 means moving contents to right. That is,
275 // transitioning to previous page.
276 pagination_model_
->UpdateScroll(
277 event
->details().scroll_x() / GetContentsBounds().width());
280 case ui::ET_GESTURE_SCROLL_END
:
281 pagination_model_
->EndScroll(pagination_model_
->
282 transition().progress
< kFinishTransitionThreshold
);
285 case ui::ET_SCROLL_FLING_START
: {
286 pagination_model_
->EndScroll(true);
287 if (fabs(event
->details().velocity_x()) > kMinHorizVelocityToSwitchPage
) {
288 pagination_model_
->SelectPageRelative(
289 event
->details().velocity_x() < 0 ? 1 : -1,
300 void ContentsView::OnScrollEvent(ui::ScrollEvent
* event
) {
301 if (show_state_
!= SHOW_APPS
||
302 event
->type() == ui::ET_SCROLL_FLING_CANCEL
) {
307 if (std::abs(event
->x_offset()) > std::abs(event
->y_offset()))
308 offset
= event
->x_offset();
310 offset
= event
->y_offset();
312 if (std::abs(offset
) > kMinScrollToSwitchPage
) {
313 if (!pagination_model_
->has_transition()) {
314 pagination_model_
->SelectPageRelative(offset
> 0 ? -1 : 1,
318 event
->StopPropagation();
322 } // namespace app_list