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

Side by Side Diff: ash/app_list/app_list_model_view.cc

Issue 10388032: Move app list from ash to ui. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: fix nits in #3 Created 8 years, 7 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
OLDNEW
(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 "ash/app_list/app_list_model_view.h"
6
7 #include "ash/app_list/app_list_item_view.h"
8 #include "ash/app_list/app_list_model.h"
9 #include "ash/app_list/pagination_model.h"
10
11 namespace ash {
12
13 AppListModelView::AppListModelView(views::ButtonListener* listener,
14 PaginationModel* pagination_model)
15 : model_(NULL),
16 listener_(listener),
17 pagination_model_(pagination_model),
18 fixed_layout_(false),
19 cols_(0),
20 rows_per_page_(0),
21 selected_item_index_(-1) {
22 set_focusable(true);
23 pagination_model_->AddObserver(this);
24 }
25
26 AppListModelView::~AppListModelView() {
27 if (model_)
28 model_->RemoveObserver(this);
29 pagination_model_->RemoveObserver(this);
30 }
31
32 void AppListModelView::SetLayout(int icon_size, int cols, int rows_per_page) {
33 fixed_layout_ = true;
34
35 icon_size_.SetSize(icon_size, icon_size);
36 cols_ = cols;
37 rows_per_page_ = rows_per_page;
38 }
39
40 void AppListModelView::CalculateLayout(const gfx::Size& content_size,
41 int num_of_tiles,
42 gfx::Size* icon_size,
43 int* rows,
44 int* cols) {
45 DCHECK(!content_size.IsEmpty() && num_of_tiles);
46
47 // Icon sizes to try.
48 const int kIconSizes[] = { 128, 96, 64, 48, 32 };
49
50 double aspect = static_cast<double>(content_size.width()) /
51 content_size.height();
52
53 // Chooses the biggest icon size that could fit all tiles.
54 gfx::Size tile_size;
55 for (size_t i = 0; i < arraysize(kIconSizes); ++i) {
56 icon_size->SetSize(kIconSizes[i], kIconSizes[i]);
57 tile_size = AppListItemView::GetPreferredSizeForIconSize(
58 *icon_size);
59
60 int max_cols = content_size.width() / tile_size.width();
61 int max_rows = content_size.height() / tile_size.height();
62
63 // Skip if |tile_size| could not fit into |content_size|.
64 if (max_cols * max_rows < num_of_tiles)
65 continue;
66
67 // Find a rows/cols pair that has a aspect ratio closest to |aspect|.
68 double min_aspect_diff = 1e5;
69 for (int c = std::max(max_cols / 2, 1); c <= max_cols; ++c) {
70 int r = std::min((num_of_tiles - 1) / c + 1, max_rows);
71 if (c * r < num_of_tiles)
72 continue;
73
74 double aspect_diff = fabs(static_cast<double>(c) / r - aspect);
75 if (aspect_diff < min_aspect_diff) {
76 *cols = c;
77 *rows = r;
78 min_aspect_diff = aspect_diff;
79 }
80 }
81
82 DCHECK((*rows) * (*cols) >= num_of_tiles);
83 return;
84 }
85
86 // No icon size that could fit all tiles.
87 *cols = std::max(content_size.width() / tile_size.width(), 1);
88 *rows = (num_of_tiles - 1) / (*cols) + 1;
89 }
90
91 void AppListModelView::SetModel(AppListModel* model) {
92 if (model_)
93 model_->RemoveObserver(this);
94
95 model_ = model;
96 if (model_)
97 model_->AddObserver(this);
98 Update();
99 }
100
101 void AppListModelView::SetSelectedItem(AppListItemView* item) {
102 int index = GetIndexOf(item);
103 if (index >= 0)
104 SetSelectedItemByIndex(index);
105 }
106
107 void AppListModelView::ClearSelectedItem(AppListItemView* item) {
108 int index = GetIndexOf(item);
109 if (index == selected_item_index_)
110 SetSelectedItemByIndex(-1);
111 }
112
113 void AppListModelView::Update() {
114 selected_item_index_ = -1;
115 RemoveAllChildViews(true);
116 if (!model_ || model_->item_count() == 0)
117 return;
118
119 for (int i = 0; i < model_->item_count(); ++i)
120 AddChildView(new AppListItemView(this, model_->GetItem(i), listener_));
121
122 Layout();
123 SchedulePaint();
124 }
125
126 AppListItemView* AppListModelView::GetItemViewAtIndex(int index) {
127 return static_cast<AppListItemView*>(child_at(index));
128 }
129
130 void AppListModelView::SetSelectedItemByIndex(int index) {
131 if (selected_item_index_ == index)
132 return;
133
134 if (selected_item_index_ >= 0)
135 GetItemViewAtIndex(selected_item_index_)->SetSelected(false);
136
137 if (index < 0 || index >= child_count()) {
138 selected_item_index_ = -1;
139 } else {
140 selected_item_index_ = index;
141 GetItemViewAtIndex(selected_item_index_)->SetSelected(true);
142
143 if (tiles_per_page())
144 pagination_model_->SelectPage(selected_item_index_ / tiles_per_page());
145 }
146 }
147
148 gfx::Size AppListModelView::GetPreferredSize() {
149 if (!fixed_layout_)
150 return gfx::Size();
151
152 gfx::Size tile_size = AppListItemView::GetPreferredSizeForIconSize(
153 icon_size_);
154 return gfx::Size(tile_size.width() * cols_,
155 tile_size.height() * rows_per_page_);
156 }
157
158 void AppListModelView::Layout() {
159 gfx::Rect rect(GetContentsBounds());
160 if (rect.IsEmpty() || child_count() == 0)
161 return;
162
163 gfx::Size tile_size;
164 if (fixed_layout_) {
165 tile_size = AppListItemView::GetPreferredSizeForIconSize(icon_size_);
166 } else {
167 int rows = 0;
168 CalculateLayout(rect.size(), child_count(), &icon_size_, &rows, &cols_);
169
170 tile_size = AppListItemView::GetPreferredSizeForIconSize(
171 icon_size_);
172 rows_per_page_ = tile_size.height() ?
173 std::max(rect.height() / tile_size.height(), 1) : 1;
174
175 tile_size.set_width(std::max(rect.width() / (cols_ + 1),
176 tile_size.width()));
177 tile_size.set_height(std::max(rect.height() / (rows_per_page_ + 1),
178 tile_size.height()));
179 }
180
181 if (!tiles_per_page())
182 return;
183
184 pagination_model_->SetTotalPages((child_count() - 1) / tiles_per_page() + 1);
185 if (pagination_model_->selected_page() < 0)
186 pagination_model_->SelectPage(0);
187
188 gfx::Rect grid_rect = rect.Center(
189 gfx::Size(tile_size.width() * cols_,
190 tile_size.height() * rows_per_page_));
191 grid_rect = grid_rect.Intersect(rect);
192
193 // Layouts items.
194 const int page = pagination_model_->selected_page();
195 const int first_visible_index = page * tiles_per_page();
196 const int last_visible_index = (page + 1) * tiles_per_page() - 1;
197 gfx::Rect current_tile(grid_rect.origin(), tile_size);
198 for (int i = 0; i < child_count(); ++i) {
199 views::View* view = child_at(i);
200 static_cast<AppListItemView*>(view)->SetIconSize(icon_size_);
201
202 if (i < first_visible_index || i > last_visible_index) {
203 view->SetVisible(false);
204 continue;
205 }
206
207 view->SetBoundsRect(current_tile);
208 view->SetVisible(rect.Contains(current_tile));
209
210 current_tile.Offset(tile_size.width(), 0);
211 if ((i + 1) % cols_ == 0) {
212 current_tile.set_x(grid_rect.x());
213 current_tile.set_y(current_tile.y() + tile_size.height());
214 }
215 }
216 }
217
218 bool AppListModelView::OnKeyPressed(const views::KeyEvent& event) {
219 bool handled = false;
220 if (selected_item_index_ >= 0)
221 handled = GetItemViewAtIndex(selected_item_index_)->OnKeyPressed(event);
222
223 if (!handled) {
224 switch (event.key_code()) {
225 case ui::VKEY_LEFT:
226 SetSelectedItemByIndex(std::max(selected_item_index_ - 1, 0));
227 return true;
228 case ui::VKEY_RIGHT:
229 SetSelectedItemByIndex(std::min(selected_item_index_ + 1,
230 child_count() - 1));
231 return true;
232 case ui::VKEY_UP:
233 SetSelectedItemByIndex(std::max(selected_item_index_ - cols_,
234 0));
235 return true;
236 case ui::VKEY_DOWN:
237 if (selected_item_index_ < 0) {
238 SetSelectedItemByIndex(0);
239 } else {
240 SetSelectedItemByIndex(std::min(selected_item_index_ + cols_,
241 child_count() - 1));
242 }
243 return true;
244 case ui::VKEY_PRIOR: {
245 SetSelectedItemByIndex(
246 std::max(selected_item_index_ - tiles_per_page(),
247 0));
248 return true;
249 }
250 case ui::VKEY_NEXT: {
251 if (selected_item_index_ < 0) {
252 SetSelectedItemByIndex(0);
253 } else {
254 SetSelectedItemByIndex(
255 std::min(selected_item_index_ + tiles_per_page(),
256 child_count() - 1));
257 }
258 }
259 default:
260 break;
261 }
262 }
263
264 return handled;
265 }
266
267 bool AppListModelView::OnKeyReleased(const views::KeyEvent& event) {
268 bool handled = false;
269 if (selected_item_index_ >= 0)
270 handled = GetItemViewAtIndex(selected_item_index_)->OnKeyReleased(event);
271
272 return handled;
273 }
274
275 void AppListModelView::OnPaintFocusBorder(gfx::Canvas* canvas) {
276 // Override to not paint focus frame.
277 }
278
279 void AppListModelView::ListItemsAdded(int start, int count) {
280 for (int i = start; i < start + count; ++i) {
281 AddChildViewAt(new AppListItemView(this, model_->GetItem(i), listener_),
282 i);
283 }
284 Layout();
285 SchedulePaint();
286 }
287
288 void AppListModelView::ListItemsRemoved(int start, int count) {
289 for (int i = 0; i < count; ++i)
290 delete child_at(start);
291
292 Layout();
293 SchedulePaint();
294 }
295
296 void AppListModelView::ListItemsChanged(int start, int count) {
297 NOTREACHED();
298 }
299
300 void AppListModelView::TotalPagesChanged() {
301 }
302
303 void AppListModelView::SelectedPageChanged(int old_selected, int new_selected) {
304 Layout();
305 }
306
307 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698