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"
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"
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
{
36 typedef std::vector
<gfx::ImageSkia
> Icons
;
38 FolderImageSource(const Icons
& icons
, const gfx::Size
& size
);
39 ~FolderImageSource() override
;
42 void DrawIcon(gfx::Canvas
* canvas
,
43 const gfx::ImageSkia
& icon
,
44 const gfx::Size icon_size
,
48 // gfx::CanvasImageSource overrides:
49 void Draw(gfx::Canvas
* canvas
) override
;
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
,
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
) {
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)
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());
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);
121 for (size_t i
= 0; i
< kNumFolderTopItems
&& i
< item_list_
->item_count();
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();
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
,
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
,
162 top_icon_bounds
.push_back(bottom_right
);
164 return top_icon_bounds
;
167 gfx::Rect
FolderImage::GetTargetIconRectInFolderForItem(
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
);
177 gfx::Rect
target_rect(folder_icon_bounds
);
178 target_rect
.ClampToCenteredSize(ItemIconSize());
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
)
203 void FolderImage::OnListItemRemoved(size_t index
, AppListItem
* item
) {
204 if (index
< kNumFolderTopItems
)
208 void FolderImage::OnListItemMoved(size_t from_index
,
211 if (from_index
< kNumFolderTopItems
|| to_index
< kNumFolderTopItems
)
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
);
222 gfx::ImageSkia(new FolderImageSource(top_icons
, icon_size
), icon_size
);
224 FOR_EACH_OBSERVER(FolderImageObserver
, observers_
, OnFolderImageUpdated());
227 } // namespace app_list