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/results_view.h" |
| 6 |
| 7 #include "base/utf_string_conversions.h" |
| 8 #include "ui/aura_shell/app_list/app_list_item_group_model.h" |
| 9 #include "ui/aura_shell/app_list/app_list_model.h" |
| 10 #include "ui/aura_shell/app_list/tile_view.h" |
| 11 #include "ui/aura_shell/app_list/tiles_page_view.h" |
| 12 #include "ui/base/resource/resource_bundle.h" |
| 13 #include "ui/views/animation/bounds_animator.h" |
| 14 #include "ui/views/controls/button/text_button.h" |
| 15 #include "ui/views/layout/box_layout.h" |
| 16 #include "third_party/skia/include/core/SkColor.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 ResultsView::ResultsView(AppListModel* model) |
| 76 : model_(model), |
| 77 page_buttons_(NULL), |
| 78 current_page_(0) { |
| 79 animator_.reset(new views::BoundsAnimator(this)); |
| 80 model_->AddObserver(this); |
| 81 Update(); |
| 82 } |
| 83 |
| 84 ResultsView::~ResultsView() { |
| 85 model_->RemoveObserver(this); |
| 86 } |
| 87 |
| 88 views::View* ResultsView::GetFocusedTile() const { |
| 89 TilesPageView* page = GetCurrentPageView(); |
| 90 return page ? page->GetFocusedTile() : NULL; |
| 91 } |
| 92 |
| 93 void ResultsView::Update() { |
| 94 current_page_ = 0; |
| 95 page_buttons_ = NULL; |
| 96 RemoveAllChildViews(true); |
| 97 |
| 98 int page_count = model_->item_count(); |
| 99 if (!page_count) |
| 100 return; |
| 101 |
| 102 if (page_count > 1) |
| 103 AddChildView(page_buttons_ = CreatePageHeader()); |
| 104 |
| 105 for (int i = 0; i < page_count; ++i) { |
| 106 AppListItemGroupModel* group = model_->item_at(i); |
| 107 AddPage(group->title(), new TilesPageView(group)); |
| 108 } |
| 109 |
| 110 Layout(); |
| 111 SetCurrentPage(0); |
| 112 } |
| 113 |
| 114 void ResultsView::AddPage(const std::string& title, TilesPageView* page) { |
| 115 pages_.push_back(page); |
| 116 AddChildView(page); |
| 117 |
| 118 if (page_buttons_) |
| 119 page_buttons_->AddChildView(CreatePageHeaderButton(this, title)); |
| 120 } |
| 121 |
| 122 int ResultsView::GetPreferredTilesPerRow() const { |
| 123 return std::max(1, width() / TileView::kTileSize); |
| 124 } |
| 125 |
| 126 TilesPageView* ResultsView::GetCurrentPageView() const { |
| 127 return static_cast<size_t>(current_page_) < pages_.size() ? |
| 128 pages_[current_page_] : NULL; |
| 129 } |
| 130 |
| 131 void ResultsView::SetCurrentPage(int page) { |
| 132 int previous_page = current_page_; |
| 133 current_page_ = page; |
| 134 |
| 135 // Swiches focus to focused tile on new page (if any). |
| 136 TilesPageView* current_view = GetCurrentPageView(); |
| 137 current_view->SetTilesPerRow(GetPreferredTilesPerRow()); |
| 138 views::View* tile = current_view->GetFocusedTile(); |
| 139 if (tile) |
| 140 tile->RequestFocus(); |
| 141 |
| 142 // Updates page buttons. |
| 143 if (page_buttons_) { |
| 144 for (int i = 0; i < page_buttons_->child_count(); ++i) { |
| 145 views::TextButton* button = static_cast<views::TextButton*>( |
| 146 page_buttons_->child_at(i)); |
| 147 |
| 148 button->SetEnabledColor(i == current_page_ ? |
| 149 kSelectedPageHeaderColor : kPageHeaderColor); |
| 150 } |
| 151 page_buttons_->SchedulePaint(); |
| 152 } |
| 153 |
| 154 // Gets sliding animation direction. |
| 155 int dir = previous_page < current_page_ ? -1 : |
| 156 previous_page > current_page_ ? 1 : 0; |
| 157 if (dir == 0) |
| 158 return; |
| 159 |
| 160 int view_width = bounds().size().width(); |
| 161 |
| 162 animator_->Cancel(); |
| 163 |
| 164 // Set current page's bounds before animation. |
| 165 gfx::Rect current_page_bounds; |
| 166 GetPageAndHeaderBounds(this, page_buttons_, current_view, |
| 167 NULL, ¤t_page_bounds); |
| 168 current_page_bounds.Offset(- dir * view_width, 0); |
| 169 current_view->SetBoundsRect(current_page_bounds); |
| 170 |
| 171 // Setup animations to slide out previous page and slide in current page. |
| 172 TilesPageView* previous_view = pages_[previous_page]; |
| 173 gfx::Rect previous_page_bounds = previous_view->bounds(); |
| 174 previous_page_bounds.Offset(dir * view_width, 0); |
| 175 animator_->AnimateViewTo(previous_view, previous_page_bounds); |
| 176 |
| 177 current_page_bounds.Offset(dir * view_width, 0); |
| 178 animator_->AnimateViewTo(current_view, current_page_bounds); |
| 179 } |
| 180 |
| 181 void ResultsView::Layout() { |
| 182 TilesPageView* page = GetCurrentPageView(); |
| 183 if (!page) |
| 184 return; |
| 185 |
| 186 page->SetTilesPerRow(GetPreferredTilesPerRow()); |
| 187 |
| 188 gfx::Rect buttons_bounds; |
| 189 gfx::Rect page_bounds; |
| 190 GetPageAndHeaderBounds(this, page_buttons_, page, |
| 191 &buttons_bounds, &page_bounds); |
| 192 |
| 193 if (page_buttons_) |
| 194 page_buttons_->SetBoundsRect(buttons_bounds); |
| 195 |
| 196 page->SetBoundsRect(page_bounds); |
| 197 } |
| 198 |
| 199 bool ResultsView::OnKeyPressed(const views::KeyEvent& event) { |
| 200 if (event.IsControlDown()) { |
| 201 switch (event.key_code()) { |
| 202 case ui::VKEY_LEFT: |
| 203 if (current_page_ > 0) |
| 204 SetCurrentPage(current_page_ - 1); |
| 205 return true; |
| 206 case ui::VKEY_RIGHT: |
| 207 if (static_cast<size_t>(current_page_ + 1) < pages_.size()) |
| 208 SetCurrentPage(current_page_ + 1); |
| 209 return true; |
| 210 default: |
| 211 break; |
| 212 } |
| 213 } |
| 214 |
| 215 return false; |
| 216 } |
| 217 |
| 218 void ResultsView::ButtonPressed(views::Button* sender, |
| 219 const views::Event& event) { |
| 220 DCHECK(page_buttons_); |
| 221 for (int i = 0; i < page_buttons_->child_count(); ++i) { |
| 222 if (page_buttons_->child_at(i) == sender) |
| 223 SetCurrentPage(i); |
| 224 } |
| 225 } |
| 226 |
| 227 void ResultsView::ListItemsAdded(int start, int count) { |
| 228 Update(); |
| 229 } |
| 230 |
| 231 void ResultsView::ListItemsRemoved(int start, int count) { |
| 232 Update(); |
| 233 } |
| 234 |
| 235 void ResultsView::ListItemsChanged(int start, int count) { |
| 236 NOTREACHED(); |
| 237 } |
| 238 |
| 239 } // namespace aura_shell |
OLD | NEW |