Home | History | Annotate | Download | only in app_list
      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