diff options
author | tapted@chromium.org <tapted@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-15 11:50:06 +0000 |
---|---|---|
committer | tapted@chromium.org <tapted@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-15 11:50:06 +0000 |
commit | aa004442c2838a5bf7eb6f5f7b0433f8157c5735 (patch) | |
tree | 074f9aa23f3957fe9b22b2112bc15c5f1a22a9b9 /ui | |
parent | fae7b5685539ff8f0f22a16a4b5ac5bbbf61c892 (diff) | |
download | chromium_src-aa004442c2838a5bf7eb6f5f7b0433f8157c5735.zip chromium_src-aa004442c2838a5bf7eb6f5f7b0433f8157c5735.tar.gz chromium_src-aa004442c2838a5bf7eb6f5f7b0433f8157c5735.tar.bz2 |
UI updates for items in the OSX app list: mouseover, font, padding.
This change adds a CrTrackingArea to items in the apps grid for a
mouseover effect. There are also minor UI tweaks: use a correct padding
for the icon in the apps grid, and use the same font as used by the
CrOS and Windows app launchers.
BUG=138633
TEST=Added: app_list_unittests --gtest_filter=AppsGridControllerTest.MouseoverSelects
Review URL: https://chromiumcodereview.appspot.com/12764024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188346 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/app_list/app_list_constants.cc | 5 | ||||
-rw-r--r-- | ui/app_list/app_list_constants.h | 4 | ||||
-rw-r--r-- | ui/app_list/cocoa/apps_grid_controller.h | 2 | ||||
-rw-r--r-- | ui/app_list/cocoa/apps_grid_controller.mm | 35 | ||||
-rw-r--r-- | ui/app_list/cocoa/apps_grid_controller_unittest.mm | 41 | ||||
-rw-r--r-- | ui/app_list/cocoa/apps_grid_view_item.h | 6 | ||||
-rw-r--r-- | ui/app_list/cocoa/apps_grid_view_item.mm | 134 | ||||
-rw-r--r-- | ui/app_list/views/app_list_item_view.cc | 4 |
8 files changed, 190 insertions, 41 deletions
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc index 4c31d2f..115f600 100644 --- a/ui/app_list/app_list_constants.cc +++ b/ui/app_list/app_list_constants.cc @@ -7,6 +7,7 @@ namespace app_list { const SkColor kContentsBackgroundColor = SkColorSetRGB(0xF5, 0xF5, 0xF5); +const SkColor kHoverAndPushedColor = SkColorSetARGB(0x19, 0, 0, 0); // Duration in milliseconds for page transition. const int kPageTransitionDurationInMs = 180; @@ -18,4 +19,8 @@ const int kOverscrollPageTransitionDurationMs = 50; const int kPreferredCols = 4; const int kPreferredRows = 4; +// Font style for app item labels. +const ui::ResourceBundle::FontStyle kItemTextFontStyle = + ui::ResourceBundle::SmallBoldFont; + } // namespace app_list diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h index cc68664..7579d99 100644 --- a/ui/app_list/app_list_constants.h +++ b/ui/app_list/app_list_constants.h @@ -7,10 +7,12 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/app_list/app_list_export.h" +#include "ui/base/resource/resource_bundle.h" namespace app_list { APP_LIST_EXPORT extern const SkColor kContentsBackgroundColor; +APP_LIST_EXPORT extern const SkColor kHoverAndPushedColor; APP_LIST_EXPORT extern const int kPageTransitionDurationInMs; APP_LIST_EXPORT extern const int kOverscrollPageTransitionDurationMs; @@ -18,6 +20,8 @@ APP_LIST_EXPORT extern const int kOverscrollPageTransitionDurationMs; APP_LIST_EXPORT extern const int kPreferredCols; APP_LIST_EXPORT extern const int kPreferredRows; +APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle; + } // namespace app_list #endif // UI_APP_LIST_APP_LIST_CONSTANTS_H_ diff --git a/ui/app_list/cocoa/apps_grid_controller.h b/ui/app_list/cocoa/apps_grid_controller.h index 3a5f052..8f01fe4 100644 --- a/ui/app_list/cocoa/apps_grid_controller.h +++ b/ui/app_list/cocoa/apps_grid_controller.h @@ -38,7 +38,7 @@ class AppsGridDelegateBridge; - (NSCollectionView*)collectionViewAtPageIndex:(size_t)pageIndex; -- (NSButton*)viewAtItemIndex:(size_t)itemIndex; +- (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex; - (app_list::AppListModel*)model; diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm index 55628ba..7eb3f5e 100644 --- a/ui/app_list/cocoa/apps_grid_controller.mm +++ b/ui/app_list/cocoa/apps_grid_controller.mm @@ -40,9 +40,6 @@ const CGFloat kViewHeight = kFixedRows * kPreferredTileHeight; // Index of the page with the most content currently visible. - (size_t)nearestPageIndex; -// Make an item prototype containing an app button for an NSCollectionView page. -- (NSCollectionViewItem*)makeItemPrototype; - // Make an empty NSCollectionView positioned horizontally for |pageIndex|. - (NSCollectionView*)makePageForIndex:(size_t)pageIndex; @@ -55,8 +52,6 @@ const CGFloat kViewHeight = kFixedRows * kPreferredTileHeight; - (AppsGridViewItem*)itemAtPageIndex:(size_t)pageIndex indexInPage:(size_t)indexInPage; -- (AppsGridViewItem*)itemAtIndex:(size_t)itemIndex; - // Update the model in full, and rebuild subviews. - (void)modelUpdated; @@ -128,11 +123,6 @@ class AppsGridDelegateBridge : public ui::ListModelObserver { return [pages_ objectAtIndex:pageIndex]; } -- (NSButton*)viewAtItemIndex:(size_t)itemIndex { - return base::mac::ObjCCastStrict<NSButton>( - [[self itemAtIndex:itemIndex] view]); -} - - (app_list::AppListModel*)model { return model_.get(); } @@ -209,21 +199,6 @@ class AppsGridDelegateBridge : public ui::ListModelObserver { } } -- (NSCollectionViewItem*)makeItemPrototype { - scoped_nsobject<NSButton> prototypeButton( - [[NSButton alloc] initWithFrame:NSZeroRect]); - [prototypeButton setImagePosition:NSImageAbove]; - [prototypeButton setButtonType:NSMomentaryPushInButton]; - [prototypeButton setTarget:self]; - [prototypeButton setAction:@selector(onItemClicked:)]; - [prototypeButton setBordered:NO]; - - scoped_nsobject<AppsGridViewItem> itemPrototype( - [[AppsGridViewItem alloc] init]); - [itemPrototype setView:prototypeButton]; - return itemPrototype.autorelease(); -} - - (NSCollectionView*)makePageForIndex:(size_t)pageIndex { NSRect pageFrame = NSMakeRect( kLeftRightPadding + kViewWidth * pageIndex, 0, @@ -236,7 +211,13 @@ class AppsGridDelegateBridge : public ui::ListModelObserver { [itemCollectionView setMaxItemSize:itemSize]; [itemCollectionView setSelectable:YES]; [itemCollectionView setFocusRingType:NSFocusRingTypeNone]; - [itemCollectionView setItemPrototype:[self makeItemPrototype]]; + + scoped_nsobject<AppsGridViewItem> itemPrototype( + [[AppsGridViewItem alloc] initWithSize:itemSize]); + [[itemPrototype button] setTarget:self]; + [[itemPrototype button] setAction:@selector(onItemClicked:)]; + + [itemCollectionView setItemPrototype:itemPrototype]; return itemCollectionView.autorelease(); } @@ -259,7 +240,7 @@ class AppsGridDelegateBridge : public ui::ListModelObserver { - (void)onItemClicked:(id)sender { for (size_t i = 0; i < [items_ count]; ++i) { AppsGridViewItem* item = [self itemAtIndex:i]; - if ([[item view] isEqual:sender]) + if ([[item button] isEqual:sender]) delegate_->ActivateAppListItem([item model], 0); } } diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm index 76d1345..744152e 100644 --- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm +++ b/ui/app_list/cocoa/apps_grid_controller_unittest.mm @@ -8,6 +8,7 @@ #import "testing/gtest_mac.h" #include "ui/app_list/app_list_item_model.h" #import "ui/app_list/cocoa/apps_grid_controller.h" +#import "ui/app_list/cocoa/apps_grid_view_item.h" #include "ui/app_list/test/app_list_test_model.h" #include "ui/app_list/test/app_list_test_view_delegate.h" #import "ui/base/test/cocoa_test_event_utils.h" @@ -58,6 +59,16 @@ class AppsGridControllerTest : public ui::CocoaTest { [test_window() keyDown:cocoa_test_event_utils::KeyEventWithCharacter(c)]; } + void SimulateMouseEnterItemAt(size_t index) { + [[apps_grid_controller_ itemAtIndex:index] mouseEntered: + cocoa_test_event_utils::EnterExitEventWithType(NSMouseEntered)]; + } + + void SimulateMouseExitItemAt(size_t index) { + [[apps_grid_controller_ itemAtIndex:index] mouseExited: + cocoa_test_event_utils::EnterExitEventWithType(NSMouseExited)]; + } + // Do a bulk replacement of the items in the grid. void ReplaceTestModel(int item_count) { scoped_ptr<app_list::test::AppListTestModel> new_model( @@ -78,7 +89,7 @@ class AppsGridControllerTest : public ui::CocoaTest { } NSButton* GetItemViewAt(size_t index) { - return [apps_grid_controller_ viewAtItemIndex:index]; + return [[apps_grid_controller_ itemAtIndex:index] button]; } NSCollectionView* GetPageAt(size_t index) { @@ -90,9 +101,9 @@ class AppsGridControllerTest : public ui::CocoaTest { NSView* GetSelectedView() { NSIndexSet* selection = [GetPageAt(0) selectionIndexes]; if ([selection count]) { - NSCollectionViewItem* item = - [GetPageAt(0) itemAtIndex:[selection firstIndex]]; - return [item view]; + AppsGridViewItem* item = base::mac::ObjCCastStrict<AppsGridViewItem>( + [GetPageAt(0) itemAtIndex:[selection firstIndex]]); + return [item button]; } return nil; @@ -281,3 +292,25 @@ TEST_F(AppsGridControllerTest, ModelUpdates) { EXPECT_EQ(kTestImageSize, icon_size.width); EXPECT_EQ(kTestImageSize, icon_size.height); } + +// Test mouseover selection. +TEST_F(AppsGridControllerTest, MouseoverSelects) { + model()->PopulateApps(2); + EXPECT_EQ(nil, GetSelectedView()); + + // Test entering and exiting the first item. + SimulateMouseEnterItemAt(0); + EXPECT_EQ(GetItemViewAt(0), GetSelectedView()); + SimulateMouseExitItemAt(0); + EXPECT_EQ(nil, GetSelectedView()); + + // AppKit doesn't guarantee the order, so test moving between items. + SimulateMouseEnterItemAt(0); + EXPECT_EQ(GetItemViewAt(0), GetSelectedView()); + SimulateMouseEnterItemAt(1); + EXPECT_EQ(GetItemViewAt(1), GetSelectedView()); + SimulateMouseExitItemAt(0); + EXPECT_EQ(GetItemViewAt(1), GetSelectedView()); + SimulateMouseExitItemAt(1); + EXPECT_EQ(nil, GetSelectedView()); +} diff --git a/ui/app_list/cocoa/apps_grid_view_item.h b/ui/app_list/cocoa/apps_grid_view_item.h index f16d96e..976ca51 100644 --- a/ui/app_list/cocoa/apps_grid_view_item.h +++ b/ui/app_list/cocoa/apps_grid_view_item.h @@ -8,6 +8,7 @@ #import <Cocoa/Cocoa.h> #include "base/memory/scoped_ptr.h" +#import "ui/base/cocoa/tracking_area.h" namespace app_list { class AppListItemModel; @@ -19,8 +20,13 @@ class ItemModelObserverBridge; @interface AppsGridViewItem : NSCollectionViewItem { @private scoped_ptr<app_list::ItemModelObserverBridge> observerBridge_; + + // Used to highlight the background on hover. + ui::ScopedCrTrackingArea trackingArea_; } +- (id)initWithSize:(NSSize)tileSize; + - (void)setModel:(app_list::AppListItemModel*)itemModel; - (app_list::AppListItemModel*)model; diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm index d7c251a..6f7e465 100644 --- a/ui/app_list/cocoa/apps_grid_view_item.mm +++ b/ui/app_list/cocoa/apps_grid_view_item.mm @@ -5,12 +5,22 @@ #import "ui/app_list/cocoa/apps_grid_view_item.h" #include "base/mac/foundation_util.h" +#include "base/memory/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #include "skia/ext/skia_utils_mac.h" #include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_item_model.h" #include "ui/app_list/app_list_item_model_observer.h" +#include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image_skia_util_mac.h" +#include "ui/gfx/font.h" + +namespace { + +// Padding from the top of the tile to the top of the app icon. +const CGFloat kTileTopPadding = 10; + +} // namespace namespace app_list { @@ -67,8 +77,97 @@ void ItemModelObserverBridge::ItemPercentDownloadedChanged() { } // namespace app_list +// Container for an NSButton to allow proper alignment of the icon in the apps +// grid, and to draw with a highlight when selected. +@interface AppsGridItemBackgroundView : NSView { + @private + BOOL selected_; +} + +- (NSButton*)button; + +- (void)setSelected:(BOOL)flag; + +@end + +@implementation AppsGridItemBackgroundView + +- (NSButton*)button { + return base::mac::ObjCCastStrict<NSButton>([[self subviews] objectAtIndex:0]); +} + +- (void)setSelected:(BOOL)flag { + if (selected_ == flag) + return; + + selected_ = flag; + [self setNeedsDisplay:YES]; +} + +- (void)drawRect:(NSRect)dirtyRect { + if (!selected_) + return; + + [gfx::SkColorToCalibratedNSColor(app_list::kHoverAndPushedColor) set]; + NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver); +} + +- (void)mouseDown:(NSEvent*)theEvent { + [[[self button] cell] setHighlighted:YES]; +} + +- (void)mouseDragged:(NSEvent*)theEvent { + NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] + fromView:nil]; + BOOL isInView = [self mouse:pointInView inRect:[self bounds]]; + [[[self button] cell] setHighlighted:isInView]; +} + +- (void)mouseUp:(NSEvent*)theEvent { + NSPoint pointInView = [self convertPoint:[theEvent locationInWindow] + fromView:nil]; + if (![self mouse:pointInView inRect:[self bounds]]) + return; + + [[self button] performClick:self]; +} + +@end + +@interface AppsGridViewItem () + +- (AppsGridItemBackgroundView*)itemBackgroundView; + +@end + @implementation AppsGridViewItem +- (id)initWithSize:(NSSize)tileSize { + if ((self = [super init])) { + scoped_nsobject<NSButton> prototypeButton( + [[NSButton alloc] initWithFrame:NSMakeRect( + 0, 0, tileSize.width, tileSize.height - kTileTopPadding)]); + + // This NSButton style always positions the icon at the very top of the + // button frame. AppsGridViewItem uses an enclosing view so that it is + // visually correct. + [prototypeButton setImagePosition:NSImageAbove]; + [prototypeButton setButtonType:NSMomentaryChangeButton]; + [prototypeButton setBordered:NO]; + + [[prototypeButton cell] + setFont:ui::ResourceBundle::GetSharedInstance().GetFont( + app_list::kItemTextFontStyle).GetNativeFont()]; + + scoped_nsobject<AppsGridItemBackgroundView> prototypeButtonBackground( + [[AppsGridItemBackgroundView alloc] initWithFrame:NSMakeRect( + 0, 0, tileSize.width, tileSize.height)]); + [prototypeButtonBackground addSubview:prototypeButton]; + [self setView:prototypeButtonBackground]; + } + return self; +} + - (void)setModel:(app_list::AppListItemModel*)itemModel { if (!itemModel) { observerBridge_.reset(); @@ -79,6 +178,18 @@ void ItemModelObserverBridge::ItemPercentDownloadedChanged() { [button setTitle:base::SysUTF8ToNSString(itemModel->title())]; [button setImage:gfx::NSImageFromImageSkia(itemModel->icon())]; observerBridge_.reset(new app_list::ItemModelObserverBridge(self, itemModel)); + + if (trackingArea_.get()) + [[self view] removeTrackingArea:trackingArea_.get()]; + + trackingArea_.reset( + [[CrTrackingArea alloc] initWithRect:NSZeroRect + options:NSTrackingInVisibleRect | + NSTrackingMouseEnteredAndExited | + NSTrackingActiveInKeyWindow + owner:self + userInfo:nil]); + [[self view] addTrackingArea:trackingArea_.get()]; } - (app_list::AppListItemModel*)model { @@ -86,16 +197,25 @@ void ItemModelObserverBridge::ItemPercentDownloadedChanged() { } - (NSButton*)button { - return base::mac::ObjCCastStrict<NSButton>([self view]); + DCHECK_EQ(1u, [[[self view] subviews] count]); + return base::mac::ObjCCastStrict<NSButton>( + [[[self view] subviews] objectAtIndex:0]); +} + +- (AppsGridItemBackgroundView*)itemBackgroundView { + return base::mac::ObjCCastStrict<AppsGridItemBackgroundView>([self view]); +} + +- (void)mouseEntered:(NSEvent*)theEvent { + [self setSelected:YES]; +} + +- (void)mouseExited:(NSEvent*)theEvent { + [self setSelected:NO]; } - (void)setSelected:(BOOL)flag { - if (flag) { - [[[self button] cell] setBackgroundColor:[NSColor lightGrayColor]]; - } else { - [[[self button] cell] setBackgroundColor:gfx::SkColorToCalibratedNSColor( - app_list::kContentsBackgroundColor)]; - } + [[self itemBackgroundView] setSelected:flag]; [super setSelected:flag]; } diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc index 640aa57..2061211 100644 --- a/ui/app_list/views/app_list_item_view.cc +++ b/ui/app_list/views/app_list_item_view.cc @@ -8,6 +8,7 @@ #include "base/utf_string_conversions.h" #include "grit/ui_resources.h" +#include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_item_model.h" #include "ui/app_list/views/apps_grid_view.h" #include "ui/app_list/views/cached_label.h" @@ -40,7 +41,6 @@ const int kProgressBarHeight = 4; const SkColor kTitleColor = SkColorSetRGB(0x5A, 0x5A, 0x5A); const SkColor kTitleHoverColor = SkColorSetRGB(0x3C, 0x3C, 0x3C); -const SkColor kHoverAndPushedColor = SkColorSetARGB(0x19, 0, 0, 0); const SkColor kSelectedColor = SkColorSetARGB(0x0D, 0, 0, 0); const SkColor kHighlightedColor = kHoverAndPushedColor; const SkColor kDownloadProgressBackgroundColor = @@ -75,7 +75,7 @@ AppListItemView::AppListItemView(AppsGridView* apps_grid_view, title_->SetBackgroundColor(0); title_->SetAutoColorReadabilityEnabled(false); title_->SetEnabledColor(kTitleColor); - title_->SetFont(rb.GetFont(ui::ResourceBundle::SmallBoldFont)); + title_->SetFont(rb.GetFont(kItemTextFontStyle)); title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); title_->SetVisible(!model_->is_installing()); title_->Invalidate(); |