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