apps_grid_view_item.mm revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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#import "ui/app_list/cocoa/apps_grid_view_item.h" 6 7#include "base/mac/foundation_util.h" 8#include "base/memory/scoped_nsobject.h" 9#include "base/strings/sys_string_conversions.h" 10#include "skia/ext/skia_utils_mac.h" 11#include "ui/app_list/app_list_constants.h" 12#include "ui/app_list/app_list_item_model.h" 13#include "ui/app_list/app_list_item_model_observer.h" 14#include "ui/base/resource/resource_bundle.h" 15#include "ui/gfx/image/image_skia_util_mac.h" 16#include "ui/gfx/font.h" 17 18namespace { 19 20// Padding from the top of the tile to the top of the app icon. 21const CGFloat kTileTopPadding = 10; 22 23} // namespace 24 25namespace app_list { 26 27class ItemModelObserverBridge : public app_list::AppListItemModelObserver { 28 public: 29 ItemModelObserverBridge(AppsGridViewItem* parent, AppListItemModel* model); 30 virtual ~ItemModelObserverBridge(); 31 32 AppListItemModel* model() { return model_; } 33 34 virtual void ItemIconChanged() OVERRIDE; 35 virtual void ItemTitleChanged() OVERRIDE; 36 virtual void ItemHighlightedChanged() OVERRIDE; 37 virtual void ItemIsInstallingChanged() OVERRIDE; 38 virtual void ItemPercentDownloadedChanged() OVERRIDE; 39 40 private: 41 AppsGridViewItem* parent_; // Weak. Owns us. 42 AppListItemModel* model_; // Weak. Owned by AppListModel::Apps. 43 44 DISALLOW_COPY_AND_ASSIGN(ItemModelObserverBridge); 45}; 46 47ItemModelObserverBridge::ItemModelObserverBridge(AppsGridViewItem* parent, 48 AppListItemModel* model) 49 : parent_(parent), 50 model_(model) { 51 model_->AddObserver(this); 52} 53 54ItemModelObserverBridge::~ItemModelObserverBridge() { 55 model_->RemoveObserver(this); 56} 57 58void ItemModelObserverBridge::ItemIconChanged() { 59 [[parent_ button] setImage:gfx::NSImageFromImageSkia(model_->icon())]; 60} 61 62void ItemModelObserverBridge::ItemTitleChanged() { 63 [[parent_ button] setTitle:base::SysUTF8ToNSString(model_->title())]; 64} 65 66void ItemModelObserverBridge::ItemHighlightedChanged() { 67 //TODO(tapted): Ensure the item view is visible (requires pagination). 68} 69 70void ItemModelObserverBridge::ItemIsInstallingChanged() { 71 //TODO(tapted): Hide the title while itemModel->is_installing(). 72} 73 74void ItemModelObserverBridge::ItemPercentDownloadedChanged() { 75 //TODO(tapted): Update install progress bar for this item. 76} 77 78} // namespace app_list 79 80// Container for an NSButton to allow proper alignment of the icon in the apps 81// grid, and to draw with a highlight when selected. 82@interface AppsGridItemBackgroundView : NSView { 83 @private 84 BOOL selected_; 85} 86 87- (NSButton*)button; 88 89- (void)setSelected:(BOOL)flag; 90 91@end 92 93@implementation AppsGridItemBackgroundView 94 95- (NSButton*)button { 96 return base::mac::ObjCCastStrict<NSButton>([[self subviews] objectAtIndex:0]); 97} 98 99- (void)setSelected:(BOOL)flag { 100 if (selected_ == flag) 101 return; 102 103 selected_ = flag; 104 [self setNeedsDisplay:YES]; 105} 106 107- (void)drawRect:(NSRect)dirtyRect { 108 if (!selected_) 109 return; 110 111 [gfx::SkColorToCalibratedNSColor(app_list::kHoverAndPushedColor) set]; 112 NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver); 113} 114 115- (void)mouseDown:(NSEvent*)theEvent { 116 [[[self button] cell] setHighlighted:YES]; 117} 118 119- (void)mouseDragged:(NSEvent*)theEvent { 120 NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] 121 fromView:nil]; 122 BOOL isInView = [self mouse:pointInView inRect:[self bounds]]; 123 [[[self button] cell] setHighlighted:isInView]; 124} 125 126- (void)mouseUp:(NSEvent*)theEvent { 127 NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] 128 fromView:nil]; 129 if (![self mouse:pointInView inRect:[self bounds]]) 130 return; 131 132 [[self button] performClick:self]; 133} 134 135@end 136 137@interface AppsGridViewItem () 138 139- (AppsGridItemBackgroundView*)itemBackgroundView; 140 141@end 142 143@implementation AppsGridViewItem 144 145- (id)initWithSize:(NSSize)tileSize { 146 if ((self = [super init])) { 147 scoped_nsobject<NSButton> prototypeButton( 148 [[NSButton alloc] initWithFrame:NSMakeRect( 149 0, 0, tileSize.width, tileSize.height - kTileTopPadding)]); 150 151 // This NSButton style always positions the icon at the very top of the 152 // button frame. AppsGridViewItem uses an enclosing view so that it is 153 // visually correct. 154 [prototypeButton setImagePosition:NSImageAbove]; 155 [prototypeButton setButtonType:NSMomentaryChangeButton]; 156 [prototypeButton setBordered:NO]; 157 158 [[prototypeButton cell] 159 setFont:ui::ResourceBundle::GetSharedInstance().GetFont( 160 app_list::kItemTextFontStyle).GetNativeFont()]; 161 162 scoped_nsobject<AppsGridItemBackgroundView> prototypeButtonBackground( 163 [[AppsGridItemBackgroundView alloc] initWithFrame:NSMakeRect( 164 0, 0, tileSize.width, tileSize.height)]); 165 [prototypeButtonBackground addSubview:prototypeButton]; 166 [self setView:prototypeButtonBackground]; 167 } 168 return self; 169} 170 171- (void)setModel:(app_list::AppListItemModel*)itemModel { 172 if (!itemModel) { 173 observerBridge_.reset(); 174 return; 175 } 176 177 NSButton* button = [self button]; 178 [button setTitle:base::SysUTF8ToNSString(itemModel->title())]; 179 [button setImage:gfx::NSImageFromImageSkia(itemModel->icon())]; 180 observerBridge_.reset(new app_list::ItemModelObserverBridge(self, itemModel)); 181 182 if (trackingArea_.get()) 183 [[self view] removeTrackingArea:trackingArea_.get()]; 184 185 trackingArea_.reset( 186 [[CrTrackingArea alloc] initWithRect:NSZeroRect 187 options:NSTrackingInVisibleRect | 188 NSTrackingMouseEnteredAndExited | 189 NSTrackingActiveInKeyWindow 190 owner:self 191 userInfo:nil]); 192 [[self view] addTrackingArea:trackingArea_.get()]; 193} 194 195- (app_list::AppListItemModel*)model { 196 return observerBridge_->model(); 197} 198 199- (NSButton*)button { 200 DCHECK_EQ(1u, [[[self view] subviews] count]); 201 return base::mac::ObjCCastStrict<NSButton>( 202 [[[self view] subviews] objectAtIndex:0]); 203} 204 205- (AppsGridItemBackgroundView*)itemBackgroundView { 206 return base::mac::ObjCCastStrict<AppsGridItemBackgroundView>([self view]); 207} 208 209- (void)mouseEntered:(NSEvent*)theEvent { 210 [self setSelected:YES]; 211} 212 213- (void)mouseExited:(NSEvent*)theEvent { 214 [self setSelected:NO]; 215} 216 217- (void)setSelected:(BOOL)flag { 218 [[self itemBackgroundView] setSelected:flag]; 219 [super setSelected:flag]; 220} 221 222@end 223