| 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/metrics/user_metrics.h" | 8 #include "base/metrics/user_metrics.h" |
| 9 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 10 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" | 10 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_bar_constants.h" |
| 11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" | 11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" |
| 12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controlle
r.h" | 12 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controlle
r.h" |
| 13 #include "chrome/browser/ui/cocoa/l10n_util.h" |
| 13 #include "chrome/grit/generated_resources.h" | 14 #include "chrome/grit/generated_resources.h" |
| 14 #import "components/bookmarks/browser/bookmark_model.h" | 15 #import "components/bookmarks/browser/bookmark_model.h" |
| 15 #import "ui/base/cocoa/nsview_additions.h" | 16 #import "ui/base/cocoa/nsview_additions.h" |
| 16 #include "ui/base/l10n/l10n_util_mac.h" | 17 #include "ui/base/l10n/l10n_util_mac.h" |
| 17 #include "ui/base/material_design/material_design_controller.h" | 18 #include "ui/base/material_design/material_design_controller.h" |
| 18 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
| 19 #include "ui/resources/grit/ui_resources.h" | 20 #include "ui/resources/grit/ui_resources.h" |
| 20 | 21 |
| 21 using base::UserMetricsAction; | 22 using base::UserMetricsAction; |
| 22 using bookmarks::BookmarkNode; | 23 using bookmarks::BookmarkNode; |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 // Padding on the right side of the arrow icon. | 27 // Padding on the trailing side of the arrow icon. |
| 27 const int kHierarchyButtonRightPadding = 4; | 28 const int kHierarchyButtonTrailingPadding = 4; |
| 28 | 29 |
| 29 // Padding on the left side of the arrow icon. | 30 // Padding on the leading side of the arrow icon. |
| 30 const int kHierarchyButtonLeftPadding = 11; | 31 const int kHierarchyButtonLeadingPadding = 11; |
| 31 | 32 |
| 32 const int kIconTextSpacer = 4; | 33 const int kIconTextSpacer = 4; |
| 33 const int kTextRightPadding = 4; | 34 const int kTrailingPadding = 4; |
| 34 const int kIconLeftPadding = 4; | 35 const int kIconLeadingPadding = 4; |
| 35 | 36 |
| 36 const int kDefaultFontSize = 12; | 37 const int kDefaultFontSize = 12; |
| 37 | 38 |
| 38 // Kerning value for the title text. | 39 // Kerning value for the title text. |
| 39 const CGFloat kKernAmount = 0.2; | 40 const CGFloat kKernAmount = 0.2; |
| 40 | 41 |
| 41 }; // namespace | 42 }; // namespace |
| 42 | 43 |
| 43 // TODO(lgrey): Bake setting the chevron image into this | 44 // TODO(lgrey): Bake setting the chevron image into this |
| 44 // class instead of setting it externally. | 45 // class instead of setting it externally. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 } | 112 } |
| 112 | 113 |
| 113 + (id)offTheSideButtonCell { | 114 + (id)offTheSideButtonCell { |
| 114 return [[[OffTheSideButtonCell alloc] init] autorelease]; | 115 return [[[OffTheSideButtonCell alloc] init] autorelease]; |
| 115 } | 116 } |
| 116 | 117 |
| 117 + (CGFloat)cellWidthForNode:(const bookmarks::BookmarkNode*)node | 118 + (CGFloat)cellWidthForNode:(const bookmarks::BookmarkNode*)node |
| 118 image:(NSImage*)image { | 119 image:(NSImage*)image { |
| 119 NSString* title = | 120 NSString* title = |
| 120 [self cleanTitle:base::SysUTF16ToNSString(node->GetTitle())]; | 121 [self cleanTitle:base::SysUTF16ToNSString(node->GetTitle())]; |
| 121 CGFloat width = kIconLeftPadding + [image size].width; | 122 CGFloat width = kIconLeadingPadding + [image size].width; |
| 122 if ([title length] > 0) { | 123 if ([title length] > 0) { |
| 123 CGSize titleSize = [title sizeWithAttributes:@{ | 124 CGSize titleSize = [title sizeWithAttributes:@{ |
| 124 NSParagraphStyleAttributeName : [self paragraphStyleForBookmarkBarCell], | 125 NSParagraphStyleAttributeName : [self paragraphStyleForBookmarkBarCell], |
| 125 NSKernAttributeName : @(kKernAmount), | 126 NSKernAttributeName : @(kKernAmount), |
| 126 NSFontAttributeName : [self fontForBookmarkBarCell], | 127 NSFontAttributeName : [self fontForBookmarkBarCell], |
| 127 }]; | 128 }]; |
| 128 width += kIconTextSpacer + std::ceil(titleSize.width) + kTextRightPadding; | 129 width += kIconTextSpacer + std::ceil(titleSize.width) + kTrailingPadding; |
| 129 } else { | 130 } else { |
| 130 width += kIconLeftPadding; | 131 width += kTrailingPadding; |
| 131 } | 132 } |
| 132 return width; | 133 return width; |
| 133 } | 134 } |
| 134 | 135 |
| 135 - (id)initForNode:(const BookmarkNode*)node | 136 - (id)initForNode:(const BookmarkNode*)node |
| 136 text:(NSString*)text | 137 text:(NSString*)text |
| 137 image:(NSImage*)image | 138 image:(NSImage*)image |
| 138 menuController:(BookmarkContextMenuCocoaController*)menuController { | 139 menuController:(BookmarkContextMenuCocoaController*)menuController { |
| 139 if ((self = [super initTextCell:text])) { | 140 if ((self = [super initTextCell:text])) { |
| 140 menuController_ = menuController; | 141 menuController_ = menuController; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 | 189 |
| 189 - (BOOL)isOffTheSideButtonCell { | 190 - (BOOL)isOffTheSideButtonCell { |
| 190 return NO; | 191 return NO; |
| 191 } | 192 } |
| 192 | 193 |
| 193 // Perform all normal init routines specific to the BookmarkButtonCell. | 194 // Perform all normal init routines specific to the BookmarkButtonCell. |
| 194 - (void)configureBookmarkButtonCell { | 195 - (void)configureBookmarkButtonCell { |
| 195 [self setButtonType:NSMomentaryPushInButton]; | 196 [self setButtonType:NSMomentaryPushInButton]; |
| 196 [self setShowsBorderOnlyWhileMouseInside:YES]; | 197 [self setShowsBorderOnlyWhileMouseInside:YES]; |
| 197 [self setControlSize:NSSmallControlSize]; | 198 [self setControlSize:NSSmallControlSize]; |
| 198 [self setAlignment:NSLeftTextAlignment]; | 199 [self setAlignment:NSNaturalTextAlignment]; |
| 199 [self setFont:[[self class] fontForBookmarkBarCell]]; | 200 [self setFont:[[self class] fontForBookmarkBarCell]]; |
| 200 [self setBordered:NO]; | 201 [self setBordered:NO]; |
| 201 [self setBezeled:NO]; | 202 [self setBezeled:NO]; |
| 202 [self setWraps:NO]; | 203 [self setWraps:NO]; |
| 203 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's | 204 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's |
| 204 // try to match Windows for a bit to see what happens. | 205 // try to match Windows for a bit to see what happens. |
| 205 [self setLineBreakMode:NSLineBreakByTruncatingTail]; | 206 [self setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 206 | 207 |
| 207 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled | 208 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled |
| 208 // at paint time without this. | 209 // at paint time without this. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 226 NSSize size = [self cellSize]; | 227 NSSize size = [self cellSize]; |
| 227 size.width = std::min(aRect.size.width, size.width); | 228 size.width = std::min(aRect.size.width, size.width); |
| 228 size.height = std::min(aRect.size.height, size.height); | 229 size.height = std::min(aRect.size.height, size.height); |
| 229 return size; | 230 return size; |
| 230 } | 231 } |
| 231 | 232 |
| 232 - (void)setBookmarkCellText:(NSString*)title | 233 - (void)setBookmarkCellText:(NSString*)title |
| 233 image:(NSImage*)image { | 234 image:(NSImage*)image { |
| 234 title = [[self class] cleanTitle:title]; | 235 title = [[self class] cleanTitle:title]; |
| 235 if ([title length] && ![self isOffTheSideButtonCell]) { | 236 if ([title length] && ![self isOffTheSideButtonCell]) { |
| 236 [self setImagePosition:NSImageLeft]; | 237 [self setImagePosition:cocoa_l10n_util::LeadingCellImagePosition()]; |
| 237 [self setTitle:title]; | 238 [self setTitle:title]; |
| 238 } else if ([self isFolderButtonCell]) { | 239 } else if ([self isFolderButtonCell]) { |
| 239 // Left-align icons for bookmarks within folders, regardless of whether | 240 // Left-align icons for bookmarks within folders, regardless of whether |
| 240 // there is a title. | 241 // there is a title. |
| 241 [self setImagePosition:NSImageLeft]; | 242 [self setImagePosition:cocoa_l10n_util::LeadingCellImagePosition()]; |
| 242 } else { | 243 } else { |
| 243 // For bookmarks without a title that aren't visible directly in the | 244 // For bookmarks without a title that aren't visible directly in the |
| 244 // bookmarks bar, squeeze things tighter by displaying only the image. | 245 // bookmarks bar, squeeze things tighter by displaying only the image. |
| 245 // By default, Cocoa leaves extra space in an attempt to display an | 246 // By default, Cocoa leaves extra space in an attempt to display an |
| 246 // empty title. | 247 // empty title. |
| 247 [self setImagePosition:NSImageOnly]; | 248 [self setImagePosition:NSImageOnly]; |
| 248 } | 249 } |
| 249 | 250 |
| 250 if (image) | 251 if (image) |
| 251 [self setImage:image]; | 252 [self setImage:image]; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 // See comment above mouseEntered:, above. | 322 // See comment above mouseEntered:, above. |
| 322 - (void)mouseExited:(NSEvent*)event { | 323 - (void)mouseExited:(NSEvent*)event { |
| 323 [[self controlView] mouseExited:event]; | 324 [[self controlView] mouseExited:event]; |
| 324 [super mouseExited:event]; | 325 [super mouseExited:event]; |
| 325 } | 326 } |
| 326 | 327 |
| 327 - (void)setDrawFolderArrow:(BOOL)draw { | 328 - (void)setDrawFolderArrow:(BOOL)draw { |
| 328 drawFolderArrow_ = draw; | 329 drawFolderArrow_ = draw; |
| 329 if (draw && !arrowImage_) { | 330 if (draw && !arrowImage_) { |
| 330 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 331 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 331 arrowImage_.reset( | 332 NSImage* image = |
| 332 [rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage() retain]); | 333 rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage(); |
| 334 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) |
| 335 image = cocoa_l10n_util::FlippedImage(image); |
| 336 arrowImage_.reset([image retain]); |
| 333 } | 337 } |
| 334 } | 338 } |
| 335 | 339 |
| 336 - (NSDictionary*)titleTextAttributes { | 340 - (NSDictionary*)titleTextAttributes { |
| 337 NSParagraphStyle* style = [[self class] paragraphStyleForBookmarkBarCell]; | 341 NSParagraphStyle* style = [[self class] paragraphStyleForBookmarkBarCell]; |
| 338 NSColor* textColor = textColor_.get(); | 342 NSColor* textColor = textColor_.get(); |
| 339 if (!textColor) { | 343 if (!textColor) { |
| 340 textColor = [NSColor blackColor]; | 344 textColor = [NSColor blackColor]; |
| 341 } | 345 } |
| 342 if (![self isEnabled]) { | 346 if (![self isEnabled]) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 358 - (NSString*)visibleTitle { | 362 - (NSString*)visibleTitle { |
| 359 return [self imagePosition] != NSImageOnly ? [self title] : @""; | 363 return [self imagePosition] != NSImageOnly ? [self title] : @""; |
| 360 } | 364 } |
| 361 | 365 |
| 362 // Add extra size for the arrow so it doesn't overlap the text. | 366 // Add extra size for the arrow so it doesn't overlap the text. |
| 363 // Does not sanity check to be sure this is actually a folder node. | 367 // Does not sanity check to be sure this is actually a folder node. |
| 364 - (NSSize)cellSize { | 368 - (NSSize)cellSize { |
| 365 NSSize cellSize = NSZeroSize; | 369 NSSize cellSize = NSZeroSize; |
| 366 // Return the space needed to display the image and title, with a little | 370 // Return the space needed to display the image and title, with a little |
| 367 // distance between them. | 371 // distance between them. |
| 368 cellSize = NSMakeSize(kIconLeftPadding + [[self image] size].width, | 372 cellSize = NSMakeSize(kIconLeadingPadding + [[self image] size].width, |
| 369 bookmarks::kBookmarkButtonHeight); | 373 bookmarks::kBookmarkButtonHeight); |
| 370 NSString* title = [self visibleTitle]; | 374 NSString* title = [self visibleTitle]; |
| 371 if ([title length] > 0) { | 375 if ([title length] > 0) { |
| 372 CGFloat textWidth = | 376 CGFloat textWidth = |
| 373 [title sizeWithAttributes:[self titleTextAttributes]].width; | 377 [title sizeWithAttributes:[self titleTextAttributes]].width; |
| 374 cellSize.width += | 378 cellSize.width += kIconTextSpacer + std::ceil(textWidth) + kTrailingPadding; |
| 375 kIconTextSpacer + std::ceil(textWidth) + kTextRightPadding; | |
| 376 } else { | 379 } else { |
| 377 // Make buttons without visible titles 20pts wide (18 plus padding). | 380 cellSize.width += kIconLeadingPadding; |
| 378 cellSize.width += kIconLeftPadding; | |
| 379 } | 381 } |
| 380 | 382 |
| 381 if (drawFolderArrow_) { | 383 if (drawFolderArrow_) { |
| 382 cellSize.width += [arrowImage_ size].width + | 384 cellSize.width += [arrowImage_ size].width + |
| 383 kHierarchyButtonLeftPadding + | 385 kHierarchyButtonLeadingPadding + |
| 384 kHierarchyButtonRightPadding; | 386 kHierarchyButtonTrailingPadding; |
| 385 } | 387 } |
| 386 return cellSize; | 388 return cellSize; |
| 387 } | 389 } |
| 388 | 390 |
| 389 - (NSRect)imageRectForBounds:(NSRect)theRect { | 391 - (NSRect)imageRectForBounds:(NSRect)theRect { |
| 390 NSRect imageRect = [super imageRectForBounds:theRect]; | 392 NSRect imageRect = [super imageRectForBounds:theRect]; |
| 391 // Add a little space between the image and the button's left edge, but only | 393 const CGFloat inset = [self insetInView:[self controlView]]; |
| 392 // if there's a visible title. | |
| 393 imageRect.origin.y -= 1; | 394 imageRect.origin.y -= 1; |
| 394 imageRect.origin.x = kIconLeftPadding; | 395 imageRect.origin.x = |
| 396 cocoa_l10n_util::ShouldDoExperimentalRTLLayout() |
| 397 ? NSMaxX(theRect) - kIconLeadingPadding - NSWidth(imageRect) + inset |
| 398 : kIconLeadingPadding; |
| 395 return imageRect; | 399 return imageRect; |
| 396 } | 400 } |
| 397 | 401 |
| 398 - (CGFloat)textStartXOffset { | 402 - (NSRect)titleRectForBounds:(NSRect)theRect { |
| 399 return kIconLeftPadding + [[self image] size].width + kIconTextSpacer; | 403 NSRect textRect = [super titleRectForBounds:theRect]; |
| 404 NSRect imageRect = [self imageRectForBounds:theRect]; |
| 405 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { |
| 406 textRect.origin.x = kTrailingPadding; |
| 407 if (drawFolderArrow_) { |
| 408 textRect.origin.x += |
| 409 [arrowImage_ size].width + kHierarchyButtonTrailingPadding; |
| 410 } |
| 411 textRect.size.width = |
| 412 NSMinX(imageRect) - textRect.origin.x - kIconTextSpacer; |
| 413 } else { |
| 414 textRect.origin.x = NSMaxX(imageRect) + kIconTextSpacer; |
| 415 } |
| 416 return textRect; |
| 400 } | 417 } |
| 401 | 418 |
| 402 - (void)drawFocusRingMaskWithFrame:(NSRect)cellFrame | 419 - (void)drawFocusRingMaskWithFrame:(NSRect)cellFrame |
| 403 inView:(NSView*)controlView { | 420 inView:(NSView*)controlView { |
| 404 // We have to adjust the focus ring slightly for the chevron and regular | 421 // We have to adjust the focus ring slightly for the chevron and regular |
| 405 // bookmark icons. | 422 // bookmark icons. |
| 406 if ([self isOffTheSideButtonCell]) { | 423 if ([self isOffTheSideButtonCell]) { |
| 407 cellFrame.origin.y -= 2; | 424 cellFrame.origin.y -= 2; |
| 408 } else if ([self visibleTitle].length > 0) { | 425 } else if ([self visibleTitle].length > 0) { |
| 409 cellFrame.origin.x += 4; | 426 cellFrame.origin.x += 4; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 421 | 438 |
| 422 // If asked to do so, and if a folder, draw the arrow. | 439 // If asked to do so, and if a folder, draw the arrow. |
| 423 if (!drawFolderArrow_) | 440 if (!drawFolderArrow_) |
| 424 return; | 441 return; |
| 425 BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]); | 442 BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]); |
| 426 DCHECK([button respondsToSelector:@selector(isFolder)]); | 443 DCHECK([button respondsToSelector:@selector(isFolder)]); |
| 427 if ([button isFolder]) { | 444 if ([button isFolder]) { |
| 428 NSRect imageRect = NSZeroRect; | 445 NSRect imageRect = NSZeroRect; |
| 429 imageRect.size = [arrowImage_ size]; | 446 imageRect.size = [arrowImage_ size]; |
| 430 const CGFloat kArrowOffset = 1.0; // Required for proper centering. | 447 const CGFloat kArrowOffset = 1.0; // Required for proper centering. |
| 431 CGFloat dX = | 448 CGFloat dX = cocoa_l10n_util::ShouldDoExperimentalRTLLayout() |
| 432 NSWidth(cellFrame) - NSWidth(imageRect) - kHierarchyButtonRightPadding; | 449 ? kHierarchyButtonTrailingPadding |
| 450 : NSWidth(cellFrame) - NSWidth(imageRect) - |
| 451 kHierarchyButtonTrailingPadding; |
| 433 CGFloat dY = (NSHeight(cellFrame) / 2.0) - (NSHeight(imageRect) / 2.0) + | 452 CGFloat dY = (NSHeight(cellFrame) / 2.0) - (NSHeight(imageRect) / 2.0) + |
| 434 kArrowOffset; | 453 kArrowOffset; |
| 435 NSRect drawRect = NSOffsetRect(imageRect, dX, dY); | 454 NSRect drawRect = NSOffsetRect(imageRect, dX, dY); |
| 436 [arrowImage_ drawInRect:drawRect | 455 [arrowImage_ drawInRect:drawRect |
| 437 fromRect:imageRect | 456 fromRect:imageRect |
| 438 operation:NSCompositeSourceOver | 457 operation:NSCompositeSourceOver |
| 439 fraction:[self isEnabled] ? 1.0 : 0.5 | 458 fraction:[self isEnabled] ? 1.0 : 0.5 |
| 440 respectFlipped:YES | 459 respectFlipped:YES |
| 441 hints:nil]; | 460 hints:nil]; |
| 442 } | 461 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 470 | 489 |
| 471 // Returns |title| with newlines and line feeds replaced with | 490 // Returns |title| with newlines and line feeds replaced with |
| 472 // spaces. | 491 // spaces. |
| 473 + (NSString*)cleanTitle:(NSString*)title { | 492 + (NSString*)cleanTitle:(NSString*)title { |
| 474 title = [title stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; | 493 title = [title stringByReplacingOccurrencesOfString:@"\n" withString:@" "]; |
| 475 title = [title stringByReplacingOccurrencesOfString:@"\r" withString:@" "]; | 494 title = [title stringByReplacingOccurrencesOfString:@"\r" withString:@" "]; |
| 476 return title; | 495 return title; |
| 477 } | 496 } |
| 478 | 497 |
| 479 @end | 498 @end |
| OLD | NEW |