Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: ui/app_list/views/contents_view.cc

Issue 316393002: App list uses PaginationModel to transition between pages. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed tests -- adds blank pages so we have 3 pages in the test environment. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/app_list/views/contents_view.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
14 #include "ui/app_list/views/app_list_folder_view.h" 13 #include "ui/app_list/views/app_list_folder_view.h"
15 #include "ui/app_list/views/app_list_main_view.h" 14 #include "ui/app_list/views/app_list_main_view.h"
16 #include "ui/app_list/views/apps_container_view.h" 15 #include "ui/app_list/views/apps_container_view.h"
17 #include "ui/app_list/views/apps_grid_view.h" 16 #include "ui/app_list/views/apps_grid_view.h"
18 #include "ui/app_list/views/search_result_list_view.h" 17 #include "ui/app_list/views/search_result_list_view.h"
19 #include "ui/app_list/views/start_page_view.h" 18 #include "ui/app_list/views/start_page_view.h"
20 #include "ui/events/event.h" 19 #include "ui/events/event.h"
21 #include "ui/views/animation/bounds_animator.h"
22 #include "ui/views/view_model.h" 20 #include "ui/views/view_model.h"
23 #include "ui/views/view_model_utils.h" 21 #include "ui/views/view_model_utils.h"
24 22
25 namespace app_list { 23 namespace app_list {
26 24
27 namespace { 25 namespace {
28 26
29 const int kMinMouseWheelToSwitchPage = 20; 27 const int kMinMouseWheelToSwitchPage = 20;
30 const int kMinScrollToSwitchPage = 20; 28 const int kMinScrollToSwitchPage = 20;
31 const int kMinHorizVelocityToSwitchPage = 800; 29 const int kMinHorizVelocityToSwitchPage = 800;
32 30
33 const double kFinishTransitionThreshold = 0.33; 31 const double kFinishTransitionThreshold = 0.33;
34 32
35 } // namespace 33 } // namespace
36 34
37 ContentsView::ContentsView(AppListMainView* app_list_main_view, 35 ContentsView::ContentsView(AppListMainView* app_list_main_view,
38 AppListModel* model, 36 AppListModel* model,
39 AppListViewDelegate* view_delegate) 37 AppListViewDelegate* view_delegate)
40 : search_results_view_(NULL), 38 : search_results_view_(NULL),
41 start_page_view_(NULL), 39 start_page_view_(NULL),
42 app_list_main_view_(app_list_main_view), 40 app_list_main_view_(app_list_main_view),
43 view_model_(new views::ViewModel), 41 view_model_(new views::ViewModel) {
44 bounds_animator_(new views::BoundsAnimator(this)) {
45 DCHECK(model); 42 DCHECK(model);
46 43
47 if (app_list::switches::IsExperimentalAppListEnabled()) { 44 if (app_list::switches::IsExperimentalAppListEnabled()) {
48 start_page_view_ = new StartPageView(app_list_main_view, view_delegate); 45 start_page_view_ = new StartPageView(app_list_main_view, view_delegate);
49 AddLauncherPage(start_page_view_, NAMED_PAGE_START); 46 AddLauncherPage(start_page_view_, NAMED_PAGE_START);
50 } else { 47 } else {
51 search_results_view_ = 48 search_results_view_ =
52 new SearchResultListView(app_list_main_view, view_delegate); 49 new SearchResultListView(app_list_main_view, view_delegate);
53 AddLauncherPage(search_results_view_, NAMED_PAGE_SEARCH_RESULTS); 50 AddLauncherPage(search_results_view_, NAMED_PAGE_SEARCH_RESULTS);
54 search_results_view_->SetResults(model->results()); 51 search_results_view_->SetResults(model->results());
55 } 52 }
56 53
57 apps_container_view_ = new AppsContainerView(app_list_main_view, model); 54 apps_container_view_ = new AppsContainerView(app_list_main_view, model);
58 active_page_ = AddLauncherPage(apps_container_view_, NAMED_PAGE_APPS); 55 int apps_page_index = AddLauncherPage(apps_container_view_, NAMED_PAGE_APPS);
59 56
57 pagination_model_.SelectPage(apps_page_index, false);
58 pagination_model_.AddObserver(this);
60 } 59 }
61 60
62 ContentsView::~ContentsView() { 61 ContentsView::~ContentsView() {
62 pagination_model_.RemoveObserver(this);
63 } 63 }
64 64
65 void ContentsView::CancelDrag() { 65 void ContentsView::CancelDrag() {
66 if (apps_container_view_->apps_grid_view()->has_dragged_view()) 66 if (apps_container_view_->apps_grid_view()->has_dragged_view())
67 apps_container_view_->apps_grid_view()->EndDrag(true); 67 apps_container_view_->apps_grid_view()->EndDrag(true);
68 if (apps_container_view_->app_list_folder_view() 68 if (apps_container_view_->app_list_folder_view()
69 ->items_grid_view() 69 ->items_grid_view()
70 ->has_dragged_view()) { 70 ->has_dragged_view()) {
71 apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag( 71 apps_container_view_->app_list_folder_view()->items_grid_view()->EndDrag(
72 true); 72 true);
73 } 73 }
74 } 74 }
75 75
76 void ContentsView::SetDragAndDropHostOfCurrentAppList( 76 void ContentsView::SetDragAndDropHostOfCurrentAppList(
77 ApplicationDragAndDropHost* drag_and_drop_host) { 77 ApplicationDragAndDropHost* drag_and_drop_host) {
78 apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); 78 apps_container_view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
79 } 79 }
80 80
81 void ContentsView::SetActivePage(int page_index) { 81 void ContentsView::SetActivePage(int page_index) {
82 if (active_page_ == page_index) 82 if (GetActivePageIndex() == page_index)
83 return; 83 return;
84 84
85 active_page_ = page_index; 85 // Start animating to the new page.
86 pagination_model_.SelectPage(page_index, true);
86 ActivePageChanged(); 87 ActivePageChanged();
87 } 88 }
88 89
90 int ContentsView::GetActivePageIndex() const {
91 // The active page is changed at the beginning of an animation, not the end.
92 return pagination_model_.SelectedTargetPage();
93 }
94
89 bool ContentsView::IsNamedPageActive(NamedPage named_page) const { 95 bool ContentsView::IsNamedPageActive(NamedPage named_page) const {
90 std::map<NamedPage, int>::const_iterator it = 96 std::map<NamedPage, int>::const_iterator it =
91 named_page_to_view_.find(named_page); 97 named_page_to_view_.find(named_page);
92 if (it == named_page_to_view_.end()) 98 if (it == named_page_to_view_.end())
93 return false; 99 return false;
94 return it->second == active_page_; 100 return it->second == GetActivePageIndex();
95 } 101 }
96 102
97 int ContentsView::GetPageIndexForNamedPage(NamedPage named_page) const { 103 int ContentsView::GetPageIndexForNamedPage(NamedPage named_page) const {
98 // Find the index of the view corresponding to the given named_page. 104 // Find the index of the view corresponding to the given named_page.
99 std::map<NamedPage, int>::const_iterator it = 105 std::map<NamedPage, int>::const_iterator it =
100 named_page_to_view_.find(named_page); 106 named_page_to_view_.find(named_page);
101 // GetPageIndexForNamedPage should never be called on a named_page that does 107 // GetPageIndexForNamedPage should never be called on a named_page that does
102 // not have a corresponding view. 108 // not have a corresponding view.
103 DCHECK(it != named_page_to_view_.end()); 109 DCHECK(it != named_page_to_view_.end());
104 return it->second; 110 return it->second;
105 } 111 }
106 112
113 int ContentsView::NumLauncherPages() const {
114 return pagination_model_.total_pages();
115 }
116
107 void ContentsView::ActivePageChanged() { 117 void ContentsView::ActivePageChanged() {
108 // TODO(xiyuan): Highlight default match instead of the first. 118 // TODO(xiyuan): Highlight default match instead of the first.
109 if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS) && 119 if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS) &&
110 search_results_view_->visible()) { 120 search_results_view_->visible()) {
111 search_results_view_->SetSelectedIndex(0); 121 search_results_view_->SetSelectedIndex(0);
112 } 122 }
113 if (search_results_view_) 123 if (search_results_view_)
114 search_results_view_->UpdateAutoLaunchState(); 124 search_results_view_->UpdateAutoLaunchState();
115 125
116 if (IsNamedPageActive(NAMED_PAGE_START)) 126 if (IsNamedPageActive(NAMED_PAGE_START))
117 start_page_view_->Reset(); 127 start_page_view_->Reset();
118 128
119 // Notify parent AppListMainView of the page change. 129 // Notify parent AppListMainView of the page change.
120 app_list_main_view_->UpdateSearchBoxVisibility(); 130 app_list_main_view_->UpdateSearchBoxVisibility();
121
122 AnimateToIdealBounds();
123 } 131 }
124 132
125 void ContentsView::ShowSearchResults(bool show) { 133 void ContentsView::ShowSearchResults(bool show) {
126 NamedPage new_named_page = show ? NAMED_PAGE_SEARCH_RESULTS : NAMED_PAGE_APPS; 134 NamedPage new_named_page = show ? NAMED_PAGE_SEARCH_RESULTS : NAMED_PAGE_APPS;
127 if (app_list::switches::IsExperimentalAppListEnabled()) 135 if (app_list::switches::IsExperimentalAppListEnabled())
128 new_named_page = NAMED_PAGE_START; 136 new_named_page = NAMED_PAGE_START;
129 137
130 SetActivePage(GetPageIndexForNamedPage(new_named_page)); 138 SetActivePage(GetPageIndexForNamedPage(new_named_page));
131 139
132 if (app_list::switches::IsExperimentalAppListEnabled()) { 140 if (app_list::switches::IsExperimentalAppListEnabled()) {
133 if (show) 141 if (show)
134 start_page_view_->ShowSearchResults(); 142 start_page_view_->ShowSearchResults();
135 else 143 else
136 start_page_view_->Reset(); 144 start_page_view_->Reset();
137 app_list_main_view_->UpdateSearchBoxVisibility(); 145 app_list_main_view_->UpdateSearchBoxVisibility();
138 } 146 }
139 } 147 }
140 148
141 bool ContentsView::IsShowingSearchResults() const { 149 bool ContentsView::IsShowingSearchResults() const {
142 return app_list::switches::IsExperimentalAppListEnabled() 150 return app_list::switches::IsExperimentalAppListEnabled()
143 ? IsNamedPageActive(NAMED_PAGE_START) && 151 ? IsNamedPageActive(NAMED_PAGE_START) &&
144 start_page_view_->IsShowingSearchResults() 152 start_page_view_->IsShowingSearchResults()
145 : IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS); 153 : IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS);
146 } 154 }
147 155
148 void ContentsView::CalculateIdealBounds() { 156 void ContentsView::UpdatePageBounds() {
149 gfx::Rect rect(GetContentsBounds()); 157 gfx::Rect rect(GetContentsBounds());
150 if (rect.IsEmpty()) 158 if (rect.IsEmpty())
151 return; 159 return;
152 160
153 if (app_list::switches::IsExperimentalAppListEnabled()) { 161 // The bounds calculations will potentially be mid-transition (depending on
154 gfx::Rect incoming_target(rect); 162 // the state of the PaginationModel).
calamity 2014/06/17 05:43:45 This comment is a bit weird now since this is only
Matt Giuca 2014/06/17 06:04:07 To the second point: thought about it, but I think
155 gfx::Rect outgoing_target(rect); 163 int current_page = std::max(0, pagination_model_.selected_page());
156 outgoing_target.set_x(-outgoing_target.width()); 164 int target_page = current_page;
157 165 double progress = 1;
158 for (int i = 0; i < view_model_->view_size(); ++i) { 166 if (pagination_model_.has_transition()) {
159 view_model_->set_ideal_bounds( 167 const PaginationModel::Transition& transition =
160 i, i == active_page_ ? incoming_target : outgoing_target); 168 pagination_model_.transition();
169 if (pagination_model_.is_valid_page(transition.target_page)) {
170 target_page = transition.target_page;
171 progress = transition.progress;
161 } 172 }
162 return;
163 } 173 }
164 174
165 gfx::Rect container_frame(rect); 175 gfx::Rect incoming_target(rect);
166 gfx::Rect results_frame(rect); 176 gfx::Rect outgoing_target(rect);
177 int dir = target_page > current_page ? -1 : 1;
167 178
168 // Offsets apps grid and result list based on |active_page_|. 179 if (app_list::switches::IsExperimentalAppListEnabled()) {
169 // SearchResultListView is on top of apps grid. Visible view is left in 180 // The experimental app list transitions horizontally.
170 // visible area and invisible ones is put out of the visible area. 181 int page_width = rect.width();
171 int contents_area_height = rect.height(); 182 int transition_offset = progress * page_width * dir;
172 if (IsNamedPageActive(NAMED_PAGE_APPS))
173 results_frame.Offset(0, -contents_area_height);
174 else if (IsNamedPageActive(NAMED_PAGE_SEARCH_RESULTS))
175 container_frame.Offset(0, contents_area_height);
176 else
177 NOTREACHED() << "Page " << active_page_ << " invalid in current app list.";
178 183
179 view_model_->set_ideal_bounds(GetPageIndexForNamedPage(NAMED_PAGE_APPS), 184 outgoing_target.set_x(transition_offset);
180 container_frame); 185 incoming_target.set_x(dir < 0 ? transition_offset + page_width
181 view_model_->set_ideal_bounds( 186 : transition_offset - page_width);
182 GetPageIndexForNamedPage(NAMED_PAGE_SEARCH_RESULTS), results_frame); 187 } else {
183 } 188 // The normal app list transitions vertically.
189 int page_height = rect.height();
190 int transition_offset = progress * page_height * dir;
184 191
185 void ContentsView::AnimateToIdealBounds() { 192 outgoing_target.set_y(transition_offset);
186 CalculateIdealBounds(); 193 incoming_target.set_y(dir < 0 ? transition_offset + page_height
187 for (int i = 0; i < view_model_->view_size(); ++i) { 194 : transition_offset - page_height);
188 bounds_animator_->AnimateViewTo(view_model_->view_at(i),
189 view_model_->ideal_bounds(i));
190 } 195 }
196
197 view_model_->view_at(current_page)->SetBoundsRect(outgoing_target);
198 view_model_->view_at(target_page)->SetBoundsRect(incoming_target);
191 } 199 }
192 200
193 PaginationModel* ContentsView::GetAppsPaginationModel() { 201 PaginationModel* ContentsView::GetAppsPaginationModel() {
194 return apps_container_view_->apps_grid_view()->pagination_model(); 202 return apps_container_view_->apps_grid_view()->pagination_model();
195 } 203 }
196 204
197 void ContentsView::ShowFolderContent(AppListFolderItem* item) { 205 void ContentsView::ShowFolderContent(AppListFolderItem* item) {
198 apps_container_view_->ShowActiveFolder(item); 206 apps_container_view_->ShowActiveFolder(item);
199 } 207 }
200 208
201 void ContentsView::Prerender() { 209 void ContentsView::Prerender() {
202 const int selected_page = 210 const int selected_page =
203 std::max(0, GetAppsPaginationModel()->selected_page()); 211 std::max(0, GetAppsPaginationModel()->selected_page());
204 apps_container_view_->apps_grid_view()->Prerender(selected_page); 212 apps_container_view_->apps_grid_view()->Prerender(selected_page);
205 } 213 }
206 214
215 views::View* ContentsView::GetPageView(int index) {
216 return view_model_->view_at(index);
217 }
218
219 void ContentsView::AddBlankPageForTesting() {
220 AddLauncherPage(new views::View);
221 }
222
207 int ContentsView::AddLauncherPage(views::View* view) { 223 int ContentsView::AddLauncherPage(views::View* view) {
208 int page_index = view_model_->view_size(); 224 int page_index = view_model_->view_size();
209 AddChildView(view); 225 AddChildView(view);
210 view_model_->Add(view, page_index); 226 view_model_->Add(view, page_index);
227 pagination_model_.SetTotalPages(view_model_->view_size());
211 return page_index; 228 return page_index;
212 } 229 }
213 230
214 int ContentsView::AddLauncherPage(views::View* view, NamedPage named_page) { 231 int ContentsView::AddLauncherPage(views::View* view, NamedPage named_page) {
215 int page_index = AddLauncherPage(view); 232 int page_index = AddLauncherPage(view);
216 named_page_to_view_.insert(std::pair<NamedPage, int>(named_page, page_index)); 233 named_page_to_view_.insert(std::pair<NamedPage, int>(named_page, page_index));
217 return page_index; 234 return page_index;
218 } 235 }
219 236
220 gfx::Size ContentsView::GetPreferredSize() const { 237 gfx::Size ContentsView::GetPreferredSize() const {
221 const gfx::Size container_size = 238 const gfx::Size container_size =
222 apps_container_view_->apps_grid_view()->GetPreferredSize(); 239 apps_container_view_->apps_grid_view()->GetPreferredSize();
223 const gfx::Size results_size = search_results_view_ 240 const gfx::Size results_size = search_results_view_
224 ? search_results_view_->GetPreferredSize() 241 ? search_results_view_->GetPreferredSize()
225 : gfx::Size(); 242 : gfx::Size();
226 243
227 int width = std::max(container_size.width(), results_size.width()); 244 int width = std::max(container_size.width(), results_size.width());
228 int height = std::max(container_size.height(), results_size.height()); 245 int height = std::max(container_size.height(), results_size.height());
229 return gfx::Size(width, height); 246 return gfx::Size(width, height);
230 } 247 }
231 248
232 void ContentsView::Layout() { 249 void ContentsView::Layout() {
233 CalculateIdealBounds(); 250 // Immediately finish all current animations.
234 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); 251 pagination_model_.FinishAnimation();
252
253 // Move the current view onto the screen, and all other views off screen to
254 // the left. (Since we are not animating, we don't need to be careful about
255 // which side we place the off-screen views onto.)
256 gfx::Rect rect(GetContentsBounds());
257 if (rect.IsEmpty())
258 return;
259
260 gfx::Rect offscreen_target(rect);
261 offscreen_target.set_x(-rect.width());
262
263 for (int i = 0; i < view_model_->view_size(); ++i) {
264 views::View* view = view_model_->view_at(i);
265 if (i == pagination_model_.SelectedTargetPage())
266 view->SetBoundsRect(rect);
267 else
268 view->SetBoundsRect(offscreen_target);
calamity 2014/06/17 05:43:45 Consider ternary operator.
Matt Giuca 2014/06/17 06:04:07 Done.
269 }
235 } 270 }
236 271
237 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) { 272 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) {
238 return view_model_->view_at(active_page_)->OnKeyPressed(event); 273 return view_model_->view_at(GetActivePageIndex())->OnKeyPressed(event);
239 } 274 }
240 275
241 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) { 276 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) {
242 if (!IsNamedPageActive(NAMED_PAGE_APPS)) 277 if (!IsNamedPageActive(NAMED_PAGE_APPS))
243 return false; 278 return false;
244 279
245 int offset; 280 int offset;
246 if (abs(event.x_offset()) > abs(event.y_offset())) 281 if (abs(event.x_offset()) > abs(event.y_offset()))
247 offset = event.x_offset(); 282 offset = event.x_offset();
248 else 283 else
249 offset = event.y_offset(); 284 offset = event.y_offset();
250 285
251 if (abs(offset) > kMinMouseWheelToSwitchPage) { 286 if (abs(offset) > kMinMouseWheelToSwitchPage) {
252 if (!GetAppsPaginationModel()->has_transition()) { 287 if (!GetAppsPaginationModel()->has_transition()) {
253 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true); 288 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true);
254 } 289 }
255 return true; 290 return true;
256 } 291 }
257 292
258 return false; 293 return false;
259 } 294 }
260 295
296 void ContentsView::TotalPagesChanged() {
297 }
298
299 void ContentsView::SelectedPageChanged(int old_selected, int new_selected) {
300 }
301
302 void ContentsView::TransitionStarted() {
303 }
304
305 void ContentsView::TransitionChanged() {
306 UpdatePageBounds();
307 }
308
261 void ContentsView::OnGestureEvent(ui::GestureEvent* event) { 309 void ContentsView::OnGestureEvent(ui::GestureEvent* event) {
262 if (!IsNamedPageActive(NAMED_PAGE_APPS)) 310 if (!IsNamedPageActive(NAMED_PAGE_APPS))
263 return; 311 return;
264 312
265 switch (event->type()) { 313 switch (event->type()) {
266 case ui::ET_GESTURE_SCROLL_BEGIN: 314 case ui::ET_GESTURE_SCROLL_BEGIN:
267 GetAppsPaginationModel()->StartScroll(); 315 GetAppsPaginationModel()->StartScroll();
268 event->SetHandled(); 316 event->SetHandled();
269 return; 317 return;
270 case ui::ET_GESTURE_SCROLL_UPDATE: 318 case ui::ET_GESTURE_SCROLL_UPDATE:
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 if (std::abs(offset) > kMinScrollToSwitchPage) { 357 if (std::abs(offset) > kMinScrollToSwitchPage) {
310 if (!GetAppsPaginationModel()->has_transition()) { 358 if (!GetAppsPaginationModel()->has_transition()) {
311 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true); 359 GetAppsPaginationModel()->SelectPageRelative(offset > 0 ? -1 : 1, true);
312 } 360 }
313 event->SetHandled(); 361 event->SetHandled();
314 event->StopPropagation(); 362 event->StopPropagation();
315 } 363 }
316 } 364 }
317 365
318 } // namespace app_list 366 } // namespace app_list
OLDNEW
« no previous file with comments | « ui/app_list/views/contents_view.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698