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_view_delegate.h"
12 #include "ui/app_list/pagination_model.h"
13 #include "ui/app_list/views/app_list_main_view.h"
14 #include "ui/app_list/views/apps_container_view.h"
15 #include "ui/app_list/views/apps_grid_view.h"
16 #include "ui/app_list/views/search_result_list_view.h"
17 #include "ui/events/event.h"
18 #include "ui/views/animation/bounds_animator.h"
19 #include "ui/views/view_model.h"
20 #include "ui/views/view_model_utils.h"
26 // Indexes of interesting views in ViewModel of ContentsView.
27 const int kIndexAppsContainer
= 0;
28 const int kIndexSearchResults
= 1;
30 const int kMinMouseWheelToSwitchPage
= 20;
31 const int kMinScrollToSwitchPage
= 20;
32 const int kMinHorizVelocityToSwitchPage
= 800;
34 const double kFinishTransitionThreshold
= 0.33;
36 AppsContainerView
* GetAppsContainerView(views::ViewModel
* model
) {
37 return static_cast<AppsContainerView
*>(model
->view_at(kIndexAppsContainer
));
40 SearchResultListView
* GetSearchResultListView(views::ViewModel
* model
) {
41 return static_cast<SearchResultListView
*>(
42 model
->view_at(kIndexSearchResults
));
47 ContentsView::ContentsView(AppListMainView
* app_list_main_view
,
48 PaginationModel
* pagination_model
,
50 AppListViewDelegate
* view_delegate
)
51 : show_state_(SHOW_APPS
),
52 pagination_model_(pagination_model
),
53 view_delegate_(view_delegate
),
54 view_model_(new views::ViewModel
),
55 bounds_animator_(new views::BoundsAnimator(this)) {
57 pagination_model_
->SetTransitionDurations(
58 kPageTransitionDurationInMs
,
59 kOverscrollPageTransitionDurationMs
);
61 content::WebContents
* start_page_contents
=
62 view_delegate
? view_delegate
->GetStartPageContents() : NULL
;
63 apps_container_view_
= new AppsContainerView(
64 app_list_main_view
, pagination_model
, model
, start_page_contents
);
65 AddChildView(apps_container_view_
);
66 view_model_
->Add(apps_container_view_
, kIndexAppsContainer
);
68 SearchResultListView
* search_results_view
= new SearchResultListView(
70 AddChildView(search_results_view
);
71 view_model_
->Add(search_results_view
, kIndexSearchResults
);
73 GetSearchResultListView(view_model_
.get())->SetResults(model
->results());
76 ContentsView::~ContentsView() {
79 void ContentsView::CancelDrag() {
80 if (apps_container_view_
->apps_grid_view()->has_dragged_view())
81 apps_container_view_
->apps_grid_view()->EndDrag(true);
84 void ContentsView::SetDragAndDropHostOfCurrentAppList(
85 ApplicationDragAndDropHost
* drag_and_drop_host
) {
86 apps_container_view_
->apps_grid_view()->
87 SetDragAndDropHostOfCurrentAppList(drag_and_drop_host
);
90 void ContentsView::SetShowState(ShowState show_state
) {
91 if (show_state_
== show_state
)
94 show_state_
= show_state
;
98 void ContentsView::ShowStateChanged() {
99 if (show_state_
== SHOW_SEARCH_RESULTS
) {
100 // TODO(xiyuan): Highlight default match instead of the first.
101 SearchResultListView
* results_view
=
102 GetSearchResultListView(view_model_
.get());
103 if (results_view
->visible())
104 results_view
->SetSelectedIndex(0);
107 AnimateToIdealBounds();
110 void ContentsView::CalculateIdealBounds() {
111 gfx::Rect
rect(GetContentsBounds());
115 gfx::Rect
container_frame(rect
);
116 gfx::Rect
results_frame(rect
);
118 // Offsets apps grid and result list based on |show_state_|.
119 // SearchResultListView is on top of apps grid. Visible view is left in
120 // visible area and invisible ones is put out of the visible area.
121 int contents_area_height
= rect
.height();
122 switch (show_state_
) {
124 results_frame
.Offset(0, -contents_area_height
);
126 case SHOW_SEARCH_RESULTS
:
127 container_frame
.Offset(0, contents_area_height
);
130 NOTREACHED() << "Unknown show_state_ " << show_state_
;
134 view_model_
->set_ideal_bounds(kIndexAppsContainer
, container_frame
);
135 view_model_
->set_ideal_bounds(kIndexSearchResults
, results_frame
);
138 void ContentsView::AnimateToIdealBounds() {
139 CalculateIdealBounds();
140 for (int i
= 0; i
< view_model_
->view_size(); ++i
) {
141 bounds_animator_
->AnimateViewTo(view_model_
->view_at(i
),
142 view_model_
->ideal_bounds(i
));
146 void ContentsView::ShowSearchResults(bool show
) {
147 SetShowState(show
? SHOW_SEARCH_RESULTS
: SHOW_APPS
);
148 SearchResultListView
* results_view
=
149 GetSearchResultListView(view_model_
.get());
151 results_view
->SetAutoLaunchTimeout(view_delegate_
->GetAutoLaunchTimeout());
153 results_view
->CancelAutoLaunchTimeout();
156 void ContentsView::ShowFolderContent(AppListFolderItem
* item
) {
157 apps_container_view_
->ShowActiveFolder(item
);
160 void ContentsView::CancelAutoLaunch() {
161 GetSearchResultListView(view_model_
.get())->CancelAutoLaunchTimeout();
162 view_delegate_
->AutoLaunchCanceled();
165 void ContentsView::Prerender() {
166 const int selected_page
= std::max(0, pagination_model_
->selected_page());
167 apps_container_view_
->apps_grid_view()->Prerender(selected_page
);
170 gfx::Size
ContentsView::GetPreferredSize() {
171 const gfx::Size container_size
= GetAppsContainerView(view_model_
.get())->
172 apps_grid_view()->GetPreferredSize();
173 const gfx::Size results_size
=
174 GetSearchResultListView(view_model_
.get())->GetPreferredSize();
176 int width
= std::max(container_size
.width(), results_size
.width());
177 int height
= std::max(container_size
.height(), results_size
.height());
178 return gfx::Size(width
, height
);
181 void ContentsView::Layout() {
182 CalculateIdealBounds();
183 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_
);
186 bool ContentsView::OnKeyPressed(const ui::KeyEvent
& event
) {
188 switch (show_state_
) {
190 return GetAppsContainerView(view_model_
.get())->OnKeyPressed(event
);
191 case SHOW_SEARCH_RESULTS
:
192 return GetSearchResultListView(view_model_
.get())->OnKeyPressed(event
);
194 NOTREACHED() << "Unknown show state " << show_state_
;
199 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent
& event
) {
200 if (show_state_
!= SHOW_APPS
)
204 if (abs(event
.x_offset()) > abs(event
.y_offset()))
205 offset
= event
.x_offset();
207 offset
= event
.y_offset();
209 if (abs(offset
) > kMinMouseWheelToSwitchPage
) {
210 if (!pagination_model_
->has_transition()) {
211 pagination_model_
->SelectPageRelative(
212 offset
> 0 ? -1 : 1, true);
220 void ContentsView::OnGestureEvent(ui::GestureEvent
* event
) {
221 if (show_state_
!= SHOW_APPS
)
224 switch (event
->type()) {
225 case ui::ET_GESTURE_SCROLL_BEGIN
:
226 pagination_model_
->StartScroll();
229 case ui::ET_GESTURE_SCROLL_UPDATE
:
230 // event->details.scroll_x() > 0 means moving contents to right. That is,
231 // transitioning to previous page.
232 pagination_model_
->UpdateScroll(
233 event
->details().scroll_x() / GetContentsBounds().width());
236 case ui::ET_GESTURE_SCROLL_END
:
237 pagination_model_
->EndScroll(pagination_model_
->
238 transition().progress
< kFinishTransitionThreshold
);
241 case ui::ET_SCROLL_FLING_START
: {
242 pagination_model_
->EndScroll(true);
243 if (fabs(event
->details().velocity_x()) > kMinHorizVelocityToSwitchPage
) {
244 pagination_model_
->SelectPageRelative(
245 event
->details().velocity_x() < 0 ? 1 : -1,
256 void ContentsView::OnScrollEvent(ui::ScrollEvent
* event
) {
257 if (show_state_
!= SHOW_APPS
||
258 event
->type() == ui::ET_SCROLL_FLING_CANCEL
) {
263 if (abs(event
->x_offset()) > abs(event
->y_offset()))
264 offset
= event
->x_offset();
266 offset
= event
->y_offset();
268 if (abs(offset
) > kMinScrollToSwitchPage
) {
269 if (!pagination_model_
->has_transition()) {
270 pagination_model_
->SelectPageRelative(offset
> 0 ? -1 : 1,
274 event
->StopPropagation();
278 } // namespace app_list