OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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_groups_view.h" | |
6 | |
7 #include "ash/app_list/app_list_item_group_model.h" | |
8 #include "ash/app_list/app_list_item_group_view.h" | |
9 #include "ash/app_list/app_list_item_view.h" | |
10 #include "ash/app_list/app_list_model.h" | |
11 #include "base/utf_string_conversions.h" | |
12 #include "third_party/skia/include/core/SkColor.h" | |
13 #include "ui/base/resource/resource_bundle.h" | |
14 #include "ui/views/animation/bounds_animator.h" | |
15 #include "ui/views/controls/button/text_button.h" | |
16 #include "ui/views/layout/box_layout.h" | |
17 | |
18 namespace ash { | |
19 | |
20 namespace { | |
21 | |
22 const SkColor kPageHeaderColor = SkColorSetARGB(0xFF, 0xB2, 0xB2, 0xB2); | |
23 const SkColor kSelectedPageHeaderColor = SK_ColorWHITE; | |
24 | |
25 // Creates page headers view that hosts page title buttons. | |
26 views::View* CreatePageHeader() { | |
27 views::View* header = new views::View; | |
28 header->SetLayoutManager( | |
29 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); | |
30 return header; | |
31 } | |
32 | |
33 // Creates page header button view that shows page title. | |
34 views::View* CreatePageHeaderButton(views::ButtonListener* listener, | |
35 const std::string& title ) { | |
36 views::TextButton* button = new views::TextButton(listener, | |
37 UTF8ToUTF16(title)); | |
38 | |
39 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | |
40 button->SetFont(rb.GetFont(ResourceBundle::BaseFont).DeriveFont( | |
41 2, gfx::Font::BOLD)); | |
42 button->SetEnabledColor(kPageHeaderColor); | |
43 return button; | |
44 } | |
45 | |
46 // Gets preferred bounds of buttons and page. | |
47 void GetPageAndHeaderBounds(views::View* parent, | |
48 views::View* buttons, | |
49 views::View* page, | |
50 gfx::Rect* buttons_bounds, | |
51 gfx::Rect* page_bounds) { | |
52 gfx::Rect content_bounds = parent->GetContentsBounds(); | |
53 | |
54 if (buttons) { | |
55 gfx::Size buttons_size = buttons->GetPreferredSize(); | |
56 if (buttons_bounds) { | |
57 buttons_bounds->SetRect( | |
58 (content_bounds.width() - buttons_size.width()) / 2, | |
59 content_bounds.bottom() - buttons_size.height(), | |
60 buttons_size.width(), buttons_size.height()); | |
61 } | |
62 | |
63 content_bounds.set_height( | |
64 std::max(0, content_bounds.height() - buttons_size.height())); | |
65 } | |
66 | |
67 if (page_bounds) { | |
68 gfx::Size page_size = page->GetPreferredSize(); | |
69 *page_bounds = content_bounds.Center(page_size); | |
70 } | |
71 } | |
72 | |
73 } // namespace | |
74 | |
75 AppListGroupsView::AppListGroupsView(AppListModel* model, | |
76 AppListItemViewListener* listener) | |
77 : model_(model), | |
78 listener_(listener), | |
79 page_buttons_(NULL), | |
80 current_page_(0) { | |
81 animator_.reset(new views::BoundsAnimator(this)); | |
82 model_->AddObserver(this); | |
83 Update(); | |
84 } | |
85 | |
86 AppListGroupsView::~AppListGroupsView() { | |
87 model_->RemoveObserver(this); | |
88 } | |
89 | |
90 views::View* AppListGroupsView::GetFocusedTile() const { | |
91 AppListItemGroupView* page = GetCurrentPageView(); | |
92 return page ? page->GetFocusedTile() : NULL; | |
93 } | |
94 | |
95 void AppListGroupsView::Update() { | |
96 current_page_ = 0; | |
97 page_buttons_ = NULL; | |
98 RemoveAllChildViews(true); | |
99 | |
100 int page_count = model_->group_count(); | |
101 if (!page_count) | |
102 return; | |
103 | |
104 if (page_count > 1) | |
105 AddChildView(page_buttons_ = CreatePageHeader()); | |
106 | |
107 for (int i = 0; i < page_count; ++i) { | |
108 AppListItemGroupModel* group = model_->GetGroup(i); | |
109 AddPage(group->title(), new AppListItemGroupView(group, listener_)); | |
110 } | |
111 | |
112 if (!size().IsEmpty()) | |
113 Layout(); | |
114 SetCurrentPage(0); | |
115 } | |
116 | |
117 void AppListGroupsView::AddPage(const std::string& title, | |
118 AppListItemGroupView* page) { | |
119 pages_.push_back(page); | |
120 AddChildView(page); | |
121 | |
122 if (page_buttons_) | |
123 page_buttons_->AddChildView(CreatePageHeaderButton(this, title)); | |
124 } | |
125 | |
126 int AppListGroupsView::GetPreferredTilesPerRow() const { | |
127 return std::max(1, width() / AppListItemView::kTileSize); | |
128 } | |
129 | |
130 AppListItemGroupView* AppListGroupsView::GetCurrentPageView() const { | |
131 return static_cast<size_t>(current_page_) < pages_.size() ? | |
132 pages_[current_page_] : NULL; | |
133 } | |
134 | |
135 void AppListGroupsView::SetCurrentPage(int page) { | |
136 int previous_page = current_page_; | |
137 current_page_ = page; | |
138 | |
139 // Updates page buttons. | |
140 if (page_buttons_) { | |
141 for (int i = 0; i < page_buttons_->child_count(); ++i) { | |
142 views::TextButton* button = static_cast<views::TextButton*>( | |
143 page_buttons_->child_at(i)); | |
144 | |
145 button->SetEnabledColor(i == current_page_ ? | |
146 kSelectedPageHeaderColor : kPageHeaderColor); | |
147 } | |
148 page_buttons_->SchedulePaint(); | |
149 } | |
150 | |
151 // Gets sliding animation direction. | |
152 int dir = previous_page < current_page_ ? -1 : | |
153 previous_page > current_page_ ? 1 : 0; | |
154 | |
155 // Skips animation if no sliding needed or no valid size. | |
156 if (dir == 0 || size().IsEmpty()) | |
157 return; | |
158 | |
159 animator_->Cancel(); | |
160 | |
161 // Makes sure new page has correct layout and focus to its focused tile. | |
162 AppListItemGroupView* current_view = GetCurrentPageView(); | |
163 current_view->SetTilesPerRow(GetPreferredTilesPerRow()); | |
164 views::View* tile = current_view->GetFocusedTile(); | |
165 if (tile) | |
166 tile->RequestFocus(); | |
167 | |
168 // Prepares current page before animation. | |
169 gfx::Rect current_page_bounds; | |
170 GetPageAndHeaderBounds(this, page_buttons_, current_view, | |
171 NULL, ¤t_page_bounds); | |
172 current_page_bounds.Offset(- dir * width(), 0); | |
173 current_view->SetBoundsRect(current_page_bounds); | |
174 | |
175 // Schedules animations to slide out previous page and slide in current page. | |
176 AppListItemGroupView* previous_view = pages_[previous_page]; | |
177 gfx::Rect previous_page_bounds = previous_view->bounds(); | |
178 previous_page_bounds.Offset(dir * width(), 0); | |
179 animator_->AnimateViewTo(previous_view, previous_page_bounds); | |
180 | |
181 current_page_bounds.Offset(dir * width(), 0); | |
182 animator_->AnimateViewTo(current_view, current_page_bounds); | |
183 } | |
184 | |
185 void AppListGroupsView::Layout() { | |
186 AppListItemGroupView* page = GetCurrentPageView(); | |
187 if (!page) | |
188 return; | |
189 | |
190 page->SetTilesPerRow(GetPreferredTilesPerRow()); | |
191 | |
192 gfx::Rect buttons_bounds; | |
193 gfx::Rect page_bounds; | |
194 GetPageAndHeaderBounds(this, page_buttons_, page, | |
195 &buttons_bounds, &page_bounds); | |
196 | |
197 if (page_buttons_) | |
198 page_buttons_->SetBoundsRect(buttons_bounds); | |
199 | |
200 page->SetBoundsRect(page_bounds); | |
201 } | |
202 | |
203 bool AppListGroupsView::OnKeyPressed(const views::KeyEvent& event) { | |
204 if (event.IsControlDown()) { | |
205 switch (event.key_code()) { | |
206 case ui::VKEY_LEFT: | |
207 if (current_page_ > 0) | |
208 SetCurrentPage(current_page_ - 1); | |
209 return true; | |
210 case ui::VKEY_RIGHT: | |
211 if (static_cast<size_t>(current_page_ + 1) < pages_.size()) | |
212 SetCurrentPage(current_page_ + 1); | |
213 return true; | |
214 default: | |
215 break; | |
216 } | |
217 } | |
218 | |
219 return false; | |
220 } | |
221 | |
222 void AppListGroupsView::ButtonPressed(views::Button* sender, | |
223 const views::Event& event) { | |
224 DCHECK(page_buttons_); | |
225 for (int i = 0; i < page_buttons_->child_count(); ++i) { | |
226 if (page_buttons_->child_at(i) == sender) | |
227 SetCurrentPage(i); | |
228 } | |
229 } | |
230 | |
231 void AppListGroupsView::ListItemsAdded(int start, int count) { | |
232 Update(); | |
233 } | |
234 | |
235 void AppListGroupsView::ListItemsRemoved(int start, int count) { | |
236 Update(); | |
237 } | |
238 | |
239 void AppListGroupsView::ListItemsChanged(int start, int count) { | |
240 NOTREACHED(); | |
241 } | |
242 | |
243 } // namespace ash | |
OLD | NEW |