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 |