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
14namespace app_list {
15
16namespace {
17
18const int kItemIconDimension = 16;
19
20// Generates the folder icon with the top 4 child item icons laid in 2x2 tile.
21class 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
82AppListFolderItem::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
90AppListFolderItem::~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
96void 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 =
102      gfx::Size(kPreferredIconDimension, kPreferredIconDimension);
103  gfx::ImageSkia icon = gfx::ImageSkia(
104      new FolderImageSource(top_icons, icon_size),
105      icon_size);
106  SetIcon(icon, false);
107}
108
109const gfx::ImageSkia& AppListFolderItem::GetTopIcon(size_t item_index) {
110  DCHECK(item_index <= top_items_.size());
111  return top_items_[item_index]->icon();
112}
113
114gfx::Rect AppListFolderItem::GetTargetIconRectInFolderForItem(
115    AppListItem* item,
116    const gfx::Rect& folder_icon_bounds) {
117  for (size_t i = 0; i < top_items_.size(); ++i) {
118    if (item->id() == top_items_[i]->id()) {
119      Rects rects = AppListFolderItem::GetTopIconsBounds(folder_icon_bounds);
120      return rects[i];
121    }
122  }
123
124  gfx::Rect target_rect(folder_icon_bounds);
125  target_rect.ClampToCenteredSize(
126      gfx::Size(kItemIconDimension, kItemIconDimension));
127  return target_rect;
128}
129
130void AppListFolderItem::Activate(int event_flags) {
131  // Folder handling is implemented by the View, so do nothing.
132}
133
134// static
135const char AppListFolderItem::kItemType[] = "FolderItem";
136
137// static
138Rects AppListFolderItem::GetTopIconsBounds(
139    const gfx::Rect& folder_icon_bounds) {
140  const int delta_to_center = 1;
141  gfx::Point icon_center = folder_icon_bounds.CenterPoint();
142  Rects top_icon_bounds;
143
144  // Get the top left icon bounds.
145  int left_x = icon_center.x() - kItemIconDimension - delta_to_center;
146  int top_y = icon_center.y() - kItemIconDimension - delta_to_center;
147  gfx::Rect top_left(left_x, top_y, kItemIconDimension, kItemIconDimension);
148  top_icon_bounds.push_back(top_left);
149
150  // Get the top right icon bounds.
151  int right_x = icon_center.x() + delta_to_center;
152  gfx::Rect top_right(right_x, top_y, kItemIconDimension, kItemIconDimension);
153  top_icon_bounds.push_back(top_right);
154
155  // Get the bottom left icon bounds.
156  int bottom_y = icon_center.y() + delta_to_center;
157  gfx::Rect bottom_left(
158      left_x, bottom_y, kItemIconDimension, kItemIconDimension);
159  top_icon_bounds.push_back(bottom_left);
160
161  // Get the bottom right icon bounds.
162  gfx::Rect bottom_right(
163      right_x, bottom_y, kItemIconDimension, kItemIconDimension);
164  top_icon_bounds.push_back(bottom_right);
165
166  return top_icon_bounds;
167}
168
169const char* AppListFolderItem::GetItemType() const {
170  return AppListFolderItem::kItemType;
171}
172
173ui::MenuModel* AppListFolderItem::GetContextMenuModel() {
174  // TODO(stevenjb/jennyz): Implement.
175  return NULL;
176}
177
178AppListItem* AppListFolderItem::FindChildItem(const std::string& id) {
179  return item_list_->FindItem(id);
180}
181
182size_t AppListFolderItem::ChildItemCount() const {
183  return item_list_->item_count();
184}
185
186void AppListFolderItem::OnExtensionPreferenceChanged() {
187  for (size_t i = 0; i < item_list_->item_count(); ++i)
188    item_list_->item_at(i)->OnExtensionPreferenceChanged();
189}
190
191bool AppListFolderItem::CompareForTest(const AppListItem* other) const {
192  if (!AppListItem::CompareForTest(other))
193    return false;
194  const AppListFolderItem* other_folder =
195      static_cast<const AppListFolderItem*>(other);
196  if (other_folder->item_list()->item_count() != item_list_->item_count())
197    return false;
198  for (size_t i = 0; i < item_list_->item_count(); ++i) {
199    if (!item_list()->item_at(i)->CompareForTest(
200            other_folder->item_list()->item_at(i)))
201      return false;
202  }
203  return true;
204}
205
206std::string AppListFolderItem::GenerateId() {
207  return base::GenerateGUID();
208}
209
210void AppListFolderItem::ItemIconChanged() {
211  UpdateIcon();
212}
213
214void AppListFolderItem::ItemNameChanged() {
215}
216
217void AppListFolderItem::ItemHighlightedChanged() {
218}
219
220void AppListFolderItem::ItemIsInstallingChanged() {
221}
222
223void AppListFolderItem::ItemPercentDownloadedChanged() {
224}
225
226void AppListFolderItem::OnListItemAdded(size_t index,
227                                        AppListItem* item) {
228  if (index <= kNumFolderTopItems)
229    UpdateTopItems();
230}
231
232void AppListFolderItem::OnListItemRemoved(size_t index,
233                                          AppListItem* item) {
234  if (index <= kNumFolderTopItems)
235    UpdateTopItems();
236}
237
238void AppListFolderItem::OnListItemMoved(size_t from_index,
239                                        size_t to_index,
240                                        AppListItem* item) {
241  if (from_index <= kNumFolderTopItems || to_index <= kNumFolderTopItems)
242    UpdateTopItems();
243}
244
245void AppListFolderItem::UpdateTopItems() {
246  for (size_t i = 0; i < top_items_.size(); ++i)
247    top_items_[i]->RemoveObserver(this);
248  top_items_.clear();
249
250  for (size_t i = 0;
251       i < kNumFolderTopItems && i < item_list_->item_count(); ++i) {
252    AppListItem* item = item_list_->item_at(i);
253    item->AddObserver(this);
254    top_items_.push_back(item);
255  }
256  UpdateIcon();
257}
258
259}  // namespace app_list
260