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/app_list_folder_item.h" 6 7 #include "base/guid.h" 8 #include "ui/app_list/app_list_constants.h" 9 #include "ui/app_list/app_list_item_list.h" 10 #include "ui/gfx/canvas.h" 11 #include "ui/gfx/image/canvas_image_source.h" 12 #include "ui/gfx/image/image_skia_operations.h" 13 14 namespace app_list { 15 16 namespace { 17 18 const int kItemIconDimension = 16; 19 20 // Generates the folder icon with the top 4 child item icons laid in 2x2 tile. 21 class FolderImageSource : public gfx::CanvasImageSource { 22 public: 23 typedef std::vector<gfx::ImageSkia> Icons; 24 25 FolderImageSource(const Icons& icons, const gfx::Size& size) 26 : gfx::CanvasImageSource(size, false), 27 icons_(icons), 28 size_(size) { 29 DCHECK(icons.size() <= kNumFolderTopItems); 30 } 31 32 virtual ~FolderImageSource() {} 33 34 private: 35 void DrawIcon(gfx::Canvas* canvas, 36 const gfx::ImageSkia& icon, 37 const gfx::Size icon_size, 38 int x, int y) { 39 if (icon.isNull()) 40 return; 41 42 gfx::ImageSkia resized( 43 gfx::ImageSkiaOperations::CreateResizedImage( 44 icon, skia::ImageOperations::RESIZE_BEST, icon_size)); 45 canvas->DrawImageInt(resized, 0, 0, resized.width(), resized.height(), 46 x, y, resized.width(), resized.height(), true); 47 } 48 49 // gfx::CanvasImageSource overrides: 50 virtual void Draw(gfx::Canvas* canvas) OVERRIDE { 51 // Draw folder circle. 52 gfx::Point center = gfx::Point(size().width() / 2 , size().height() / 2); 53 SkPaint paint; 54 paint.setStyle(SkPaint::kFill_Style); 55 paint.setAntiAlias(true); 56 paint.setColor(kFolderBubbleColor); 57 canvas->DrawCircle(center, size().width() / 2, paint); 58 59 if (icons_.size() == 0) 60 return; 61 62 // Draw top items' icons. 63 const gfx::Size item_icon_size = 64 gfx::Size(kItemIconDimension, kItemIconDimension); 65 Rects top_icon_bounds = 66 AppListFolderItem::GetTopIconsBounds(gfx::Rect(size())); 67 68 for (size_t i= 0; i < kNumFolderTopItems && i < icons_.size(); ++i) { 69 DrawIcon(canvas, icons_[i], item_icon_size, 70 top_icon_bounds[i].x(), top_icon_bounds[i].y()); 71 } 72 } 73 74 Icons icons_; 75 gfx::Size size_; 76 77 DISALLOW_COPY_AND_ASSIGN(FolderImageSource); 78 }; 79 80 } // namespace 81 82 AppListFolderItem::AppListFolderItem(const std::string& id, 83 FolderType folder_type) 84 : AppListItem(id), 85 folder_type_(folder_type), 86 item_list_(new AppListItemList) { 87 item_list_->AddObserver(this); 88 } 89 90 AppListFolderItem::~AppListFolderItem() { 91 for (size_t i = 0; i < top_items_.size(); ++i) 92 top_items_[i]->RemoveObserver(this); 93 item_list_->RemoveObserver(this); 94 } 95 96 void AppListFolderItem::UpdateIcon() { 97 FolderImageSource::Icons top_icons; 98 for (size_t i = 0; i < top_items_.size(); ++i) 99 top_icons.push_back(top_items_[i]->icon()); 100 101 const gfx::Size icon_size = gfx::Size(kGridIconDimension, kGridIconDimension); 102 gfx::ImageSkia icon = gfx::ImageSkia( 103 new FolderImageSource(top_icons, icon_size), 104 icon_size); 105 SetIcon(icon, false); 106 } 107 108 const gfx::ImageSkia& AppListFolderItem::GetTopIcon(size_t item_index) { 109 DCHECK(item_index <= top_items_.size()); 110 return top_items_[item_index]->icon(); 111 } 112 113 gfx::Rect AppListFolderItem::GetTargetIconRectInFolderForItem( 114 AppListItem* item, 115 const gfx::Rect& folder_icon_bounds) { 116 for (size_t i = 0; i < top_items_.size(); ++i) { 117 if (item->id() == top_items_[i]->id()) { 118 Rects rects = AppListFolderItem::GetTopIconsBounds(folder_icon_bounds); 119 return rects[i]; 120 } 121 } 122 123 gfx::Rect target_rect(folder_icon_bounds); 124 target_rect.ClampToCenteredSize( 125 gfx::Size(kItemIconDimension, kItemIconDimension)); 126 return target_rect; 127 } 128 129 void AppListFolderItem::Activate(int event_flags) { 130 // Folder handling is implemented by the View, so do nothing. 131 } 132 133 // static 134 const char AppListFolderItem::kItemType[] = "FolderItem"; 135 136 // static 137 Rects AppListFolderItem::GetTopIconsBounds( 138 const gfx::Rect& folder_icon_bounds) { 139 const int delta_to_center = 1; 140 gfx::Point icon_center = folder_icon_bounds.CenterPoint(); 141 Rects top_icon_bounds; 142 143 // Get the top left icon bounds. 144 int left_x = icon_center.x() - kItemIconDimension - delta_to_center; 145 int top_y = icon_center.y() - kItemIconDimension - delta_to_center; 146 gfx::Rect top_left(left_x, top_y, kItemIconDimension, kItemIconDimension); 147 top_icon_bounds.push_back(top_left); 148 149 // Get the top right icon bounds. 150 int right_x = icon_center.x() + delta_to_center; 151 gfx::Rect top_right(right_x, top_y, kItemIconDimension, kItemIconDimension); 152 top_icon_bounds.push_back(top_right); 153 154 // Get the bottom left icon bounds. 155 int bottom_y = icon_center.y() + delta_to_center; 156 gfx::Rect bottom_left( 157 left_x, bottom_y, kItemIconDimension, kItemIconDimension); 158 top_icon_bounds.push_back(bottom_left); 159 160 // Get the bottom right icon bounds. 161 gfx::Rect bottom_right( 162 right_x, bottom_y, kItemIconDimension, kItemIconDimension); 163 top_icon_bounds.push_back(bottom_right); 164 165 return top_icon_bounds; 166 } 167 168 const char* AppListFolderItem::GetItemType() const { 169 return AppListFolderItem::kItemType; 170 } 171 172 ui::MenuModel* AppListFolderItem::GetContextMenuModel() { 173 // TODO(stevenjb/jennyz): Implement. 174 return NULL; 175 } 176 177 AppListItem* AppListFolderItem::FindChildItem(const std::string& id) { 178 return item_list_->FindItem(id); 179 } 180 181 size_t AppListFolderItem::ChildItemCount() const { 182 return item_list_->item_count(); 183 } 184 185 void AppListFolderItem::OnExtensionPreferenceChanged() { 186 for (size_t i = 0; i < item_list_->item_count(); ++i) 187 item_list_->item_at(i)->OnExtensionPreferenceChanged(); 188 } 189 190 bool AppListFolderItem::CompareForTest(const AppListItem* other) const { 191 if (!AppListItem::CompareForTest(other)) 192 return false; 193 const AppListFolderItem* other_folder = 194 static_cast<const AppListFolderItem*>(other); 195 if (other_folder->item_list()->item_count() != item_list_->item_count()) 196 return false; 197 for (size_t i = 0; i < item_list_->item_count(); ++i) { 198 if (!item_list()->item_at(i)->CompareForTest( 199 other_folder->item_list()->item_at(i))) 200 return false; 201 } 202 return true; 203 } 204 205 std::string AppListFolderItem::GenerateId() { 206 return base::GenerateGUID(); 207 } 208 209 void AppListFolderItem::ItemIconChanged() { 210 UpdateIcon(); 211 } 212 213 void AppListFolderItem::OnListItemAdded(size_t index, 214 AppListItem* item) { 215 if (index <= kNumFolderTopItems) 216 UpdateTopItems(); 217 } 218 219 void AppListFolderItem::OnListItemRemoved(size_t index, 220 AppListItem* item) { 221 if (index <= kNumFolderTopItems) 222 UpdateTopItems(); 223 } 224 225 void AppListFolderItem::OnListItemMoved(size_t from_index, 226 size_t to_index, 227 AppListItem* item) { 228 if (from_index <= kNumFolderTopItems || to_index <= kNumFolderTopItems) 229 UpdateTopItems(); 230 } 231 232 void AppListFolderItem::UpdateTopItems() { 233 for (size_t i = 0; i < top_items_.size(); ++i) 234 top_items_[i]->RemoveObserver(this); 235 top_items_.clear(); 236 237 for (size_t i = 0; 238 i < kNumFolderTopItems && i < item_list_->item_count(); ++i) { 239 AppListItem* item = item_list_->item_at(i); 240 item->AddObserver(this); 241 top_items_.push_back(item); 242 } 243 UpdateIcon(); 244 } 245 246 } // namespace app_list 247