1 // Copyright 2013 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/views/apps_container_view.h" 6 7 #include <algorithm> 8 #include <vector> 9 10 #include "base/command_line.h" 11 #include "ui/app_list/app_list_constants.h" 12 #include "ui/app_list/app_list_folder_item.h" 13 #include "ui/app_list/app_list_switches.h" 14 #include "ui/app_list/views/app_list_folder_view.h" 15 #include "ui/app_list/views/app_list_item_view.h" 16 #include "ui/app_list/views/app_list_main_view.h" 17 #include "ui/app_list/views/apps_grid_view.h" 18 #include "ui/app_list/views/folder_background_view.h" 19 #include "ui/events/event.h" 20 21 namespace app_list { 22 23 AppsContainerView::AppsContainerView(AppListMainView* app_list_main_view, 24 AppListModel* model) 25 : model_(model), 26 show_state_(SHOW_NONE), 27 top_icon_animation_pending_count_(0) { 28 apps_grid_view_ = new AppsGridView(app_list_main_view); 29 int cols = kPreferredCols; 30 int rows = kPreferredRows; 31 // ShouldCenterWindow also implies that it is wide instead of tall. 32 if (app_list_main_view->ShouldCenterWindow()) { 33 cols = kExperimentalPreferredCols; 34 rows = kExperimentalPreferredRows; 35 } 36 apps_grid_view_->SetLayout(kPreferredIconDimension, cols, rows); 37 AddChildView(apps_grid_view_); 38 39 folder_background_view_ = new FolderBackgroundView(); 40 AddChildView(folder_background_view_); 41 42 app_list_folder_view_ = 43 new AppListFolderView(this, model, app_list_main_view); 44 // The folder view is initially hidden. 45 app_list_folder_view_->SetVisible(false); 46 AddChildView(app_list_folder_view_); 47 48 apps_grid_view_->SetModel(model_); 49 apps_grid_view_->SetItemList(model_->top_level_item_list()); 50 SetShowState(SHOW_APPS, 51 false); /* show apps without animation */ 52 } 53 54 AppsContainerView::~AppsContainerView() { 55 } 56 57 void AppsContainerView::ShowActiveFolder(AppListFolderItem* folder_item) { 58 // Prevent new animations from starting if there are currently animations 59 // pending. This fixes crbug.com/357099. 60 if (top_icon_animation_pending_count_) 61 return; 62 63 app_list_folder_view_->SetAppListFolderItem(folder_item); 64 SetShowState(SHOW_ACTIVE_FOLDER, false); 65 66 CreateViewsForFolderTopItemsAnimation(folder_item, true); 67 } 68 69 void AppsContainerView::ShowApps(AppListFolderItem* folder_item) { 70 if (top_icon_animation_pending_count_) 71 return; 72 73 PrepareToShowApps(folder_item); 74 SetShowState(SHOW_APPS, 75 true); /* show apps with animation */ 76 } 77 78 void AppsContainerView::ResetForShowApps() { 79 SetShowState(SHOW_APPS, false /* show apps without animation */); 80 folder_background_view_->UpdateFolderContainerBubble( 81 FolderBackgroundView::NO_BUBBLE); 82 } 83 84 void AppsContainerView::SetDragAndDropHostOfCurrentAppList( 85 ApplicationDragAndDropHost* drag_and_drop_host) { 86 apps_grid_view()->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); 87 app_list_folder_view()->items_grid_view()-> 88 SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); 89 } 90 91 void AppsContainerView::ReparentFolderItemTransit( 92 AppListFolderItem* folder_item) { 93 if (top_icon_animation_pending_count_) 94 return; 95 96 PrepareToShowApps(folder_item); 97 SetShowState(SHOW_ITEM_REPARENT, false); 98 } 99 100 bool AppsContainerView::IsInFolderView() const { 101 return show_state_ == SHOW_ACTIVE_FOLDER; 102 } 103 104 gfx::Size AppsContainerView::GetPreferredSize() const { 105 const gfx::Size grid_size = apps_grid_view_->GetPreferredSize(); 106 const gfx::Size folder_view_size = app_list_folder_view_->GetPreferredSize(); 107 108 int width = std::max(grid_size.width(), folder_view_size.width()); 109 int height = std::max(grid_size.height(), folder_view_size.height()); 110 return gfx::Size(width, height); 111 } 112 113 void AppsContainerView::Layout() { 114 gfx::Rect rect(GetContentsBounds()); 115 if (rect.IsEmpty()) 116 return; 117 118 switch (show_state_) { 119 case SHOW_APPS: 120 apps_grid_view_->SetBoundsRect(rect); 121 break; 122 case SHOW_ACTIVE_FOLDER: 123 folder_background_view_->SetBoundsRect(rect); 124 app_list_folder_view_->SetBoundsRect(rect); 125 break; 126 case SHOW_ITEM_REPARENT: 127 break; 128 default: 129 NOTREACHED(); 130 } 131 } 132 133 bool AppsContainerView::OnKeyPressed(const ui::KeyEvent& event) { 134 if (show_state_ == SHOW_APPS) 135 return apps_grid_view_->OnKeyPressed(event); 136 else 137 return app_list_folder_view_->OnKeyPressed(event); 138 } 139 140 void AppsContainerView::OnTopIconAnimationsComplete() { 141 --top_icon_animation_pending_count_; 142 143 if (!top_icon_animation_pending_count_) { 144 // Clean up the transitional views used for top item icon animation. 145 top_icon_views_.clear(); 146 147 // Show the folder icon when closing the folder. 148 if ((show_state_ == SHOW_APPS || show_state_ == SHOW_ITEM_REPARENT) && 149 apps_grid_view_->activated_folder_item_view()) { 150 apps_grid_view_->activated_folder_item_view()->SetVisible(true); 151 } 152 } 153 } 154 155 void AppsContainerView::SetShowState(ShowState show_state, 156 bool show_apps_with_animation) { 157 if (show_state_ == show_state) 158 return; 159 160 show_state_ = show_state; 161 162 switch (show_state_) { 163 case SHOW_APPS: 164 folder_background_view_->SetVisible(false); 165 if (show_apps_with_animation) { 166 app_list_folder_view_->ScheduleShowHideAnimation(false, false); 167 apps_grid_view_->ScheduleShowHideAnimation(true); 168 } else { 169 app_list_folder_view_->HideViewImmediately(); 170 apps_grid_view_->ResetForShowApps(); 171 } 172 break; 173 case SHOW_ACTIVE_FOLDER: 174 folder_background_view_->SetVisible(true); 175 apps_grid_view_->ScheduleShowHideAnimation(false); 176 app_list_folder_view_->ScheduleShowHideAnimation(true, false); 177 break; 178 case SHOW_ITEM_REPARENT: 179 folder_background_view_->SetVisible(false); 180 folder_background_view_->UpdateFolderContainerBubble( 181 FolderBackgroundView::NO_BUBBLE); 182 app_list_folder_view_->ScheduleShowHideAnimation(false, true); 183 apps_grid_view_->ScheduleShowHideAnimation(true); 184 break; 185 default: 186 NOTREACHED(); 187 } 188 189 Layout(); 190 } 191 192 Rects AppsContainerView::GetTopItemIconBoundsInActiveFolder() { 193 // Get the active folder's icon bounds relative to AppsContainerView. 194 AppListItemView* folder_item_view = 195 apps_grid_view_->activated_folder_item_view(); 196 gfx::Rect to_grid_view = folder_item_view->ConvertRectToParent( 197 folder_item_view->GetIconBounds()); 198 gfx::Rect to_container = apps_grid_view_->ConvertRectToParent(to_grid_view); 199 200 return AppListFolderItem::GetTopIconsBounds(to_container); 201 } 202 203 void AppsContainerView::CreateViewsForFolderTopItemsAnimation( 204 AppListFolderItem* active_folder, 205 bool open_folder) { 206 top_icon_views_.clear(); 207 std::vector<gfx::Rect> top_items_bounds = 208 GetTopItemIconBoundsInActiveFolder(); 209 top_icon_animation_pending_count_ = 210 std::min(kNumFolderTopItems, active_folder->item_list()->item_count()); 211 for (size_t i = 0; i < top_icon_animation_pending_count_; ++i) { 212 if (active_folder->GetTopIcon(i).isNull()) 213 continue; 214 215 TopIconAnimationView* icon_view = new TopIconAnimationView( 216 active_folder->GetTopIcon(i), top_items_bounds[i], open_folder); 217 icon_view->AddObserver(this); 218 top_icon_views_.push_back(icon_view); 219 220 // Add the transitional views into child views, and set its bounds to the 221 // same location of the item in the folder list view. 222 AddChildView(top_icon_views_[i]); 223 top_icon_views_[i]->SetBoundsRect( 224 app_list_folder_view_->ConvertRectToParent( 225 app_list_folder_view_->GetItemIconBoundsAt(i))); 226 static_cast<TopIconAnimationView*>(top_icon_views_[i])->TransformView(); 227 } 228 } 229 230 void AppsContainerView::PrepareToShowApps(AppListFolderItem* folder_item) { 231 if (folder_item) 232 CreateViewsForFolderTopItemsAnimation(folder_item, false); 233 234 // Hide the active folder item until the animation completes. 235 if (apps_grid_view_->activated_folder_item_view()) 236 apps_grid_view_->activated_folder_item_view()->SetVisible(false); 237 } 238 239 } // namespace app_list 240