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

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

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

Powered by Google App Engine
This is Rietveld 408576698