| 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" |
| 11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controlle
r.h" | 11 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_context_menu_cocoa_controlle
r.h" |
| 12 #include "chrome/browser/ui/cocoa/l10n_util.h" |
| 12 #include "chrome/grit/generated_resources.h" | 13 #include "chrome/grit/generated_resources.h" |
| 13 #import "components/bookmarks/browser/bookmark_model.h" | 14 #import "components/bookmarks/browser/bookmark_model.h" |
| 14 #include "content/public/browser/user_metrics.h" | 15 #include "content/public/browser/user_metrics.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 kTextTrailingPadding = 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 }; // namespace | 39 }; // namespace |
| 39 | 40 |
| 40 @interface OffTheSideButtonCell : BookmarkButtonCell | 41 @interface OffTheSideButtonCell : BookmarkButtonCell |
| 41 | 42 |
| 42 - (NSString*)accessibilityTitle; | 43 - (NSString*)accessibilityTitle; |
| 43 | 44 |
| 44 @end | 45 @end |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 | 172 |
| 172 - (BOOL)isOffTheSideButtonCell { | 173 - (BOOL)isOffTheSideButtonCell { |
| 173 return NO; | 174 return NO; |
| 174 } | 175 } |
| 175 | 176 |
| 176 // Perform all normal init routines specific to the BookmarkButtonCell. | 177 // Perform all normal init routines specific to the BookmarkButtonCell. |
| 177 - (void)configureBookmarkButtonCell { | 178 - (void)configureBookmarkButtonCell { |
| 178 [self setButtonType:NSMomentaryPushInButton]; | 179 [self setButtonType:NSMomentaryPushInButton]; |
| 179 [self setShowsBorderOnlyWhileMouseInside:YES]; | 180 [self setShowsBorderOnlyWhileMouseInside:YES]; |
| 180 [self setControlSize:NSSmallControlSize]; | 181 [self setControlSize:NSSmallControlSize]; |
| 181 [self setAlignment:NSLeftTextAlignment]; | 182 [self setAlignment:NSNaturalTextAlignment]; |
| 182 [self setFont:[NSFont systemFontOfSize:kDefaultFontSize]]; | 183 [self setFont:[NSFont systemFontOfSize:kDefaultFontSize]]; |
| 183 [self setBordered:NO]; | 184 [self setBordered:NO]; |
| 184 [self setBezeled:NO]; | 185 [self setBezeled:NO]; |
| 185 [self setWraps:NO]; | 186 [self setWraps:NO]; |
| 186 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's | 187 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's |
| 187 // try to match Windows for a bit to see what happens. | 188 // try to match Windows for a bit to see what happens. |
| 188 [self setLineBreakMode:NSLineBreakByTruncatingTail]; | 189 [self setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 189 | 190 |
| 190 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled | 191 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled |
| 191 // at paint time without this. | 192 // at paint time without this. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 213 } | 214 } |
| 214 | 215 |
| 215 - (void)setBookmarkCellText:(NSString*)title | 216 - (void)setBookmarkCellText:(NSString*)title |
| 216 image:(NSImage*)image { | 217 image:(NSImage*)image { |
| 217 title = [title stringByReplacingOccurrencesOfString:@"\n" | 218 title = [title stringByReplacingOccurrencesOfString:@"\n" |
| 218 withString:@" "]; | 219 withString:@" "]; |
| 219 title = [title stringByReplacingOccurrencesOfString:@"\r" | 220 title = [title stringByReplacingOccurrencesOfString:@"\r" |
| 220 withString:@" "]; | 221 withString:@" "]; |
| 221 | 222 |
| 222 if ([title length]) { | 223 if ([title length]) { |
| 223 [self setImagePosition:NSImageLeft]; | 224 [self setImagePosition:cocoa_l10n_util::LeadingCellImagePosition()]; |
| 224 [self setTitle:title]; | 225 [self setTitle:title]; |
| 225 } else if ([self isFolderButtonCell]) { | 226 } else if ([self isFolderButtonCell]) { |
| 226 // Left-align icons for bookmarks within folders, regardless of whether | 227 // Left-align icons for bookmarks within folders, regardless of whether |
| 227 // there is a title. | 228 // there is a title. |
| 228 [self setImagePosition:NSImageLeft]; | 229 [self setImagePosition:cocoa_l10n_util::LeadingCellImagePosition()]; |
| 229 } else { | 230 } else { |
| 230 // For bookmarks without a title that aren't visible directly in the | 231 // For bookmarks without a title that aren't visible directly in the |
| 231 // bookmarks bar, squeeze things tighter by displaying only the image. | 232 // bookmarks bar, squeeze things tighter by displaying only the image. |
| 232 // By default, Cocoa leaves extra space in an attempt to display an | 233 // By default, Cocoa leaves extra space in an attempt to display an |
| 233 // empty title. | 234 // empty title. |
| 234 [self setImagePosition:NSImageOnly]; | 235 [self setImagePosition:NSImageOnly]; |
| 235 } | 236 } |
| 236 | 237 |
| 237 if (image) | 238 if (image) |
| 238 [self setImage:image]; | 239 [self setImage:image]; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 // See comment above mouseEntered:, above. | 297 // See comment above mouseEntered:, above. |
| 297 - (void)mouseExited:(NSEvent*)event { | 298 - (void)mouseExited:(NSEvent*)event { |
| 298 [[self controlView] mouseExited:event]; | 299 [[self controlView] mouseExited:event]; |
| 299 [super mouseExited:event]; | 300 [super mouseExited:event]; |
| 300 } | 301 } |
| 301 | 302 |
| 302 - (void)setDrawFolderArrow:(BOOL)draw { | 303 - (void)setDrawFolderArrow:(BOOL)draw { |
| 303 drawFolderArrow_ = draw; | 304 drawFolderArrow_ = draw; |
| 304 if (draw && !arrowImage_) { | 305 if (draw && !arrowImage_) { |
| 305 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 306 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 306 arrowImage_.reset( | 307 NSImage* image = |
| 307 [rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage() retain]); | 308 rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage(); |
| 309 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) |
| 310 image = cocoa_l10n_util::FlippedImage(image); |
| 311 arrowImage_.reset([image retain]); |
| 308 } | 312 } |
| 309 } | 313 } |
| 310 | 314 |
| 311 - (NSDictionary*)titleTextAttributes { | 315 - (NSDictionary*)titleTextAttributes { |
| 312 base::scoped_nsobject<NSMutableParagraphStyle> style( | 316 base::scoped_nsobject<NSMutableParagraphStyle> style( |
| 313 [NSMutableParagraphStyle new]); | 317 [NSMutableParagraphStyle new]); |
| 314 [style setAlignment:NSNaturalTextAlignment]; | 318 [style setAlignment:NSNaturalTextAlignment]; |
| 315 [style setLineBreakMode:NSLineBreakByTruncatingTail]; | 319 [style setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 316 NSColor* textColor = textColor_.get(); | 320 NSColor* textColor = textColor_.get(); |
| 317 if (!textColor) { | 321 if (!textColor) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 336 - (NSString*)visibleTitle { | 340 - (NSString*)visibleTitle { |
| 337 return [self imagePosition] != NSImageOnly ? [self title] : @""; | 341 return [self imagePosition] != NSImageOnly ? [self title] : @""; |
| 338 } | 342 } |
| 339 | 343 |
| 340 // Add extra size for the arrow so it doesn't overlap the text. | 344 // Add extra size for the arrow so it doesn't overlap the text. |
| 341 // Does not sanity check to be sure this is actually a folder node. | 345 // Does not sanity check to be sure this is actually a folder node. |
| 342 - (NSSize)cellSize { | 346 - (NSSize)cellSize { |
| 343 NSSize cellSize = NSZeroSize; | 347 NSSize cellSize = NSZeroSize; |
| 344 // Return the space needed to display the image and title, with a little | 348 // Return the space needed to display the image and title, with a little |
| 345 // distance between them. | 349 // distance between them. |
| 346 cellSize = NSMakeSize(kIconLeftPadding + [[self image] size].width, | 350 cellSize = NSMakeSize(kIconLeadingPadding + [[self image] size].width, |
| 347 bookmarks::kBookmarkButtonHeight); | 351 bookmarks::kBookmarkButtonHeight); |
| 348 NSString* title = [self visibleTitle]; | 352 NSString* title = [self visibleTitle]; |
| 349 if ([title length] > 0) { | 353 if ([title length] > 0) { |
| 350 CGFloat textWidth = | 354 CGFloat textWidth = |
| 351 [title sizeWithAttributes:[self titleTextAttributes]].width; | 355 [title sizeWithAttributes:[self titleTextAttributes]].width; |
| 352 cellSize.width += | 356 cellSize.width += |
| 353 kIconTextSpacer + std::ceil(textWidth) + kTextRightPadding; | 357 kIconTextSpacer + std::ceil(textWidth) + kTextTrailingPadding; |
| 354 } else { | 358 } else { |
| 355 // Make buttons without visible titles 20pts wide (18 plus padding). | 359 // Make buttons without visible titles 20pts wide (18 plus padding). |
| 356 cellSize.width += kIconLeftPadding; | 360 cellSize.width += kIconLeadingPadding; |
| 357 } | 361 } |
| 358 | 362 |
| 359 if (drawFolderArrow_) { | 363 if (drawFolderArrow_) { |
| 360 cellSize.width += [arrowImage_ size].width + | 364 cellSize.width += [arrowImage_ size].width + |
| 361 kHierarchyButtonLeftPadding + | 365 kHierarchyButtonLeadingPadding + |
| 362 kHierarchyButtonRightPadding; | 366 kHierarchyButtonTrailingPadding; |
| 363 } | 367 } |
| 368 cellSize.width += [self insetInView:[self controlView]] * 2; |
| 364 return cellSize; | 369 return cellSize; |
| 365 } | 370 } |
| 366 | 371 |
| 367 - (NSRect)imageRectForBounds:(NSRect)theRect { | 372 - (NSRect)imageRectForBounds:(NSRect)theRect { |
| 368 NSRect imageRect = [super imageRectForBounds:theRect]; | 373 NSRect imageRect = [super imageRectForBounds:theRect]; |
| 369 // Add a little space between the image and the button's left edge, but only | 374 const CGFloat inset = [self insetInView:[self controlView]]; |
| 370 // if there's a visible title. | 375 imageRect.origin.y -= inset; |
| 371 imageRect.origin.y -= 1; | 376 imageRect.origin.x = |
| 372 imageRect.origin.x = kIconLeftPadding; | 377 cocoa_l10n_util::ShouldDoExperimentalRTLLayout() |
| 378 ? NSMaxX(theRect) - kIconLeadingPadding - NSWidth(imageRect) |
| 379 : kIconLeadingPadding + inset; |
| 373 return imageRect; | 380 return imageRect; |
| 374 } | 381 } |
| 375 | 382 |
| 376 - (CGFloat)textStartXOffset { | 383 - (NSRect)titleRectForBounds:(NSRect)theRect { |
| 377 return kIconLeftPadding + [[self image] size].width + kIconTextSpacer; | 384 NSRect textRect = [super titleRectForBounds:theRect]; |
| 385 NSRect imageRect = [self imageRectForBounds:theRect]; |
| 386 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) { |
| 387 textRect.origin.x = drawFolderArrow_ |
| 388 ? [arrowImage_ size].width + |
| 389 kHierarchyButtonTrailingPadding + |
| 390 kTextTrailingPadding |
| 391 : kTextTrailingPadding; |
| 392 textRect.origin.x += [self insetInView:[self controlView]]; |
| 393 textRect.size.width = |
| 394 NSMinX(imageRect) - textRect.origin.x - kIconTextSpacer; |
| 395 } else { |
| 396 textRect.origin.x = NSMaxX(imageRect) + kIconTextSpacer; |
| 397 } |
| 398 return textRect; |
| 378 } | 399 } |
| 379 | 400 |
| 380 - (void)drawFocusRingMaskWithFrame:(NSRect)cellFrame | 401 - (void)drawFocusRingMaskWithFrame:(NSRect)cellFrame |
| 381 inView:(NSView*)controlView { | 402 inView:(NSView*)controlView { |
| 382 // We have to adjust the focus ring slightly for the chevron and regular | 403 // We have to adjust the focus ring slightly for the chevron and regular |
| 383 // bookmark icons. | 404 // bookmark icons. |
| 384 if ([self isOffTheSideButtonCell]) { | 405 if ([self isOffTheSideButtonCell]) { |
| 385 cellFrame.origin.y -= 2; | 406 cellFrame.origin.y -= 2; |
| 386 } else if ([self visibleTitle].length > 0) { | 407 } else if ([self visibleTitle].length > 0) { |
| 387 cellFrame.origin.x += 4; | 408 cellFrame.origin.x += 4; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 399 | 420 |
| 400 // If asked to do so, and if a folder, draw the arrow. | 421 // If asked to do so, and if a folder, draw the arrow. |
| 401 if (!drawFolderArrow_) | 422 if (!drawFolderArrow_) |
| 402 return; | 423 return; |
| 403 BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]); | 424 BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]); |
| 404 DCHECK([button respondsToSelector:@selector(isFolder)]); | 425 DCHECK([button respondsToSelector:@selector(isFolder)]); |
| 405 if ([button isFolder]) { | 426 if ([button isFolder]) { |
| 406 NSRect imageRect = NSZeroRect; | 427 NSRect imageRect = NSZeroRect; |
| 407 imageRect.size = [arrowImage_ size]; | 428 imageRect.size = [arrowImage_ size]; |
| 408 const CGFloat kArrowOffset = 1.0; // Required for proper centering. | 429 const CGFloat kArrowOffset = 1.0; // Required for proper centering. |
| 409 CGFloat dX = | 430 CGFloat dX = cocoa_l10n_util::ShouldDoExperimentalRTLLayout() |
| 410 NSWidth(cellFrame) - NSWidth(imageRect) - kHierarchyButtonRightPadding; | 431 ? kHierarchyButtonTrailingPadding |
| 432 : NSWidth(cellFrame) - NSWidth(imageRect) - |
| 433 kHierarchyButtonTrailingPadding; |
| 411 CGFloat dY = (NSHeight(cellFrame) / 2.0) - (NSHeight(imageRect) / 2.0) + | 434 CGFloat dY = (NSHeight(cellFrame) / 2.0) - (NSHeight(imageRect) / 2.0) + |
| 412 kArrowOffset; | 435 kArrowOffset; |
| 413 NSRect drawRect = NSOffsetRect(imageRect, dX, dY); | 436 NSRect drawRect = NSOffsetRect(imageRect, dX, dY); |
| 414 [arrowImage_ drawInRect:drawRect | 437 [arrowImage_ drawInRect:drawRect |
| 415 fromRect:imageRect | 438 fromRect:imageRect |
| 416 operation:NSCompositeSourceOver | 439 operation:NSCompositeSourceOver |
| 417 fraction:[self isEnabled] ? 1.0 : 0.5 | 440 fraction:[self isEnabled] ? 1.0 : 0.5 |
| 418 respectFlipped:YES | 441 respectFlipped:YES |
| 419 hints:nil]; | 442 hints:nil]; |
| 420 } | 443 } |
| 421 } | 444 } |
| 422 | 445 |
| 423 - (int)verticalTextOffset { | 446 - (int)verticalTextOffset { |
| 424 return -1; | 447 return -1; |
| 425 } | 448 } |
| 426 | 449 |
| 427 - (CGFloat)hoverBackgroundVerticalOffsetInControlView:(NSView*)controlView { | 450 - (CGFloat)hoverBackgroundVerticalOffsetInControlView:(NSView*)controlView { |
| 428 // In Material Design on Retina, and not in a folder menu, nudge the hover | 451 // In Material Design on Retina, and not in a folder menu, nudge the hover |
| 429 // background by 1px. | 452 // background by 1px. |
| 430 const CGFloat kLineWidth = [controlView cr_lineWidth]; | 453 const CGFloat kLineWidth = [controlView cr_lineWidth]; |
| 431 if ([self isMaterialDesignButtonType] && ![self isFolderButtonCell] && | 454 if ([self isMaterialDesignButtonType] && ![self isFolderButtonCell] && |
| 432 kLineWidth < 1) { | 455 kLineWidth < 1) { |
| 433 return -kLineWidth; | 456 return -kLineWidth; |
| 434 } | 457 } |
| 435 return 0.0; | 458 return 0.0; |
| 436 } | 459 } |
| 437 | 460 |
| 438 | 461 |
| 439 @end | 462 @end |
| OLD | NEW |