Home | History | Annotate | Download | only in controls
      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 // Because an NSButtonCell has multiple initializers, this method performs the
     56 // common cell customization code.
     57 - (void)customizeButtonCell {
     58   [self setBordered:NO];
     59   [self setTextColor:[HyperlinkButtonCell defaultTextColor]];
     60   [self setShouldUnderline:YES];
     61 
     62   CGFloat fontSize = [NSFont systemFontSizeForControlSize:[self controlSize]];
     63   NSFont* font = [NSFont controlContentFontOfSize:fontSize];
     64   [self setFont:font];
     65 
     66   // Do not change button appearance when we are pushed.
     67   [self setHighlightsBy:NSNoCellMask];
     68 
     69   // We need to set this so that we can override |-mouseEntered:| and
     70   // |-mouseExited:| to change the cursor style on hover states.
     71   [self setShowsBorderOnlyWhileMouseInside:YES];
     72 }
     73 
     74 - (void)setControlSize:(NSControlSize)size {
     75   [super setControlSize:size];
     76   [self customizeButtonCell];  // recompute |font|.
     77 }
     78 
     79 // Creates the NSDictionary of attributes for the attributed string.
     80 - (NSDictionary*)linkAttributes {
     81   NSUInteger underlineMask = NSNoUnderlineStyle;
     82   if (shouldUnderline_ &&
     83       (!underlineOnHover_ || (mouseIsInside_ && [self isEnabled])))
     84     underlineMask = NSUnderlinePatternSolid | NSUnderlineStyleSingle;
     85 
     86   base::scoped_nsobject<NSMutableParagraphStyle> paragraphStyle(
     87       [[NSParagraphStyle defaultParagraphStyle] mutableCopy]);
     88   [paragraphStyle setAlignment:[self alignment]];
     89   [paragraphStyle setLineBreakMode:[self lineBreakMode]];
     90 
     91   return [NSDictionary dictionaryWithObjectsAndKeys:
     92       [self textColor], NSForegroundColorAttributeName,
     93       [NSNumber numberWithInt:underlineMask], NSUnderlineStyleAttributeName,
     94       [self font], NSFontAttributeName,
     95       [NSCursor pointingHandCursor], NSCursorAttributeName,
     96       paragraphStyle.get(), NSParagraphStyleAttributeName,
     97       nil
     98   ];
     99 }
    100 
    101 // Override the drawing for the cell so that the custom style attributes
    102 // can always be applied and so that ellipses will appear when appropriate.
    103 - (NSRect)drawTitle:(NSAttributedString*)title
    104           withFrame:(NSRect)frame
    105              inView:(NSView*)controlView {
    106   NSDictionary* linkAttributes = [self linkAttributes];
    107   NSString* plainTitle = [title string];
    108   [plainTitle drawWithRect:frame
    109                    options:(NSStringDrawingUsesLineFragmentOrigin |
    110                             NSStringDrawingTruncatesLastVisibleLine)
    111                 attributes:linkAttributes];
    112   return frame;
    113 }
    114 
    115 // Override the default behavior to draw the border. Instead, change the cursor.
    116 - (void)mouseEntered:(NSEvent*)event {
    117   mouseIsInside_ = YES;
    118   if ([self isEnabled])
    119     [[NSCursor pointingHandCursor] push];
    120   else
    121     [[NSCursor currentCursor] push];
    122   if (underlineOnHover_)
    123     [[self controlView] setNeedsDisplay:YES];
    124 }
    125 
    126 - (void)mouseExited:(NSEvent*)event {
    127   mouseIsInside_ = NO;
    128   [NSCursor pop];
    129   if (underlineOnHover_)
    130     [[self controlView] setNeedsDisplay:YES];
    131 }
    132 
    133 // Setters and getters.
    134 - (NSColor*)textColor {
    135   if ([self isEnabled])
    136     return textColor_.get();
    137   else
    138     return [NSColor disabledControlTextColor];
    139 }
    140 
    141 - (void)setTextColor:(NSColor*)color {
    142   textColor_.reset([color retain]);
    143 }
    144 
    145 // Override so that |-sizeToFit| works better with this type of cell.
    146 - (NSSize)cellSize {
    147   NSSize size = [super cellSize];
    148   size.width += 2;
    149   return size;
    150 }
    151 
    152 @end
    153