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
) {
80 // Draw circle for folder shadow.
81 gfx::PointF
shadow_center(size().width() / 2, size().height() / 2);
83 paint
.setStyle(SkPaint::kFill_Style
);
84 paint
.setAntiAlias(true);
85 paint
.setColor(kFolderShadowColor
);
86 canvas
->sk_canvas()->drawCircle(shadow_center
.x(), shadow_center
.y(),
87 kFolderShadowRadius
, paint
);
88 // Draw circle for folder bubble.
89 gfx::PointF
bubble_center(shadow_center
);
90 bubble_center
.Offset(0, -kFolderShadowOffsetY
);
91 paint
.setColor(kFolderBubbleColor
);
92 canvas
->sk_canvas()->drawCircle(bubble_center
.x(), bubble_center
.y(),
93 kFolderBubbleRadius
, paint
);
95 if (icons_
.size() == 0)
98 // Draw top items' icons.
99 const gfx::Size
item_icon_size(ItemIconSize());
100 std::vector
<gfx::Rect
> top_icon_bounds
=
101 FolderImage::GetTopIconsBounds(gfx::Rect(size()));
103 for (size_t i
= 0; i
< kNumFolderTopItems
&& i
< icons_
.size(); ++i
) {
104 DrawIcon(canvas
, icons_
[i
], item_icon_size
, top_icon_bounds
[i
].x(),
105 top_icon_bounds
[i
].y());
111 FolderImage::FolderImage(AppListItemList
* item_list
) : item_list_(item_list
) {
112 item_list_
->AddObserver(this);
115 FolderImage::~FolderImage() {
116 for (auto* item
: top_items_
)
117 item
->RemoveObserver(this);
118 item_list_
->RemoveObserver(this);
121 void FolderImage::UpdateIcon() {
122 for (auto* item
: top_items_
)
123 item
->RemoveObserver(this);
126 for (size_t i
= 0; i
< kNumFolderTopItems
&& i
< item_list_
->item_count();
128 AppListItem
* item
= item_list_
->item_at(i
);
129 item
->AddObserver(this);
130 top_items_
.push_back(item
);
132 RedrawIconAndNotify();
135 const gfx::ImageSkia
& FolderImage::GetTopIcon(size_t item_index
) const {
136 CHECK_LT(item_index
, top_items_
.size());
137 return top_items_
[item_index
]->icon();
141 std::vector
<gfx::Rect
> FolderImage::GetTopIconsBounds(
142 const gfx::Rect
& folder_icon_bounds
) {
143 const int delta_to_center
= 1;
144 gfx::Point icon_center
= folder_icon_bounds
.CenterPoint();
145 std::vector
<gfx::Rect
> top_icon_bounds
;
147 // Get the top left icon bounds.
148 int left_x
= icon_center
.x() - kItemIconDimension
- delta_to_center
;
149 int top_y
= icon_center
.y() - kItemIconDimension
- delta_to_center
;
150 gfx::Rect
top_left(left_x
, top_y
, kItemIconDimension
, kItemIconDimension
);
151 top_icon_bounds
.push_back(top_left
);
153 // Get the top right icon bounds.
154 int right_x
= icon_center
.x() + delta_to_center
;
155 gfx::Rect
top_right(right_x
, top_y
, kItemIconDimension
, kItemIconDimension
);
156 top_icon_bounds
.push_back(top_right
);
158 // Get the bottom left icon bounds.
159 int bottom_y
= icon_center
.y() + delta_to_center
;
160 gfx::Rect
bottom_left(left_x
, bottom_y
, kItemIconDimension
,
162 top_icon_bounds
.push_back(bottom_left
);
164 // Get the bottom right icon bounds.
165 gfx::Rect
bottom_right(right_x
, bottom_y
, kItemIconDimension
,
167 top_icon_bounds
.push_back(bottom_right
);
169 return top_icon_bounds
;
172 gfx::Rect
FolderImage::GetTargetIconRectInFolderForItem(
174 const gfx::Rect
& folder_icon_bounds
) const {
175 for (size_t i
= 0; i
< top_items_
.size(); ++i
) {
176 if (item
->id() == top_items_
[i
]->id()) {
177 std::vector
<gfx::Rect
> rects
= GetTopIconsBounds(folder_icon_bounds
);
182 gfx::Rect
target_rect(folder_icon_bounds
);
183 target_rect
.ClampToCenteredSize(ItemIconSize());
187 void FolderImage::AddObserver(FolderImageObserver
* observer
) {
188 observers_
.AddObserver(observer
);
191 void FolderImage::RemoveObserver(FolderImageObserver
* observer
) {
192 observers_
.RemoveObserver(observer
);
195 void FolderImage::ItemIconChanged() {
196 // Note: Must update the image only (cannot simply call UpdateIcon), because
197 // UpdateIcon removes and re-adds the FolderImage as an observer of the
198 // AppListItems, which causes the current iterator to call ItemIconChanged
199 // again, and goes into an infinite loop.
200 RedrawIconAndNotify();
203 void FolderImage::OnListItemAdded(size_t index
, AppListItem
* item
) {
204 if (index
< kNumFolderTopItems
)
208 void FolderImage::OnListItemRemoved(size_t index
, AppListItem
* item
) {
209 if (index
< kNumFolderTopItems
)
213 void FolderImage::OnListItemMoved(size_t from_index
,
216 if (from_index
< kNumFolderTopItems
|| to_index
< kNumFolderTopItems
)
220 void FolderImage::RedrawIconAndNotify() {
221 FolderImageSource::Icons top_icons
;
222 for (const auto* item
: top_items_
)
223 top_icons
.push_back(item
->icon());
225 const gfx::Size icon_size
= gfx::Size(kGridIconDimension
, kGridIconDimension
);
227 gfx::ImageSkia(new FolderImageSource(top_icons
, icon_size
), icon_size
);
229 FOR_EACH_OBSERVER(FolderImageObserver
, observers_
, OnFolderImageUpdated());
232 } // namespace app_list