Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / app_list / folder_image.cc
blob0c9b9588b947feeecf19ffce9ca59545edab2430
1 // Copyright 2014 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.
5 #include "ui/app_list/folder_image.h"
7 #include <vector>
9 #include "ui/app_list/app_list_constants.h"
10 #include "ui/app_list/app_list_item.h"
11 #include "ui/app_list/app_list_item_list.h"
12 #include "ui/base/l10n/l10n_util.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/gfx/geometry/point.h"
15 #include "ui/gfx/geometry/rect.h"
16 #include "ui/gfx/geometry/size.h"
17 #include "ui/gfx/image/canvas_image_source.h"
18 #include "ui/gfx/image/image_skia.h"
19 #include "ui/gfx/image/image_skia_operations.h"
20 #include "ui/strings/grit/ui_strings.h"
22 namespace app_list {
24 namespace {
26 const int kItemIconDimension = 16;
28 // Gets the size of a small app icon inside the folder icon.
29 gfx::Size ItemIconSize() {
30 return gfx::Size(kItemIconDimension, kItemIconDimension);
33 // Generates the folder icon with the top 4 child item icons laid in 2x2 tile.
34 class FolderImageSource : public gfx::CanvasImageSource {
35 public:
36 typedef std::vector<gfx::ImageSkia> Icons;
38 FolderImageSource(const Icons& icons, const gfx::Size& size);
39 ~FolderImageSource() override;
41 private:
42 void DrawIcon(gfx::Canvas* canvas,
43 const gfx::ImageSkia& icon,
44 const gfx::Size icon_size,
45 int x,
46 int y);
48 // gfx::CanvasImageSource overrides:
49 void Draw(gfx::Canvas* canvas) override;
51 Icons icons_;
52 gfx::Size size_;
54 DISALLOW_COPY_AND_ASSIGN(FolderImageSource);
57 FolderImageSource::FolderImageSource(const Icons& icons, const gfx::Size& size)
58 : gfx::CanvasImageSource(size, false), icons_(icons), size_(size) {
59 DCHECK(icons.size() <= kNumFolderTopItems);
62 FolderImageSource::~FolderImageSource() {
65 void FolderImageSource::DrawIcon(gfx::Canvas* canvas,
66 const gfx::ImageSkia& icon,
67 const gfx::Size icon_size,
68 int x,
69 int y) {
70 if (icon.isNull())
71 return;
73 gfx::ImageSkia resized(gfx::ImageSkiaOperations::CreateResizedImage(
74 icon, skia::ImageOperations::RESIZE_BEST, icon_size));
75 canvas->DrawImageInt(resized, 0, 0, resized.width(), resized.height(), x, y,
76 resized.width(), resized.height(), true);
79 void FolderImageSource::Draw(gfx::Canvas* canvas) {
80 SkPaint paint;
81 // Draw circle for folder bubble.
82 gfx::PointF bubble_center(size().width() / 2, size().height() / 2);
83 bubble_center.Offset(0, -kFolderBubbleOffsetY);
84 paint.setStyle(SkPaint::kFill_Style);
85 paint.setAntiAlias(true);
86 paint.setColor(kFolderBubbleColor);
87 canvas->sk_canvas()->drawCircle(bubble_center.x(), bubble_center.y(),
88 kFolderBubbleRadius, paint);
90 if (icons_.size() == 0)
91 return;
93 // Draw top items' icons.
94 const gfx::Size item_icon_size(ItemIconSize());
95 std::vector<gfx::Rect> top_icon_bounds =
96 FolderImage::GetTopIconsBounds(gfx::Rect(size()));
98 for (size_t i = 0; i < kNumFolderTopItems && i < icons_.size(); ++i) {
99 DrawIcon(canvas, icons_[i], item_icon_size, top_icon_bounds[i].x(),
100 top_icon_bounds[i].y());
104 } // namespace
106 FolderImage::FolderImage(AppListItemList* item_list) : item_list_(item_list) {
107 item_list_->AddObserver(this);
110 FolderImage::~FolderImage() {
111 for (auto* item : top_items_)
112 item->RemoveObserver(this);
113 item_list_->RemoveObserver(this);
116 void FolderImage::UpdateIcon() {
117 for (auto* item : top_items_)
118 item->RemoveObserver(this);
119 top_items_.clear();
121 for (size_t i = 0; i < kNumFolderTopItems && i < item_list_->item_count();
122 ++i) {
123 AppListItem* item = item_list_->item_at(i);
124 item->AddObserver(this);
125 top_items_.push_back(item);
127 RedrawIconAndNotify();
130 const gfx::ImageSkia& FolderImage::GetTopIcon(size_t item_index) const {
131 CHECK_LT(item_index, top_items_.size());
132 return top_items_[item_index]->icon();
135 // static
136 std::vector<gfx::Rect> FolderImage::GetTopIconsBounds(
137 const gfx::Rect& folder_icon_bounds) {
138 const int delta_to_center = 1;
139 gfx::Point icon_center = folder_icon_bounds.CenterPoint();
140 std::vector<gfx::Rect> top_icon_bounds;
142 // Get the top left icon bounds.
143 int left_x = icon_center.x() - kItemIconDimension - delta_to_center;
144 int top_y = icon_center.y() - kItemIconDimension - delta_to_center;
145 gfx::Rect top_left(left_x, top_y, kItemIconDimension, kItemIconDimension);
146 top_icon_bounds.push_back(top_left);
148 // Get the top right icon bounds.
149 int right_x = icon_center.x() + delta_to_center;
150 gfx::Rect top_right(right_x, top_y, kItemIconDimension, kItemIconDimension);
151 top_icon_bounds.push_back(top_right);
153 // Get the bottom left icon bounds.
154 int bottom_y = icon_center.y() + delta_to_center;
155 gfx::Rect bottom_left(left_x, bottom_y, kItemIconDimension,
156 kItemIconDimension);
157 top_icon_bounds.push_back(bottom_left);
159 // Get the bottom right icon bounds.
160 gfx::Rect bottom_right(right_x, bottom_y, kItemIconDimension,
161 kItemIconDimension);
162 top_icon_bounds.push_back(bottom_right);
164 return top_icon_bounds;
167 gfx::Rect FolderImage::GetTargetIconRectInFolderForItem(
168 AppListItem* item,
169 const gfx::Rect& folder_icon_bounds) const {
170 for (size_t i = 0; i < top_items_.size(); ++i) {
171 if (item->id() == top_items_[i]->id()) {
172 std::vector<gfx::Rect> rects = GetTopIconsBounds(folder_icon_bounds);
173 return rects[i];
177 gfx::Rect target_rect(folder_icon_bounds);
178 target_rect.ClampToCenteredSize(ItemIconSize());
179 return target_rect;
182 void FolderImage::AddObserver(FolderImageObserver* observer) {
183 observers_.AddObserver(observer);
186 void FolderImage::RemoveObserver(FolderImageObserver* observer) {
187 observers_.RemoveObserver(observer);
190 void FolderImage::ItemIconChanged() {
191 // Note: Must update the image only (cannot simply call UpdateIcon), because
192 // UpdateIcon removes and re-adds the FolderImage as an observer of the
193 // AppListItems, which causes the current iterator to call ItemIconChanged
194 // again, and goes into an infinite loop.
195 RedrawIconAndNotify();
198 void FolderImage::OnListItemAdded(size_t index, AppListItem* item) {
199 if (index < kNumFolderTopItems)
200 UpdateIcon();
203 void FolderImage::OnListItemRemoved(size_t index, AppListItem* item) {
204 if (index < kNumFolderTopItems)
205 UpdateIcon();
208 void FolderImage::OnListItemMoved(size_t from_index,
209 size_t to_index,
210 AppListItem* item) {
211 if (from_index < kNumFolderTopItems || to_index < kNumFolderTopItems)
212 UpdateIcon();
215 void FolderImage::RedrawIconAndNotify() {
216 FolderImageSource::Icons top_icons;
217 for (const auto* item : top_items_)
218 top_icons.push_back(item->icon());
220 const gfx::Size icon_size = gfx::Size(kGridIconDimension, kGridIconDimension);
221 icon_ =
222 gfx::ImageSkia(new FolderImageSource(top_icons, icon_size), icon_size);
224 FOR_EACH_OBSERVER(FolderImageObserver, observers_, OnFolderImageUpdated());
227 } // namespace app_list