Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" | 5 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button_cell.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/sys_string_conversions.h" | 8 #include "base/strings/sys_string_conversions.h" |
| 9 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" | 9 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" |
| 10 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" | 10 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 const int kHierarchyButtonLeftPadding = 11; | 30 const int kHierarchyButtonLeftPadding = 11; |
| 31 | 31 |
| 32 const int kIconTextSpacer = 4; | 32 const int kIconTextSpacer = 4; |
| 33 const int kTextRightPadding = 4; | 33 const int kTextRightPadding = 4; |
| 34 const int kIconLeftPadding = 4; | 34 const int kIconLeftPadding = 4; |
| 35 | 35 |
| 36 const int kDefaultFontSize = 12; | 36 const int kDefaultFontSize = 12; |
| 37 | 37 |
| 38 }; // namespace | 38 }; // namespace |
| 39 | 39 |
| 40 @interface BookmarkButtonCell (Private) | |
| 41 // Returns YES if the cell is the offTheSide button cell. | |
| 42 - (BOOL)isOffTheSideButtonCell; | |
| 43 - (void)configureBookmarkButtonCell; | |
| 44 - (void)applyTextColor; | |
| 45 // Returns the title the button cell displays. Note that a button cell can | |
| 46 // have a title string assigned but it won't be visible if its image position | |
| 47 // is NSImageOnly. | |
| 48 - (NSString*)visibleTitle; | |
| 49 // Returns the dictionary of attributes to associate with the button title. | |
| 50 - (NSDictionary*)titleTextAttributes; | |
| 51 @end | |
| 52 | |
| 40 // TODO(lgrey): Bake setting the chevron image into this | 53 // TODO(lgrey): Bake setting the chevron image into this |
| 41 // class instead of setting it externally. | 54 // class instead of setting it externally. |
| 42 @interface OffTheSideButtonCell : BookmarkButtonCell | 55 @interface OffTheSideButtonCell : BookmarkButtonCell |
| 43 | 56 |
| 44 - (NSString*)accessibilityTitle; | 57 - (NSString*)accessibilityTitle; |
| 45 | 58 |
| 46 @end | 59 @end |
| 47 @implementation OffTheSideButtonCell | 60 @implementation OffTheSideButtonCell |
| 48 | 61 |
| 49 - (BOOL)isOffTheSideButtonCell { | 62 - (BOOL)isOffTheSideButtonCell { |
| 50 return YES; | 63 return YES; |
| 51 } | 64 } |
| 52 | 65 |
| 53 - (NSString*)accessibilityTitle { | 66 - (NSString*)accessibilityTitle { |
| 54 return l10n_util::GetNSString(IDS_ACCNAME_BOOKMARKS_CHEVRON); | 67 return l10n_util::GetNSString(IDS_ACCNAME_BOOKMARKS_CHEVRON); |
| 55 } | 68 } |
| 56 | 69 |
| 57 - (NSRect)imageRectForBounds:(NSRect)theRect { | 70 - (NSRect)imageRectForBounds:(NSRect)theRect { |
| 58 NSRect imageRect = [super imageRectForBounds:theRect]; | 71 NSRect imageRect = [super imageRectForBounds:theRect]; |
| 59 // Make sure the chevron icon stays centered. Normally a bookmark bar item | 72 // Make sure the chevron icon stays centered. Normally a bookmark bar item |
| 60 // with no label has its icon placed at a fixed x-position. | 73 // with no label has its icon placed at a fixed x-position. |
| 61 CGFloat totalWidth = NSMaxX(theRect); | 74 CGFloat totalWidth = NSMaxX(theRect); |
| 62 imageRect.origin.x = (totalWidth - [self image].size.width) / 2; | 75 imageRect.origin.x = (totalWidth - [self image].size.width) / 2; |
| 63 return imageRect; | 76 return imageRect; |
| 64 } | 77 } |
| 65 | 78 |
| 66 @end | 79 @end |
| 67 | 80 |
| 68 @interface BookmarkButtonCell(Private) | |
| 69 // Returns YES if the cell is the offTheSide button cell. | |
| 70 - (BOOL)isOffTheSideButtonCell; | |
| 71 - (void)configureBookmarkButtonCell; | |
| 72 - (void)applyTextColor; | |
| 73 // Returns the title the button cell displays. Note that a button cell can | |
| 74 // have a title string assigned but it won't be visible if its image position | |
| 75 // is NSImageOnly. | |
| 76 - (NSString*)visibleTitle; | |
| 77 // Returns the dictionary of attributes to associate with the button title. | |
| 78 - (NSDictionary*)titleTextAttributes; | |
| 79 @end | |
| 80 | |
| 81 | 81 |
| 82 @implementation BookmarkButtonCell | 82 @implementation BookmarkButtonCell |
| 83 | 83 |
| 84 @synthesize startingChildIndex = startingChildIndex_; | 84 @synthesize startingChildIndex = startingChildIndex_; |
| 85 @synthesize drawFolderArrow = drawFolderArrow_; | 85 @synthesize drawFolderArrow = drawFolderArrow_; |
| 86 | 86 |
| 87 + (id)buttonCellForNode:(const BookmarkNode*)node | 87 + (id)buttonCellForNode:(const BookmarkNode*)node |
| 88 text:(NSString*)text | 88 text:(NSString*)text |
| 89 image:(NSImage*)image | 89 image:(NSImage*)image |
| 90 menuController:(BookmarkContextMenuCocoaController*)menuController { | 90 menuController:(BookmarkContextMenuCocoaController*)menuController { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 105 image:image | 105 image:image |
| 106 menuController:menuController] | 106 menuController:menuController] |
| 107 autorelease]; | 107 autorelease]; |
| 108 return buttonCell; | 108 return buttonCell; |
| 109 } | 109 } |
| 110 | 110 |
| 111 + (id)offTheSideButtonCell { | 111 + (id)offTheSideButtonCell { |
| 112 return [[[OffTheSideButtonCell alloc] init] autorelease]; | 112 return [[[OffTheSideButtonCell alloc] init] autorelease]; |
| 113 } | 113 } |
| 114 | 114 |
| 115 + (CGFloat)cellWidthForNode:(const bookmarks::BookmarkNode*)node | |
| 116 image:(NSImage*)image { | |
| 117 NSString* title = | |
| 118 [self cleanTitle:base::SysUTF16ToNSString(node->GetTitle())]; | |
| 119 CGFloat width = kIconLeftPadding + [image size].width; | |
| 120 if ([title length] > 0) { | |
| 121 CGSize titleSize = [title sizeWithAttributes:@{ | |
| 122 NSParagraphStyleAttributeName : [self paragraphStyleForBookmarkBarCell] | |
| 123 }]; | |
| 124 width += kIconTextSpacer + std::ceil(titleSize.width) + kTextRightPadding; | |
| 125 } else { | |
| 126 width += kIconLeftPadding; | |
| 127 } | |
| 128 return width; | |
| 129 } | |
| 130 | |
| 115 - (id)initForNode:(const BookmarkNode*)node | 131 - (id)initForNode:(const BookmarkNode*)node |
| 116 text:(NSString*)text | 132 text:(NSString*)text |
| 117 image:(NSImage*)image | 133 image:(NSImage*)image |
| 118 menuController:(BookmarkContextMenuCocoaController*)menuController { | 134 menuController:(BookmarkContextMenuCocoaController*)menuController { |
| 119 if ((self = [super initTextCell:text])) { | 135 if ((self = [super initTextCell:text])) { |
| 120 menuController_ = menuController; | 136 menuController_ = menuController; |
| 121 [self configureBookmarkButtonCell]; | 137 [self configureBookmarkButtonCell]; |
| 122 [self setTextColor:[NSColor blackColor]]; | 138 [self setTextColor:[NSColor blackColor]]; |
| 123 [self setBookmarkNode:node]; | 139 [self setBookmarkNode:node image:image]; |
| 124 // When opening a bookmark folder, the default behavior is that the | 140 // When opening a bookmark folder, the default behavior is that the |
| 125 // favicon is greyed when menu item is hovered with the mouse cursor. | 141 // favicon is greyed when menu item is hovered with the mouse cursor. |
| 126 // When using NSNoCellMask, the favicon won't be greyed when menu item | 142 // When using NSNoCellMask, the favicon won't be greyed when menu item |
| 127 // is hovered. | 143 // is hovered. |
| 128 // In the bookmark bar, the favicon is not greyed when the bookmark is | 144 // In the bookmark bar, the favicon is not greyed when the bookmark is |
| 129 // hovered with the mouse cursor. | 145 // hovered with the mouse cursor. |
| 130 // It makes the behavior of the bookmark folder consistent with hovering | 146 // It makes the behavior of the bookmark folder consistent with hovering |
| 131 // on the bookmark bar. | 147 // on the bookmark bar. |
| 132 [self setHighlightsBy:NSNoCellMask]; | 148 [self setHighlightsBy:NSNoCellMask]; |
| 133 | |
| 134 if (node) { | |
| 135 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); | |
| 136 [self setBookmarkCellText:title image:image]; | |
| 137 } else { | |
| 138 [self setEmpty:YES]; | |
| 139 [self setBookmarkCellText:l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU) | |
| 140 image:nil]; | |
| 141 } | |
| 142 } | 149 } |
| 143 | 150 |
| 144 return self; | 151 return self; |
| 145 } | 152 } |
| 146 | 153 |
| 147 - (id)initWithText:(NSString*)text | 154 - (id)initWithText:(NSString*)text |
| 148 image:(NSImage*)image | 155 image:(NSImage*)image |
| 149 menuController:(BookmarkContextMenuCocoaController*)menuController { | 156 menuController:(BookmarkContextMenuCocoaController*)menuController { |
| 150 if ((self = [super initTextCell:text])) { | 157 if ((self = [super initTextCell:text])) { |
| 151 menuController_ = menuController; | 158 menuController_ = menuController; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 178 - (BOOL)isOffTheSideButtonCell { | 185 - (BOOL)isOffTheSideButtonCell { |
| 179 return NO; | 186 return NO; |
| 180 } | 187 } |
| 181 | 188 |
| 182 // Perform all normal init routines specific to the BookmarkButtonCell. | 189 // Perform all normal init routines specific to the BookmarkButtonCell. |
| 183 - (void)configureBookmarkButtonCell { | 190 - (void)configureBookmarkButtonCell { |
| 184 [self setButtonType:NSMomentaryPushInButton]; | 191 [self setButtonType:NSMomentaryPushInButton]; |
| 185 [self setShowsBorderOnlyWhileMouseInside:YES]; | 192 [self setShowsBorderOnlyWhileMouseInside:YES]; |
| 186 [self setControlSize:NSSmallControlSize]; | 193 [self setControlSize:NSSmallControlSize]; |
| 187 [self setAlignment:NSLeftTextAlignment]; | 194 [self setAlignment:NSLeftTextAlignment]; |
| 188 [self setFont:[NSFont systemFontOfSize:kDefaultFontSize]]; | 195 [self setFont:[[self class] fontForBookmarkBarCell]]; |
| 189 [self setBordered:NO]; | 196 [self setBordered:NO]; |
| 190 [self setBezeled:NO]; | 197 [self setBezeled:NO]; |
| 191 [self setWraps:NO]; | 198 [self setWraps:NO]; |
| 192 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's | 199 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's |
| 193 // try to match Windows for a bit to see what happens. | 200 // try to match Windows for a bit to see what happens. |
| 194 [self setLineBreakMode:NSLineBreakByTruncatingTail]; | 201 [self setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 195 | 202 |
| 196 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled | 203 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled |
| 197 // at paint time without this. | 204 // at paint time without this. |
| 198 [self setImageScaling:NSImageScaleNone]; | 205 [self setImageScaling:NSImageScaleNone]; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 213 - (NSSize)cellSizeForBounds:(NSRect)aRect { | 220 - (NSSize)cellSizeForBounds:(NSRect)aRect { |
| 214 // There's no bezel or border so return cellSize. | 221 // There's no bezel or border so return cellSize. |
| 215 NSSize size = [self cellSize]; | 222 NSSize size = [self cellSize]; |
| 216 size.width = std::min(aRect.size.width, size.width); | 223 size.width = std::min(aRect.size.width, size.width); |
| 217 size.height = std::min(aRect.size.height, size.height); | 224 size.height = std::min(aRect.size.height, size.height); |
| 218 return size; | 225 return size; |
| 219 } | 226 } |
| 220 | 227 |
| 221 - (void)setBookmarkCellText:(NSString*)title | 228 - (void)setBookmarkCellText:(NSString*)title |
| 222 image:(NSImage*)image { | 229 image:(NSImage*)image { |
| 223 title = [title stringByReplacingOccurrencesOfString:@"\n" | 230 title = [[self class] cleanTitle:title]; |
| 224 withString:@" "]; | 231 if ([title length] && ![self isOffTheSideButtonCell]) { |
| 225 title = [title stringByReplacingOccurrencesOfString:@"\r" | |
| 226 withString:@" "]; | |
| 227 | |
| 228 if ([title length]) { | |
| 229 [self setImagePosition:NSImageLeft]; | 232 [self setImagePosition:NSImageLeft]; |
| 230 [self setTitle:title]; | 233 [self setTitle:title]; |
| 231 } else if ([self isFolderButtonCell]) { | 234 } else if ([self isFolderButtonCell]) { |
| 232 // Left-align icons for bookmarks within folders, regardless of whether | 235 // Left-align icons for bookmarks within folders, regardless of whether |
| 233 // there is a title. | 236 // there is a title. |
| 234 [self setImagePosition:NSImageLeft]; | 237 [self setImagePosition:NSImageLeft]; |
| 235 } else { | 238 } else { |
| 236 // For bookmarks without a title that aren't visible directly in the | 239 // For bookmarks without a title that aren't visible directly in the |
| 237 // bookmarks bar, squeeze things tighter by displaying only the image. | 240 // bookmarks bar, squeeze things tighter by displaying only the image. |
| 238 // By default, Cocoa leaves extra space in an attempt to display an | 241 // By default, Cocoa leaves extra space in an attempt to display an |
| 239 // empty title. | 242 // empty title. |
| 240 [self setImagePosition:NSImageOnly]; | 243 [self setImagePosition:NSImageOnly]; |
| 241 } | 244 } |
| 242 | 245 |
| 243 if (image) | 246 if (image) |
| 244 [self setImage:image]; | 247 [self setImage:image]; |
| 245 } | 248 } |
| 246 | 249 |
| 247 - (void)setBookmarkNode:(const BookmarkNode*)node { | 250 - (void)setBookmarkNode:(const BookmarkNode*)node { |
| 251 [self setBookmarkNode:node image:nil]; | |
| 252 } | |
| 253 | |
| 254 - (void)setBookmarkNode:(const BookmarkNode*)node image:(NSImage*)image { | |
| 248 [self setRepresentedObject:[NSValue valueWithPointer:node]]; | 255 [self setRepresentedObject:[NSValue valueWithPointer:node]]; |
| 256 if (node) { | |
| 257 NSString* title = base::SysUTF16ToNSString(node->GetTitle()); | |
| 258 [self setBookmarkCellText:title image:image]; | |
| 259 } else { | |
| 260 [self setEmpty:YES]; | |
| 261 [self setBookmarkCellText:l10n_util::GetNSString(IDS_MENU_EMPTY_SUBMENU) | |
| 262 image:nil]; | |
| 263 } | |
| 249 } | 264 } |
| 250 | 265 |
| 251 - (const BookmarkNode*)bookmarkNode { | 266 - (const BookmarkNode*)bookmarkNode { |
| 252 return static_cast<const BookmarkNode*>([[self representedObject] | 267 return static_cast<const BookmarkNode*>([[self representedObject] |
| 253 pointerValue]); | 268 pointerValue]); |
| 254 } | 269 } |
| 255 | 270 |
| 256 - (NSMenu*)menu { | 271 - (NSMenu*)menu { |
| 257 // If node is NULL, this is a custom button, the menu does not represent | 272 // If node is NULL, this is a custom button, the menu does not represent |
| 258 // anything. | 273 // anything. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 308 - (void)setDrawFolderArrow:(BOOL)draw { | 323 - (void)setDrawFolderArrow:(BOOL)draw { |
| 309 drawFolderArrow_ = draw; | 324 drawFolderArrow_ = draw; |
| 310 if (draw && !arrowImage_) { | 325 if (draw && !arrowImage_) { |
| 311 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 326 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 312 arrowImage_.reset( | 327 arrowImage_.reset( |
| 313 [rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage() retain]); | 328 [rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage() retain]); |
| 314 } | 329 } |
| 315 } | 330 } |
| 316 | 331 |
| 317 - (NSDictionary*)titleTextAttributes { | 332 - (NSDictionary*)titleTextAttributes { |
| 318 base::scoped_nsobject<NSMutableParagraphStyle> style( | 333 NSParagraphStyle* style = [[self class] paragraphStyleForBookmarkBarCell]; |
| 319 [NSMutableParagraphStyle new]); | |
| 320 [style setAlignment:NSNaturalTextAlignment]; | |
| 321 [style setLineBreakMode:NSLineBreakByTruncatingTail]; | |
| 322 NSColor* textColor = textColor_.get(); | 334 NSColor* textColor = textColor_.get(); |
| 323 if (!textColor) { | 335 if (!textColor) { |
| 324 textColor = [NSColor blackColor]; | 336 textColor = [NSColor blackColor]; |
| 325 } | 337 } |
| 326 if (![self isEnabled]) { | 338 if (![self isEnabled]) { |
| 327 textColor = [textColor colorWithAlphaComponent:0.5]; | 339 textColor = [textColor colorWithAlphaComponent:0.5]; |
| 328 } | 340 } |
| 329 NSFont* theFont = [self font]; | 341 NSFont* theFont = [self font]; |
| 330 if (!theFont) { | 342 if (!theFont) { |
| 331 theFont = [NSFont systemFontOfSize:kDefaultFontSize]; | 343 theFont = [NSFont systemFontOfSize:kDefaultFontSize]; |
| 332 } | 344 } |
| 333 | 345 |
| 334 return @{ | 346 return @{ |
| 335 NSFontAttributeName : theFont, | 347 NSFontAttributeName : theFont, |
| 336 NSForegroundColorAttributeName : textColor, | 348 NSForegroundColorAttributeName : textColor, |
| 337 NSParagraphStyleAttributeName : style.get(), | 349 NSParagraphStyleAttributeName : style, |
| 338 NSKernAttributeName : [NSNumber numberWithFloat:0.2] | 350 NSKernAttributeName : [NSNumber numberWithFloat:0.2] |
| 339 }; | 351 }; |
| 340 } | 352 } |
| 341 | 353 |
| 342 - (NSString*)visibleTitle { | 354 - (NSString*)visibleTitle { |
| 343 return [self imagePosition] != NSImageOnly ? [self title] : @""; | 355 return [self imagePosition] != NSImageOnly ? [self title] : @""; |
| 344 } | 356 } |
| 345 | 357 |
| 346 // Add extra size for the arrow so it doesn't overlap the text. | 358 // Add extra size for the arrow so it doesn't overlap the text. |
| 347 // Does not sanity check to be sure this is actually a folder node. | 359 // Does not sanity check to be sure this is actually a folder node. |
| 348 - (NSSize)cellSize { | 360 - (NSSize)cellSize { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 434 // In Material Design on Retina, and not in a folder menu, nudge the hover | 446 // In Material Design on Retina, and not in a folder menu, nudge the hover |
| 435 // background by 1px. | 447 // background by 1px. |
| 436 const CGFloat kLineWidth = [controlView cr_lineWidth]; | 448 const CGFloat kLineWidth = [controlView cr_lineWidth]; |
| 437 if ([self isMaterialDesignButtonType] && ![self isFolderButtonCell] && | 449 if ([self isMaterialDesignButtonType] && ![self isFolderButtonCell] && |
| 438 kLineWidth < 1) { | 450 kLineWidth < 1) { |
| 439 return -kLineWidth; | 451 return -kLineWidth; |
| 440 } | 452 } |
| 441 return 0.0; | 453 return 0.0; |
| 442 } | 454 } |
| 443 | 455 |
| 456 + (NSFont*)fontForBookmarkBarCell { | |
|
Elly Fong-Jones
2017/03/23 15:40:22
I like this pattern of breaking sorta-constants ou
| |
| 457 return [NSFont systemFontOfSize:kDefaultFontSize]; | |
| 458 } | |
| 459 | |
| 460 + (NSParagraphStyle*)paragraphStyleForBookmarkBarCell { | |
| 461 NSMutableParagraphStyle* style = [[NSMutableParagraphStyle alloc] init]; | |
| 462 [style setAlignment:NSNaturalTextAlignment]; | |
| 463 [style setLineBreakMode:NSLineBreakByTruncatingTail]; | |
| 464 return [style autorelease]; | |
| 465 } | |
| 466 | |
| 467 // Returns |title| with newlines and line feeds replaced with | |
| 468 // spaces. | |
| 469 + (NSString*)cleanTitle:(NSString*)title { | |
| 470 title = [title stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; | |
| 471 title = [title stringByReplacingOccurrencesOfString:@"\r" withString:@" "]; | |
| 472 return title; | |
| 473 } | |
| 444 | 474 |
| 445 @end | 475 @end |
| OLD | NEW |