• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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