OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "ui/app_list/contents_view.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ui/app_list/app_list_constants.h" | |
10 #include "ui/app_list/app_list_view.h" | |
11 #include "ui/app_list/apps_grid_view.h" | |
12 #include "ui/app_list/pagination_model.h" | |
13 #include "ui/app_list/search_result_list_view.h" | |
14 #include "ui/base/events/event.h" | |
15 #include "ui/views/animation/bounds_animator.h" | |
16 #include "ui/views/view_model.h" | |
17 #include "ui/views/view_model_utils.h" | |
18 | |
19 namespace app_list { | |
20 | |
21 namespace { | |
22 | |
23 const int kPreferredIconDimension = 48; | |
24 | |
25 // Indexes of interesting views in ViewModel of ContentsView. | |
26 const int kIndexAppsGrid = 0; | |
27 const int kIndexSearchResults = 1; | |
28 | |
29 const int kMinMouseWheelToSwitchPage = 20; | |
30 const int kMinScrollToSwitchPage = 20; | |
31 const int kMinHorizVelocityToSwitchPage = 800; | |
32 | |
33 const double kFinishTransitionThreshold = 0.33; | |
34 | |
35 // Helpers to get certain child view from |model|. | |
36 AppsGridView* GetAppsGridView(views::ViewModel* model) { | |
37 return static_cast<AppsGridView*>(model->view_at(kIndexAppsGrid)); | |
38 } | |
39 | |
40 SearchResultListView* GetSearchResultListView(views::ViewModel* model) { | |
41 return static_cast<SearchResultListView*>( | |
42 model->view_at(kIndexSearchResults)); | |
43 } | |
44 | |
45 } // namespace | |
46 | |
47 ContentsView::ContentsView(AppListView* app_list_view, | |
48 PaginationModel* pagination_model) | |
49 : show_state_(SHOW_APPS), | |
50 pagination_model_(pagination_model), | |
51 view_model_(new views::ViewModel), | |
52 ALLOW_THIS_IN_INITIALIZER_LIST( | |
53 bounds_animator_(new views::BoundsAnimator(this))) { | |
54 pagination_model_->SetTransitionDurations( | |
55 kPageTransitionDurationInMs, | |
56 kOverscrollPageTransitionDurationMs); | |
57 | |
58 AppsGridView* apps_grid_view = new AppsGridView(app_list_view, | |
59 pagination_model); | |
60 apps_grid_view->SetLayout(kPreferredIconDimension, | |
61 kPreferredCols, | |
62 kPreferredRows); | |
63 AddChildView(apps_grid_view); | |
64 view_model_->Add(apps_grid_view, kIndexAppsGrid); | |
65 | |
66 SearchResultListView* search_results_view = new SearchResultListView( | |
67 app_list_view); | |
68 AddChildView(search_results_view); | |
69 view_model_->Add(search_results_view, kIndexSearchResults); | |
70 } | |
71 | |
72 ContentsView::~ContentsView() { | |
73 } | |
74 | |
75 void ContentsView::SetModel(AppListModel* model) { | |
76 if (model) { | |
77 GetAppsGridView(view_model_.get())->SetModel(model); | |
78 GetSearchResultListView(view_model_.get())->SetResults(model->results()); | |
79 } else { | |
80 GetAppsGridView(view_model_.get())->SetModel(NULL); | |
81 GetSearchResultListView(view_model_.get())->SetResults(NULL); | |
82 } | |
83 } | |
84 | |
85 void ContentsView::SetShowState(ShowState show_state) { | |
86 if (show_state_ == show_state) | |
87 return; | |
88 | |
89 show_state_ = show_state; | |
90 ShowStateChanged(); | |
91 } | |
92 | |
93 void ContentsView::ShowStateChanged() { | |
94 if (show_state_ == SHOW_SEARCH_RESULTS) { | |
95 // TODO(xiyuan): Highlight default match instead of the first. | |
96 SearchResultListView* results_view = | |
97 GetSearchResultListView(view_model_.get()); | |
98 if (results_view->visible()) | |
99 results_view->SetSelectedIndex(0); | |
100 } | |
101 | |
102 AnimateToIdealBounds(); | |
103 } | |
104 | |
105 void ContentsView::CalculateIdealBounds() { | |
106 gfx::Rect rect(GetContentsBounds()); | |
107 if (rect.IsEmpty()) | |
108 return; | |
109 | |
110 gfx::Rect grid_frame(rect); | |
111 gfx::Rect results_frame(rect); | |
112 | |
113 // Offsets apps grid and result list based on |show_state_|. | |
114 // SearchResultListView is on top of apps grid. Visible view is left in | |
115 // visible area and invisible ones is put out of the visible area. | |
116 int contents_area_height = rect.height(); | |
117 switch (show_state_) { | |
118 case SHOW_APPS: | |
119 results_frame.Offset(0, -contents_area_height); | |
120 break; | |
121 case SHOW_SEARCH_RESULTS: | |
122 grid_frame.Offset(0, contents_area_height); | |
123 break; | |
124 default: | |
125 NOTREACHED() << "Unknown show_state_ " << show_state_; | |
126 break; | |
127 } | |
128 | |
129 view_model_->set_ideal_bounds(kIndexAppsGrid, grid_frame); | |
130 view_model_->set_ideal_bounds(kIndexSearchResults, results_frame); | |
131 } | |
132 | |
133 void ContentsView::AnimateToIdealBounds() { | |
134 CalculateIdealBounds(); | |
135 for (int i = 0; i < view_model_->view_size(); ++i) { | |
136 bounds_animator_->AnimateViewTo(view_model_->view_at(i), | |
137 view_model_->ideal_bounds(i)); | |
138 } | |
139 } | |
140 | |
141 void ContentsView::ShowSearchResults(bool show) { | |
142 SetShowState(show ? SHOW_SEARCH_RESULTS : SHOW_APPS); | |
143 } | |
144 | |
145 gfx::Size ContentsView::GetPreferredSize() { | |
146 const gfx::Size grid_size = | |
147 GetAppsGridView(view_model_.get())->GetPreferredSize(); | |
148 const gfx::Size results_size = | |
149 GetSearchResultListView(view_model_.get())->GetPreferredSize(); | |
150 | |
151 int width = std::max(grid_size.width(), results_size.width()); | |
152 int height = std::max(grid_size.height(), results_size.height()); | |
153 return gfx::Size(width, height); | |
154 } | |
155 | |
156 void ContentsView::Layout() { | |
157 CalculateIdealBounds(); | |
158 views::ViewModelUtils::SetViewBoundsToIdealBounds(*view_model_); | |
159 } | |
160 | |
161 bool ContentsView::OnKeyPressed(const ui::KeyEvent& event) { | |
162 switch (show_state_) { | |
163 case SHOW_APPS: | |
164 return GetAppsGridView(view_model_.get())->OnKeyPressed(event); | |
165 case SHOW_SEARCH_RESULTS: | |
166 return GetSearchResultListView(view_model_.get())->OnKeyPressed(event); | |
167 default: | |
168 NOTREACHED() << "Unknown show state " << show_state_; | |
169 } | |
170 return false; | |
171 } | |
172 | |
173 bool ContentsView::OnMouseWheel(const ui::MouseWheelEvent& event) { | |
174 if (show_state_ != SHOW_APPS) | |
175 return false; | |
176 | |
177 if (abs(event.offset()) > kMinMouseWheelToSwitchPage) { | |
178 if (!pagination_model_->has_transition()) | |
179 pagination_model_->SelectPageRelative(event.offset() > 0 ? -1 : 1, true); | |
180 return true; | |
181 } | |
182 | |
183 return false; | |
184 } | |
185 | |
186 void ContentsView::OnGestureEvent(ui::GestureEvent* event) { | |
187 if (show_state_ != SHOW_APPS) | |
188 return; | |
189 | |
190 switch (event->type()) { | |
191 case ui::ET_GESTURE_SCROLL_BEGIN: | |
192 pagination_model_->StartScroll(); | |
193 event->SetHandled(); | |
194 return; | |
195 case ui::ET_GESTURE_SCROLL_UPDATE: | |
196 // event->details.scroll_x() > 0 means moving contents to right. That is, | |
197 // transitioning to previous page. | |
198 pagination_model_->UpdateScroll( | |
199 event->details().scroll_x() / GetContentsBounds().width()); | |
200 event->SetHandled(); | |
201 return; | |
202 case ui::ET_GESTURE_SCROLL_END: | |
203 pagination_model_->EndScroll(pagination_model_-> | |
204 transition().progress < kFinishTransitionThreshold); | |
205 event->SetHandled(); | |
206 return; | |
207 case ui::ET_SCROLL_FLING_START: { | |
208 pagination_model_->EndScroll(true); | |
209 if (fabs(event->details().velocity_x()) > kMinHorizVelocityToSwitchPage) { | |
210 pagination_model_->SelectPageRelative( | |
211 event->details().velocity_x() < 0 ? 1 : -1, | |
212 true); | |
213 } | |
214 event->SetHandled(); | |
215 return; | |
216 } | |
217 default: | |
218 break; | |
219 } | |
220 } | |
221 | |
222 void ContentsView::OnScrollEvent(ui::ScrollEvent* event) { | |
223 if (show_state_ != SHOW_APPS || | |
224 event->type() == ui::ET_SCROLL_FLING_CANCEL || | |
225 abs(event->x_offset()) < kMinScrollToSwitchPage) { | |
226 return; | |
227 } | |
228 | |
229 if (!pagination_model_->has_transition()) { | |
230 pagination_model_->SelectPageRelative(event->x_offset() > 0 ? -1 : 1, | |
231 true); | |
232 } | |
233 event->SetHandled(); | |
234 } | |
235 | |
236 } // namespace app_list | |
OLD | NEW |