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/base/cocoa/controls/hyperlink_button_cell.h" 6 7@interface HyperlinkButtonCell () 8- (void)customizeButtonCell; 9@end 10 11@implementation HyperlinkButtonCell 12 13@dynamic textColor; 14@synthesize underlineOnHover = underlineOnHover_; 15@synthesize shouldUnderline = shouldUnderline_; 16 17+ (NSColor*)defaultTextColor { 18 return [NSColor blueColor]; 19} 20 21+ (NSButton*)buttonWithString:(NSString*)string { 22 NSButton* button = [[[NSButton alloc] initWithFrame:NSZeroRect] autorelease]; 23 base::scoped_nsobject<HyperlinkButtonCell> cell( 24 [[HyperlinkButtonCell alloc] initTextCell:string]); 25 [cell setAlignment:NSLeftTextAlignment]; 26 [button setCell:cell.get()]; 27 [button setBezelStyle:NSRegularSquareBezelStyle]; 28 return button; 29} 30 31// Designated initializer. 32- (id)init { 33 if ((self = [super init])) { 34 [self customizeButtonCell]; 35 } 36 return self; 37} 38 39// Initializer called when the cell is loaded from the NIB. 40- (id)initWithCoder:(NSCoder*)aDecoder { 41 if ((self = [super initWithCoder:aDecoder])) { 42 [self customizeButtonCell]; 43 } 44 return self; 45} 46 47// Initializer for code-based creation. 48- (id)initTextCell:(NSString*)title { 49 if ((self = [super initTextCell:title])) { 50 [self customizeButtonCell]; 51 } 52 return self; 53} 54 55- (id)copyWithZone:(NSZone*)zone { 56 NSColor* color = textColor_.release(); 57 HyperlinkButtonCell* cell = [super copyWithZone:zone]; 58 cell->textColor_.reset([color copy]); 59 textColor_.reset(color); 60 return cell; 61} 62 63// Because an NSButtonCell has multiple initializers, this method performs the 64// common cell customization code. 65- (void)customizeButtonCell { 66 [self setBordered:NO]; 67 [self setTextColor:[HyperlinkButtonCell defaultTextColor]]; 68 [self setShouldUnderline:YES]; 69 70 CGFloat fontSize = [NSFont systemFontSizeForControlSize:[self controlSize]]; 71 NSFont* font = [NSFont controlContentFontOfSize:fontSize]; 72 [self setFont:font]; 73 74 // Do not change button appearance when we are pushed. 75 [self setHighlightsBy:NSNoCellMask]; 76 77 // We need to set this so that we can override |-mouseEntered:| and 78 // |-mouseExited:| to change the cursor style on hover states. 79 [self setShowsBorderOnlyWhileMouseInside:YES]; 80} 81 82- (void)setControlSize:(NSControlSize)size { 83 [super setControlSize:size]; 84 [self customizeButtonCell]; // recompute |font|. 85} 86 87// Creates the NSDictionary of attributes for the attributed string. 88- (NSDictionary*)linkAttributes { 89 NSUInteger underlineMask = NSNoUnderlineStyle; 90 if (shouldUnderline_ && 91 (!underlineOnHover_ || (mouseIsInside_ && [self isEnabled]))) 92 underlineMask = NSUnderlinePatternSolid | NSUnderlineStyleSingle; 93 94 base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle( 95 [[NSParagraphStyle defaultParagraphStyle] mutableCopy]); 96 [paragraphStyle setAlignment:[self alignment]]; 97 [paragraphStyle setLineBreakMode:[self lineBreakMode]]; 98 99 return [NSDictionary dictionaryWithObjectsAndKeys: 100 [self textColor], NSForegroundColorAttributeName, 101 [NSNumber numberWithInt:underlineMask], NSUnderlineStyleAttributeName, 102 [self font], NSFontAttributeName, 103 [NSCursor pointingHandCursor], NSCursorAttributeName, 104 paragraphStyle.get(), NSParagraphStyleAttributeName, 105 nil 106 ]; 107} 108 109// Override the drawing for the cell so that the custom style attributes 110// can always be applied and so that ellipses will appear when appropriate. 111- (NSRect)drawTitle:(NSAttributedString*)title 112 withFrame:(NSRect)frame 113 inView:(NSView*)controlView { 114 NSDictionary* linkAttributes = [self linkAttributes]; 115 NSString* plainTitle = [title string]; 116 [plainTitle drawWithRect:frame 117 options:(NSStringDrawingUsesLineFragmentOrigin | 118 NSStringDrawingTruncatesLastVisibleLine) 119 attributes:linkAttributes]; 120 return frame; 121} 122 123// Override the default behavior to draw the border. Instead, change the cursor. 124- (void)mouseEntered:(NSEvent*)event { 125 mouseIsInside_ = YES; 126 if ([self isEnabled]) 127 [[NSCursor pointingHandCursor] push]; 128 else 129 [[NSCursor currentCursor] push]; 130 if (underlineOnHover_) 131 [[self controlView] setNeedsDisplay:YES]; 132} 133 134- (void)mouseExited:(NSEvent*)event { 135 mouseIsInside_ = NO; 136 [NSCursor pop]; 137 if (underlineOnHover_) 138 [[self controlView] setNeedsDisplay:YES]; 139} 140 141// Setters and getters. 142- (NSColor*)textColor { 143 if ([self isEnabled]) 144 return textColor_.get(); 145 else 146 return [NSColor disabledControlTextColor]; 147} 148 149- (void)setTextColor:(NSColor*)color { 150 textColor_.reset([color retain]); 151} 152 153// Override so that |-sizeToFit| works better with this type of cell. 154- (NSSize)cellSize { 155 NSSize size = [super cellSize]; 156 size.width += 2; 157 return size; 158} 159 160@end 161