OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/app_list/views/contents_view.h" | 5 #include "ui/app_list/views/contents_view.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "ui/app_list/app_list_constants.h" | 10 #include "ui/app_list/app_list_constants.h" |
11 #include "ui/app_list/app_list_switches.h" | 11 #include "ui/app_list/app_list_switches.h" |
12 #include "ui/app_list/app_list_view_delegate.h" | 12 #include "ui/app_list/app_list_view_delegate.h" |
13 #include "ui/app_list/pagination_model.h" | 13 #include "ui/app_list/pagination_model.h" |
14 #include "ui/app_list/views/app_list_folder_view.h" | 14 #include "ui/app_list/views/app_list_folder_view.h" |
15 #include "ui/app_list/views/app_list_main_view.h" | 15 #include "ui/app_list/views/app_list_main_view.h" |
16 #include "ui/app_list/views/apps_container_view.h" | 16 #include "ui/app_list/views/apps_container_view.h" |
17 #include "ui/app_list/views/apps_grid_view.h" | 17 #include "ui/app_list/views/apps_grid_view.h" |
18 #include "ui/app_list/views/search_result_list_view.h" | 18 #include "ui/app_list/views/search_result_list_view.h" |
19 #include "ui/app_list/views/start_page_view.h" | 19 #include "ui/app_list/views/start_page_view.h" |
20 #include "ui/events/event.h" | 20 #include "ui/events/event.h" |
21 #include "ui/views/animation/bounds_animator.h" | 21 #include "ui/views/animation/bounds_animator.h" |
22 #include "ui/views/view_model.h" | 22 #include "ui/views/view_model.h" |
23 #include "ui/views/view_model_utils.h" | 23 #include "ui/views/view_model_utils.h" |
24 | 24 |
25 namespace app_list { | 25 namespace app_list { |
26 | 26 |
27 namespace { | 27 namespace { |
28 | 28 |
29 // Indexes of interesting views in ViewModel of ContentsView. | |
30 const int kIndexAppsContainer = 0; | |
31 const int kIndexSearchResults = 1; | |
32 const int kIndexStartPage = 2; | |
33 | |
34 const int kMinMouseWheelToSwitchPage = 20; | 29 const int kMinMouseWheelToSwitchPage = 20; |
35 const int kMinScrollToSwitchPage = 20; | 30 const int kMinScrollToSwitchPage = 20; |
36 const int kMinHorizVelocityToSwitchPage = 800; | 31 const int kMinHorizVelocityToSwitchPage = 800; |
37 | 32 |
38 const double kFinishTransitionThreshold = 0.33; | 33 const double kFinishTransitionThreshold = 0.33; |
39 | 34 |
40 } // namespace | 35 } // namespace |
41 | 36 |
42 ContentsView::ContentsView(AppListMainView* app_list_main_view, | 37 ContentsView::ContentsView(AppListMainView* app_list_main_view, |
43 AppListModel* model, | 38 AppListModel* model, |
44 AppListViewDelegate* view_delegate) | 39 AppListViewDelegate* view_delegate) |
45 : show_state_(SHOW_APPS), | 40 : start_page_view_(NULL), |
46 start_page_view_(NULL), | |
47 app_list_main_view_(app_list_main_view), | 41 app_list_main_view_(app_list_main_view), |
48 view_model_(new views::ViewModel), | 42 view_model_(new views::ViewModel), |
49 bounds_animator_(new views::BoundsAnimator(this)) { | 43 bounds_animator_(new views::BoundsAnimator(this)) { |
50 DCHECK(model); | 44 DCHECK(model); |
51 | 45 |
52 apps_container_view_ = new AppsContainerView(app_list_main_view, model); | |
53 AddChildView(apps_container_view_); | |
54 view_model_->Add(apps_container_view_, kIndexAppsContainer); | |
55 | |
56 search_results_view_ = | 46 search_results_view_ = |
57 new SearchResultListView(app_list_main_view, view_delegate); | 47 new SearchResultListView(app_list_main_view, view_delegate); |
58 AddChildView(search_results_view_); | 48 AddLauncherPage(search_results_view_, NAMED_PAGE_SEARCH_RESULTS); |
59 view_model_->Add(search_results_view_, kIndexSearchResults); | |
60 | 49 |
61 if (app_list::switches::IsExperimentalAppListEnabled()) { | 50 if (app_list::switches::IsExperimentalAppListEnabled()) { |
62 start_page_view_ = new StartPageView(app_list_main_view, view_delegate); | 51 start_page_view_ = new StartPageView(app_list_main_view, view_delegate); |
63 AddChildView(start_page_view_); | 52 AddLauncherPage(start_page_view_, NAMED_PAGE_START); |
64 view_model_->Add(start_page_view_, kIndexStartPage); | |
65 } | 53 } |
66 | 54 |
| 55 apps_container_view_ = new AppsContainerView(app_list_main_view, model); |
| 56 active_page_ = AddLauncherPage(apps_container_view_, NAMED_PAGE_APPS); |
| 57 |
67 search_results_view_->SetResults(model->results()); | 58 search_results_view_->SetResults(model->results()); |
68 } | 59 } |
69 | 60 |
70 ContentsView::~ContentsView() { | 61 ContentsView::~ContentsView() { |
71 } | 62 } |
72 | 63 |
73 void ContentsView::CancelDrag() { | 64 void ContentsView::CancelDrag() { |
74 if (apps_container_view_->apps_grid_view()->has_dragged_view()) | 65 if (apps_container_view_->apps_grid_view()->has_dragged_view()) |
75 apps_container_view_->apps_grid_view()->EndDrag(true); | 66 apps_container_view_->apps_grid_view()->EndDrag(true); |
76 if (apps_container_view_->app_list_folder_view() | 67 if (apps_container_view_->app_list_folder_view() |
77 ->items_grid_view() | 68 ->items_grid_view() |
78 ->has_dragged_view()) { | 69 ->has_dragged_view()) { |
79 apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag( | 70 apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag( |
80 true); | 71 true); |
81 } | 72 } |
82 } | 73 } |
83 | 74 |
84 void ContentsView::SetDragAndDropHostOfCurrentAppList( | 75 void ContentsView::SetDragAndDropHostOfCurrentAppList( |
85 ApplicationDragAndDropHost* drag_and_drop_host) { | 76 ApplicationDragAndDropHost* drag_and_drop_host) { |
86 apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); | 77 apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); |
87 } | 78 } |
88 | 79 |
89 void ContentsView::SetShowState(ShowState show_state) { | 80 void ContentsView::SetActivePage(int page_index) { |
90 if (show_state_ == show_state) | 81 if (active_page_ == page_index) |
91 return; | 82 return; |
92 | 83 |
93 show_state_ = show_state; | 84 active_page_ = page_index; |
94 ShowStateChanged(); | 85 ActivePageChanged(); |
95 } | 86 } |
96 | 87 |
97 void ContentsView::ShowStateChanged() { | 88 bool ContentsView::IsNamedPageActive(NamedPage named_page) const { |
| 89 std::map<NamedPage, int>::const_iterator it = |
| 90 named_page_to_view_.find(named_page); |
| 91 if (it == named_page_to_view_.end()) |
| 92 return false; |
| 93 return it->second == active_page_; |
| 94 } |
| 95 |
| 96 int ContentsView::GetPageIndexForNamedPage(NamedPage named_page) const { |
| 97 // Find the index of the view corresponding to the given named_page. |
| 98 std::map<NamedPage, int>::const_iterator it = |
| 99 named_page_to_view_.find(named_page); |
| 100 // GetPageIndexForNamedPage should never be called on a named_page that does |
| 101 // not have a corresponding view. |
| 102 DCHECK(it != named_page_to_view_.end()); |
| 103 return it->second; |
| 104 } |
| 105 |
| 106 void ContentsView::ActivePageChanged() { |
98 // TODO(xiyuan): Highlight default match instead of the first. | 107 // TODO(xiyuan): Highlight default match instead of the first. |
99 if (show_state_ == SHOW_SEARCH_RESULTS && search_results_view_->visible()) | 108 if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS) && |
| 109 search_results_view_->visible()) { |
100 search_results_view_->SetSelectedIndex(0); | 110 search_results_view_->SetSelectedIndex(0); |
| 111 } |
101 search_results_view_->UpdateAutoLaunchState(); | 112 search_results_view_->UpdateAutoLaunchState(); |
102 | 113 |
103 // Notify parent AppListMainView of show state change. | 114 // Notify parent AppListMainView of the page change. |
104 app_list_main_view_->OnContentsViewShowStateChanged(); | 115 app_list_main_view_->OnContentsViewActivePageChanged(); |
105 | 116 |
106 if (show_state_ == SHOW_START_PAGE) | 117 if (IsNamedPageActive(NAMED_PAGE_START)) |
107 start_page_view_->Reset(); | 118 start_page_view_->Reset(); |
108 | 119 |
109 AnimateToIdealBounds(); | 120 AnimateToIdealBounds(); |
110 } | 121 } |
111 | 122 |
112 void ContentsView::CalculateIdealBounds() { | 123 void ContentsView::CalculateIdealBounds() { |
113 gfx::Rect rect(GetContentsBounds()); | 124 gfx::Rect rect(GetContentsBounds()); |
114 if (rect.IsEmpty()) | 125 if (rect.IsEmpty()) |
115 return; | 126 return; |
116 | 127 |
117 if (app_list::switches::IsExperimentalAppListEnabled()) { | 128 if (app_list::switches::IsExperimentalAppListEnabled()) { |
118 int incoming_view_index = 0; | |
119 switch (show_state_) { | |
120 case SHOW_APPS: | |
121 incoming_view_index = kIndexAppsContainer; | |
122 break; | |
123 case SHOW_SEARCH_RESULTS: | |
124 incoming_view_index = kIndexSearchResults; | |
125 break; | |
126 case SHOW_START_PAGE: | |
127 incoming_view_index = kIndexStartPage; | |
128 break; | |
129 default: | |
130 NOTREACHED(); | |
131 } | |
132 | |
133 gfx::Rect incoming_target(rect); | 129 gfx::Rect incoming_target(rect); |
134 gfx::Rect outgoing_target(rect); | 130 gfx::Rect outgoing_target(rect); |
135 outgoing_target.set_x(-outgoing_target.width()); | 131 outgoing_target.set_x(-outgoing_target.width()); |
136 | 132 |
137 for (int i = 0; i < view_model_->view_size(); ++i) { | 133 for (int i = 0; i < view_model_->view_size(); ++i) { |
138 view_model_->set_ideal_bounds(i, | 134 view_model_->set_ideal_bounds( |
139 i == incoming_view_index ? incoming_target | 135 i, i == active_page_ ? incoming_target : outgoing_target); |
140 : outgoing_target); | |
141 } | 136 } |
142 return; | 137 return; |
143 } | 138 } |
144 | 139 |
145 gfx::Rect container_frame(rect); | 140 gfx::Rect container_frame(rect); |
146 gfx::Rect results_frame(rect); | 141 gfx::Rect results_frame(rect); |
147 | 142 |
148 // Offsets apps grid and result list based on |show_state_|. | 143 // Offsets apps grid and result list based on |active_page_|. |
149 // SearchResultListView is on top of apps grid. Visible view is left in | 144 // SearchResultListView is on top of apps grid. Visible view is left in |
150 // visible area and invisible ones is put out of the visible area. | 145 // visible area and invisible ones is put out of the visible area. |
151 int contents_area_height = rect.height(); | 146 int contents_area_height = rect.height(); |
152 switch (show_state_) { | 147 if (IsNamedPageActive(NAMED_PAGE_APPS)) |
153 case SHOW_APPS: | 148 results_frame.Offset(0, -contents_area_height); |
154 results_frame.Offset(0, -contents_area_height); | 149 else if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS)) |
155 break; | 150 container_frame.Offset(0, contents_area_height); |
156 case SHOW_SEARCH_RESULTS: | 151 else |
157 container_frame.Offset(0, contents_area_height); | 152 NOTREACHED() << "Page " << active_page_ << " invalid in current app list."; |
158 break; | |
159 default: | |
160 NOTREACHED() << "Unknown show_state_ " << show_state_; | |
161 break; | |
162 } | |
163 | 153 |
164 view_model_->set_ideal_bounds(kIndexAppsContainer, container_frame); | 154 view_model_->set_ideal_bounds(GetPageIndexForNamedPage(NAMED_PAGE_APPS), |
165 view_model_->set_ideal_bounds(kIndexSearchResults, results_frame); | 155 container_frame); |
| 156 view_model_->set_ideal_bounds( |
| 157 GetPageIndexForNamedPage(NAMED_PAGE_SEARCH_RESULTS), results_frame); |
166 } | 158 } |
167 | 159 |
168 void ContentsView::AnimateToIdealBounds() { | 160 void ContentsView::AnimateToIdealBounds() { |
169 CalculateIdealBounds(); | 161 CalculateIdealBounds(); |
170 for (int i = 0; i < view_model_->view_size(); ++i) { | 162 for (int i = 0; i < view_model_->view_size(); ++i) { |
171 bounds_animator_->AnimateViewTo(view_model_->view_at(i), | 163 bounds_animator_->AnimateViewTo(view_model_->view_at(i), |
172 view_model_->ideal_bounds(i)); | 164 view_model_->ideal_bounds(i)); |
173 } | 165 } |
174 } | 166 } |
175 | 167 |
176 PaginationModel* ContentsView::GetAppsPaginationModel() { | 168 PaginationModel* ContentsView::GetAppsPaginationModel() { |
177 return apps_container_view_->apps_grid_view()->pagination_model(); | 169 return apps_container_view_->apps_grid_view()->pagination_model(); |
178 } | 170 } |
179 | 171 |
180 void ContentsView::ShowSearchResults(bool show) { | 172 void ContentsView::ShowSearchResults(bool show) { |
181 SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS); | 173 NamedPage new_named_page = show ? NAMED_PAGE_SEARCH_RESULTS : NAMED_PAGE_APPS; |
| 174 SetActivePage(GetPageIndexForNamedPage(new_named_page)); |
182 } | 175 } |
183 | 176 |
184 void ContentsView::ShowFolderContent(AppListFolderItem* item) { | 177 void ContentsView::ShowFolderContent(AppListFolderItem* item) { |
185 apps_container_view_->ShowActiveFolder(item); | 178 apps_container_view_->ShowActiveFolder(item); |
186 } | 179 } |
187 | 180 |
188 void ContentsView::Prerender() { | 181 void ContentsView::Prerender() { |
189 const int selected_page = | 182 const int selected_page = |
190 std::max(0, GetAppsPaginationModel()->selected_page()); | 183 std::max(0, GetAppsPaginationModel()->selected_page()); |
191 apps_container_view_->apps_grid_view()->Prerender(selected_page); | 184 apps_container_view_->apps_grid_view()->Prerender(selected_page); |
192 } | 185 } |
193 | 186 |
| 187 int ContentsView::AddLauncherPage(views::View* view) { |
| 188 int page_index = view_model_->view_size(); |
| 189 AddChildView(view); |
| 190 view_model_->Add(view, page_index); |
| 191 return page_index; |
| 192 } |
| 193 |
| 194 int ContentsView::AddLauncherPage(views::View* view, NamedPage named_page) { |
| 195 int page_index = AddLauncherPage(view); |
| 196 named_page_to_view_.insert(std::pair<NamedPage, int>(named_page, page_index)); |
| 197 return page_index; |
| 198 } |
| 199 |
194 gfx::Size ContentsView::GetPreferredSize() const { | 200 gfx::Size ContentsView::GetPreferredSize() const { |
195 const gfx::Size container_size = | 201 const gfx::Size container_size = |
196 apps_container_view_->apps_grid_view()->GetPreferredSize(); | 202 apps_container_view_->apps_grid_view()->GetPreferredSize(); |
197 const gfx::Size results_size = search_results_view_->GetPreferredSize(); | 203 const gfx::Size results_size = search_results_view_->GetPreferredSize(); |
198 | 204 |
199 int width = std::max(container_size.width(), results_size.width()); | 205 int width = std::max(container_size.width(), results_size.width()); |
200 int height = std::max(container_size.height(), results_size.height()); | 206 int height = std::max(container_size.height(), results_size.height()); |
201 return gfx::Size(width, height); | 207 return gfx::Size(width, height); |
202 } | 208 } |
203 | 209 |
204 void ContentsView::Layout() { | 210 void ContentsView::Layout() { |
205 CalculateIdealBounds(); | 211 CalculateIdealBounds(); |
206 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); | 212 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); |
207 } | 213 } |
208 | 214 |
209 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) { | 215 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) { |
210 switch (show_state_) { | 216 return view_model_->view_at(active_page_)->OnKeyPressed(event); |
211 case SHOW_APPS: | |
212 return apps_container_view_->OnKeyPressed(event); | |
213 case SHOW_SEARCH_RESULTS: | |
214 return search_results_view_->OnKeyPressed(event); | |
215 case SHOW_START_PAGE: | |
216 return start_page_view_->OnKeyPressed(event); | |
217 default: | |
218 NOTREACHED() << "Unknown show state " << show_state_; | |
219 } | |
220 return false; | |
221 } | 217 } |
222 | 218 |
223 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) { | 219 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) { |
224 if (show_state_ != SHOW_APPS) | 220 if (!IsNamedPageActive(NAMED_PAGE_APPS)) |
225 return false; | 221 return false; |
226 | 222 |
227 int offset; | 223 int offset; |
228 if (abs(event.x_offset()) > abs(event.y_offset())) | 224 if (abs(event.x_offset()) > abs(event.y_offset())) |
229 offset = event.x_offset(); | 225 offset = event.x_offset(); |
230 else | 226 else |
231 offset = event.y_offset(); | 227 offset = event.y_offset(); |
232 | 228 |
233 if (abs(offset) > kMinMouseWheelToSwitchPage) { | 229 if (abs(offset) > kMinMouseWheelToSwitchPage) { |
234 if (!GetAppsPaginationModel()->has_transition()) { | 230 if (!GetAppsPaginationModel()->has_transition()) { |
235 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true); | 231 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true); |
236 } | 232 } |
237 return true; | 233 return true; |
238 } | 234 } |
239 | 235 |
240 return false; | 236 return false; |
241 } | 237 } |
242 | 238 |
243 void ContentsView::OnGestureEvent(ui::GestureEvent* event) { | 239 void ContentsView::OnGestureEvent(ui::GestureEvent* event) { |
244 if (show_state_ != SHOW_APPS) | 240 if (!IsNamedPageActive(NAMED_PAGE_APPS)) |
245 return; | 241 return; |
246 | 242 |
247 switch (event->type()) { | 243 switch (event->type()) { |
248 case ui::ET_GESTURE_SCROLL_BEGIN: | 244 case ui::ET_GESTURE_SCROLL_BEGIN: |
249 GetAppsPaginationModel()->StartScroll(); | 245 GetAppsPaginationModel()->StartScroll(); |
250 event->SetHandled(); | 246 event->SetHandled(); |
251 return; | 247 return; |
252 case ui::ET_GESTURE_SCROLL_UPDATE: | 248 case ui::ET_GESTURE_SCROLL_UPDATE: |
253 // event->details.scroll_x() > 0 means moving contents to right. That is, | 249 // event->details.scroll_x() > 0 means moving contents to right. That is, |
254 // transitioning to previous page. | 250 // transitioning to previous page. |
(...skipping 15 matching lines...) Expand all Loading... |
270 } | 266 } |
271 event->SetHandled(); | 267 event->SetHandled(); |
272 return; | 268 return; |
273 } | 269 } |
274 default: | 270 default: |
275 break; | 271 break; |
276 } | 272 } |
277 } | 273 } |
278 | 274 |
279 void ContentsView::OnScrollEvent(ui::ScrollEvent* event) { | 275 void ContentsView::OnScrollEvent(ui::ScrollEvent* event) { |
280 if (show_state_ != SHOW_APPS || | 276 if (!IsNamedPageActive(NAMED_PAGE_APPS) || |
281 event->type() == ui::ET_SCROLL_FLING_CANCEL) { | 277 event->type() == ui::ET_SCROLL_FLING_CANCEL) { |
282 return; | 278 return; |
283 } | 279 } |
284 | 280 |
285 float offset; | 281 float offset; |
286 if (std::abs(event->x_offset()) > std::abs(event->y_offset())) | 282 if (std::abs(event->x_offset()) > std::abs(event->y_offset())) |
287 offset = event->x_offset(); | 283 offset = event->x_offset(); |
288 else | 284 else |
289 offset = event->y_offset(); | 285 offset = event->y_offset(); |
290 | 286 |
291 if (std::abs(offset) > kMinScrollToSwitchPage) { | 287 if (std::abs(offset) > kMinScrollToSwitchPage) { |
292 if (!GetAppsPaginationModel()->has_transition()) { | 288 if (!GetAppsPaginationModel()->has_transition()) { |
293 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true); | 289 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true); |
294 } | 290 } |
295 event->SetHandled(); | 291 event->SetHandled(); |
296 event->StopPropagation(); | 292 event->StopPropagation(); |
297 } | 293 } |
298 } | 294 } |
299 | 295 |
300 } // namespace app_list | 296 } // namespace app_list |
OLD | NEW |