Chromium Code Reviews| Index: chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm |
| diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm |
| index 7198d96d9d1d6146d5026bdfd79803edcfec0e48..aa6c69f251c997f97e8af8c28f4ebbba7e77c019 100644 |
| --- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm |
| +++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm |
| @@ -84,6 +84,7 @@ const CGFloat kProfileButtonHeight = 30; |
| const int kBezelThickness = 3; // Width of the bezel on an NSButton. |
| const int kImageTitleSpacing = 10; |
| const int kBlueButtonHeight = 30; |
| +const CGFloat kFocusRingLineWidth = 2; |
| // Fixed size for embedded sign in pages as defined in Gaia. |
| const CGFloat kFixedGaiaViewWidth = 360; |
| @@ -409,22 +410,34 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| return buttonSize; |
| } |
| -@end |
| +- (NSFocusRingType)focusRingType { |
| + // This is taken care of by the custom drawing code. |
| + return NSFocusRingTypeNone; |
| +} |
| -// A custom button that has a transparent backround. |
| -@interface TransparentBackgroundButton : NSButton |
| -@end |
| +- (void)drawWithFrame:(NSRect)frame inView:(NSView *)controlView { |
| + [super drawInteriorWithFrame:frame inView:controlView]; |
| -@implementation TransparentBackgroundButton |
| -- (id)initWithFrame:(NSRect)frameRect { |
| - if ((self = [super initWithFrame:frameRect])) { |
| - [self setBordered:NO]; |
| - [self setFont:[NSFont labelFontOfSize:kTextFontSize]]; |
| - [self setButtonType:NSMomentaryChangeButton]; |
| + // Focus ring. |
| + if ([self showsFirstResponder]) { |
| + NSRect focusRingRect = |
| + NSInsetRect(frame, kFocusRingLineWidth, kFocusRingLineWidth); |
| + // TODO(noms): When we are targetting 10.7, we should change this to use |
| + // -drawFocusRingMaskWithFrame instead. |
| + [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:1] set]; |
| + NSBezierPath* path = [NSBezierPath bezierPathWithRect:focusRingRect]; |
| + [path setLineWidth:kFocusRingLineWidth]; |
| + [path stroke]; |
| } |
| - return self; |
| } |
| +@end |
| + |
| +// A custom image view that has a transparent backround. |
| +@interface TransparentBackgroundImageView : NSImageView |
| +@end |
| + |
| +@implementation TransparentBackgroundImageView |
| - (void)drawRect:(NSRect)dirtyRect { |
| NSColor* backgroundColor = [NSColor colorWithCalibratedWhite:1 alpha:0.6f]; |
| [backgroundColor setFill]; |
| @@ -433,13 +446,31 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| } |
| @end |
| +@interface CustomCircleImageCell : NSButtonCell |
| +@end |
| + |
| +@implementation CustomCircleImageCell |
| +- (void)drawWithFrame:(NSRect)frame inView:(NSView *)controlView { |
| + // Display everything as a circle that spans the entire control. |
| + NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:frame]; |
| + [path addClip]; |
| + |
| + [super drawImage:[self image] withFrame:frame inView:controlView]; |
| + |
| + // Focus ring. |
| + if ([self showsFirstResponder]) { |
| + [[[NSColor keyboardFocusIndicatorColor] colorWithAlphaComponent:1] set]; |
| + [path setLineWidth:kFocusRingLineWidth]; |
| + [path stroke]; |
| + } |
| +} |
| +@end |
| + |
| // A custom image control that shows a "Change" button when moused over. |
| -@interface EditableProfilePhoto : NSImageView { |
| +@interface EditableProfilePhoto : HoverImageButton { |
| @private |
| AvatarMenu* avatarMenu_; // Weak; Owned by ProfileChooserController. |
| - base::scoped_nsobject<TransparentBackgroundButton> changePhotoButton_; |
| - // Used to display the "Change" button on hover. |
| - ui::ScopedCrTrackingArea trackingArea_; |
| + base::scoped_nsobject<TransparentBackgroundImageView> changePhotoImage_; |
| ProfileChooserController* controller_; |
| } |
| @@ -452,16 +483,6 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| // Called when the "Change" button is clicked. |
| - (void)editPhoto:(id)sender; |
| -// When hovering over the profile photo, show the "Change" button. |
| -- (void)mouseEntered:(NSEvent*)event; |
| - |
| -// When hovering away from the profile photo, hide the "Change" button. |
| -- (void)mouseExited:(NSEvent*)event; |
| -@end |
| - |
| -@interface EditableProfilePhoto (Private) |
| -// Create the "Change" avatar photo button. |
| -- (TransparentBackgroundButton*)changePhotoButtonWithRect:(NSRect)rect; |
| @end |
| @implementation EditableProfilePhoto |
| @@ -473,24 +494,29 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| if ((self = [super initWithFrame:frameRect])) { |
| avatarMenu_ = avatarMenu; |
| controller_ = controller; |
| - [self setImage:CreateProfileImage( |
| - profileIcon, kLargeImageSide).ToNSImage()]; |
| - // Add a tracking area so that we can show/hide the button when hovering. |
| - trackingArea_.reset([[CrTrackingArea alloc] |
| - initWithRect:[self bounds] |
| - options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
| - owner:self |
| - userInfo:nil]); |
| - [self addTrackingArea:trackingArea_.get()]; |
| + [self setBordered:NO]; |
| + |
| + base::scoped_nsobject<CustomCircleImageCell> cell( |
| + [[CustomCircleImageCell alloc] init]); |
| + [self setCell:cell.get()]; |
| + |
| + [self setDefaultImage:CreateProfileImage( |
| + profileIcon, kLargeImageSide).ToNSImage()]; |
| + [self setImagePosition:NSImageOnly]; |
| NSRect bounds = NSMakeRect(0, 0, kLargeImageSide, kLargeImageSide); |
| if (editingAllowed) { |
| - changePhotoButton_.reset([self changePhotoButtonWithRect:bounds]); |
| - [self addSubview:changePhotoButton_]; |
| - |
| - // Hide the button until the image is hovered over. |
| - [changePhotoButton_ setHidden:YES]; |
| + [self setTarget:self]; |
| + [self setAction:@selector(editPhoto:)]; |
| + changePhotoImage_.reset([[TransparentBackgroundImageView alloc] |
| + initWithFrame:bounds]); |
| + [changePhotoImage_ setImage:ui::ResourceBundle::GetSharedInstance(). |
| + GetNativeImageNamed(IDR_ICON_PROFILES_EDIT_CAMERA).AsNSImage()]; |
| + [self addSubview:changePhotoImage_]; |
| + |
| + // Hide the image until the button is hovered over. |
| + [changePhotoImage_ setHidden:YES]; |
| } |
| // Set the image cell's accessibility strings to be the same as the |
| @@ -522,36 +548,15 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| return self; |
| } |
| -- (void)drawRect:(NSRect)dirtyRect { |
| - NSRect bounds = [self bounds]; |
| - |
| - // Display the profile picture as a circle. |
| - NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:bounds]; |
| - [path addClip]; |
| - [self.image drawAtPoint:bounds.origin |
| - fromRect:bounds |
| - operation:NSCompositeSourceOver |
| - fraction:1.0]; |
| - |
| -} |
| - |
| - (void)editPhoto:(id)sender { |
| avatarMenu_->EditProfile(avatarMenu_->GetActiveProfileIndex()); |
| [controller_ |
| postActionPerformed:ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE]; |
| } |
| -- (void)mouseEntered:(NSEvent*)event { |
| - [changePhotoButton_ setHidden:NO]; |
| -} |
| - |
| -- (void)mouseExited:(NSEvent*)event { |
| - [changePhotoButton_ setHidden:YES]; |
| -} |
| - |
| -// Make sure the element is focusable for accessibility. |
| -- (BOOL)canBecomeKeyView { |
| - return YES; |
| +- (void)setHoverState:(HoverState)state { |
| + [super setHoverState:state]; |
| + [changePhotoImage_ setHidden:([self hoverState] == kHoverStateNone)]; |
| } |
| - (BOOL)accessibilityIsIgnored { |
| @@ -571,16 +576,6 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| [super accessibilityPerformAction:action]; |
| } |
| -- (TransparentBackgroundButton*)changePhotoButtonWithRect:(NSRect)rect { |
| - TransparentBackgroundButton* button = |
| - [[TransparentBackgroundButton alloc] initWithFrame:rect]; |
| - [button setImage:ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed( |
| - IDR_ICON_PROFILES_EDIT_CAMERA).AsNSImage()]; |
| - [button setImagePosition:NSImageOnly]; |
| - [button setTarget:self]; |
| - [button setAction:@selector(editPhoto:)]; |
| - return button; |
| -} |
| @end |
| // A custom text control that turns into a textfield for editing when clicked. |
| @@ -772,6 +767,21 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| } |
| @end |
| +// A custom dummy button that is used to clear focus from the bubble's controls. |
| +@interface DummyWindowFocusButton : NSButton |
| +@end |
| + |
| +@implementation DummyWindowFocusButton |
| +// Ignore accessibility, as this is a placeholder button. |
| +- (BOOL)accessibilityIsIgnored { |
| + return YES; |
| +} |
| +- (id)accessibilityAttributeValue:(NSString*)attribute { |
| + return @[]; |
| +} |
| + |
| +@end |
| + |
| @interface ProfileChooserController () |
| // Builds the profile chooser view. |
| - (NSView*)buildProfileChooserView; |
| @@ -1126,7 +1136,15 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| if (viewMode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) |
| tutorialMode_ = profiles::TUTORIAL_MODE_NONE; |
| + // Add a dummy, empty element so that we don't initially display any |
| + // focus rings. |
| + NSButton* dummyFocusButton = |
| + [[[DummyWindowFocusButton alloc] initWithFrame:NSZeroRect] autorelease]; |
| + [dummyFocusButton setNextKeyView:subView]; |
| + [[self window] makeFirstResponder:dummyFocusButton]; |
|
groby-ooo-7-16
2014/08/25 22:06:01
Wondering: Did you test you can't cycle back to th
noms (inactive)
2014/08/26 15:08:17
Hmm, I can cycle back for sure. Adding the two lin
groby-ooo-7-16
2014/08/26 17:49:25
No, autorecalculate means recalculate is called wh
|
| + |
| [contentView addSubview:subView]; |
| + [contentView addSubview:dummyFocusButton]; |
| SetWindowSize([self window], |
| NSMakeSize(NSWidth([subView frame]), NSHeight([subView frame]))); |
| } |
| @@ -1670,7 +1688,8 @@ class ActiveProfileObserverBridge : public AvatarMenuObserver, |
| - (NSButton*)createOtherProfileView:(int)itemIndex { |
| const AvatarMenu::Item& item = avatarMenu_->GetItemAt(itemIndex); |
| - NSRect rect = NSMakeRect(0, 0, kFixedMenuWidth, kBlueButtonHeight); |
| + NSRect rect = NSMakeRect( |
| + 0, 0, kFixedMenuWidth, kBlueButtonHeight + kSmallVerticalSpacing); |
| base::scoped_nsobject<BackgroundColorHoverButton> profileButton( |
| [[BackgroundColorHoverButton alloc] |
| initWithFrame:rect |