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 "ui/aura_shell/app_list/app_list_groups_view.h" |
| 6 |
| 7 #include "base/utf_string_conversions.h" |
| 8 #include "third_party/skia/include/core/SkColor.h" |
| 9 #include "ui/aura_shell/app_list/app_list_item_group_model.h" |
| 10 #include "ui/aura_shell/app_list/app_list_item_group_view.h" |
| 11 #include "ui/aura_shell/app_list/app_list_item_view.h" |
| 12 #include "ui/aura_shell/app_list/app_list_model.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 aura_shell { |
| 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 aura_shell |
OLD | NEW |