| 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 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" | 10 #import "chrome/browser/ui/cocoa/bookmarks/bookmark_button.h" |
| 10 #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" |
| 11 #include "chrome/grit/generated_resources.h" | 12 #include "chrome/grit/generated_resources.h" |
| 12 #import "components/bookmarks/browser/bookmark_model.h" | 13 #import "components/bookmarks/browser/bookmark_model.h" |
| 13 #include "content/public/browser/user_metrics.h" | 14 #include "content/public/browser/user_metrics.h" |
| 14 #include "ui/base/l10n/l10n_util_mac.h" | 15 #include "ui/base/l10n/l10n_util_mac.h" |
| 16 #include "ui/base/material_design/material_design_controller.h" |
| 15 #include "ui/base/resource/resource_bundle.h" | 17 #include "ui/base/resource/resource_bundle.h" |
| 16 #include "ui/resources/grit/ui_resources.h" | 18 #include "ui/resources/grit/ui_resources.h" |
| 17 | 19 |
| 18 using base::UserMetricsAction; | 20 using base::UserMetricsAction; |
| 19 using bookmarks::BookmarkNode; | 21 using bookmarks::BookmarkNode; |
| 20 | 22 |
| 23 namespace { |
| 24 |
| 21 const int kHierarchyButtonXMargin = 4; | 25 const int kHierarchyButtonXMargin = 4; |
| 26 const int kIconTextSpacer = 4; |
| 27 const int kTextRightPadding = 1; |
| 28 const int kIconLeftPadding = 3; |
| 29 |
| 30 const int kDefaultFontSize = 12; |
| 31 |
| 32 }; // namespace |
| 22 | 33 |
| 23 @interface BookmarkButtonCell(Private) | 34 @interface BookmarkButtonCell(Private) |
| 24 - (void)configureBookmarkButtonCell; | 35 - (void)configureBookmarkButtonCell; |
| 25 - (void)applyTextColor; | 36 - (void)applyTextColor; |
| 37 // Returns the title the button cell displays. Note that a button cell can |
| 38 // have a title string assigned but it won't be visible if its image position |
| 39 // is NSImageOnly. |
| 40 - (NSString*)visibleTitle; |
| 41 // Returns the dictionary of attributes to associate with the button title. |
| 42 - (NSDictionary*)titleTextAttributes; |
| 26 @end | 43 @end |
| 27 | 44 |
| 28 | 45 |
| 29 @implementation BookmarkButtonCell | 46 @implementation BookmarkButtonCell |
| 30 | 47 |
| 31 @synthesize startingChildIndex = startingChildIndex_; | 48 @synthesize startingChildIndex = startingChildIndex_; |
| 32 @synthesize drawFolderArrow = drawFolderArrow_; | 49 @synthesize drawFolderArrow = drawFolderArrow_; |
| 33 | 50 |
| 34 + (id)buttonCellForNode:(const BookmarkNode*)node | 51 + (id)buttonCellForNode:(const BookmarkNode*)node |
| 35 text:(NSString*)text | 52 text:(NSString*)text |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 [self configureBookmarkButtonCell]; | 131 [self configureBookmarkButtonCell]; |
| 115 } | 132 } |
| 116 | 133 |
| 117 - (BOOL)isFolderButtonCell { | 134 - (BOOL)isFolderButtonCell { |
| 118 return NO; | 135 return NO; |
| 119 } | 136 } |
| 120 | 137 |
| 121 // Perform all normal init routines specific to the BookmarkButtonCell. | 138 // Perform all normal init routines specific to the BookmarkButtonCell. |
| 122 - (void)configureBookmarkButtonCell { | 139 - (void)configureBookmarkButtonCell { |
| 123 [self setButtonType:NSMomentaryPushInButton]; | 140 [self setButtonType:NSMomentaryPushInButton]; |
| 124 [self setBezelStyle:NSShadowlessSquareBezelStyle]; | |
| 125 [self setShowsBorderOnlyWhileMouseInside:YES]; | 141 [self setShowsBorderOnlyWhileMouseInside:YES]; |
| 126 [self setControlSize:NSSmallControlSize]; | 142 [self setControlSize:NSSmallControlSize]; |
| 127 [self setAlignment:NSLeftTextAlignment]; | 143 [self setAlignment:NSLeftTextAlignment]; |
| 128 [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; | 144 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 145 [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]]; |
| 146 [self setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 147 } else { |
| 148 [self setFont:[NSFont systemFontOfSize:kDefaultFontSize]]; |
| 149 [self setBordered:NO]; |
| 150 [self setBezeled:NO]; |
| 151 } |
| 129 [self setWraps:NO]; | 152 [self setWraps:NO]; |
| 130 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's | 153 // NSLineBreakByTruncatingMiddle seems more common on OSX but let's |
| 131 // try to match Windows for a bit to see what happens. | 154 // try to match Windows for a bit to see what happens. |
| 132 [self setLineBreakMode:NSLineBreakByTruncatingTail]; | 155 [self setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 133 | 156 |
| 134 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled | 157 // The overflow button chevron bitmap is not 16 units high, so it'd be scaled |
| 135 // at paint time without this. | 158 // at paint time without this. |
| 136 [self setImageScaling:NSImageScaleNone]; | 159 [self setImageScaling:NSImageScaleNone]; |
| 137 | 160 |
| 138 // Theming doesn't work for bookmark buttons yet (cell text is chucked). | 161 // Theming doesn't work for bookmark buttons yet (cell text is chucked). |
| 139 [super setShouldTheme:NO]; | 162 [super setShouldTheme:NO]; |
| 140 } | 163 } |
| 141 | 164 |
| 142 - (BOOL)empty { | 165 - (BOOL)empty { |
| 143 return empty_; | 166 return empty_; |
| 144 } | 167 } |
| 145 | 168 |
| 146 - (void)setEmpty:(BOOL)empty { | 169 - (void)setEmpty:(BOOL)empty { |
| 147 empty_ = empty; | 170 empty_ = empty; |
| 148 [self setShowsBorderOnlyWhileMouseInside:!empty]; | 171 [self setShowsBorderOnlyWhileMouseInside:!empty]; |
| 149 } | 172 } |
| 150 | 173 |
| 151 - (NSSize)cellSizeForBounds:(NSRect)aRect { | 174 - (NSSize)cellSizeForBounds:(NSRect)aRect { |
| 175 // There's no bezel or border in Material Design so return cellSize. |
| 176 if (ui::MaterialDesignController::IsModeMaterial()) { |
| 177 NSSize size = [self cellSize]; |
| 178 size.width = std::min(aRect.size.width, size.width); |
| 179 size.height = std::min(aRect.size.height, size.height); |
| 180 return size; |
| 181 } |
| 152 NSSize size = [super cellSizeForBounds:aRect]; | 182 NSSize size = [super cellSizeForBounds:aRect]; |
| 153 // Cocoa seems to slightly underestimate how much space we need, so we | 183 // Cocoa seems to slightly underestimate how much space we need, so we |
| 154 // compensate here to avoid a clipped rendering. | 184 // compensate here to avoid a clipped rendering. |
| 155 size.width += 2; | 185 size.width += 2; |
| 156 size.height += 4; | 186 size.height += 4; |
| 157 return size; | 187 return size; |
| 158 } | 188 } |
| 159 | 189 |
| 160 - (void)setBookmarkCellText:(NSString*)title | 190 - (void)setBookmarkCellText:(NSString*)title |
| 161 image:(NSImage*)image { | 191 image:(NSImage*)image { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 | 245 |
| 216 - (void)setTextColor:(NSColor*)color { | 246 - (void)setTextColor:(NSColor*)color { |
| 217 if ([textColor_ isEqualTo:color]) | 247 if ([textColor_ isEqualTo:color]) |
| 218 return; | 248 return; |
| 219 textColor_.reset([color copy]); | 249 textColor_.reset([color copy]); |
| 220 [self applyTextColor]; | 250 [self applyTextColor]; |
| 221 } | 251 } |
| 222 | 252 |
| 223 // We must reapply the text color after any setTitle: call | 253 // We must reapply the text color after any setTitle: call |
| 224 - (void)applyTextColor { | 254 - (void)applyTextColor { |
| 225 base::scoped_nsobject<NSMutableParagraphStyle> style( | |
| 226 [NSMutableParagraphStyle new]); | |
| 227 [style setAlignment:NSLeftTextAlignment]; | |
| 228 NSDictionary* dict = [NSDictionary | |
| 229 dictionaryWithObjectsAndKeys:textColor_, | |
| 230 NSForegroundColorAttributeName, | |
| 231 [self font], NSFontAttributeName, | |
| 232 style.get(), NSParagraphStyleAttributeName, | |
| 233 [NSNumber numberWithFloat:0.2], NSKernAttributeName, | |
| 234 nil]; | |
| 235 base::scoped_nsobject<NSAttributedString> ats( | 255 base::scoped_nsobject<NSAttributedString> ats( |
| 236 [[NSAttributedString alloc] initWithString:[self title] attributes:dict]); | 256 [[NSAttributedString alloc] initWithString:[self title] |
| 257 attributes:[self titleTextAttributes]]); |
| 237 [self setAttributedTitle:ats.get()]; | 258 [self setAttributedTitle:ats.get()]; |
| 238 } | 259 } |
| 239 | 260 |
| 240 // To implement "hover open a bookmark button to open the folder" | 261 // To implement "hover open a bookmark button to open the folder" |
| 241 // which feels like menus, we override NSButtonCell's mouseEntered: | 262 // which feels like menus, we override NSButtonCell's mouseEntered: |
| 242 // and mouseExited:, then and pass them along to our owning control. | 263 // and mouseExited:, then and pass them along to our owning control. |
| 243 // Note: as verified in a debugger, mouseEntered: does NOT increase | 264 // Note: as verified in a debugger, mouseEntered: does NOT increase |
| 244 // the retainCount of the cell or its owning control. | 265 // the retainCount of the cell or its owning control. |
| 245 - (void)mouseEntered:(NSEvent*)event { | 266 - (void)mouseEntered:(NSEvent*)event { |
| 246 [super mouseEntered:event]; | 267 [super mouseEntered:event]; |
| 247 [[self controlView] mouseEntered:event]; | 268 [[self controlView] mouseEntered:event]; |
| 248 } | 269 } |
| 249 | 270 |
| 250 // See comment above mouseEntered:, above. | 271 // See comment above mouseEntered:, above. |
| 251 - (void)mouseExited:(NSEvent*)event { | 272 - (void)mouseExited:(NSEvent*)event { |
| 252 [[self controlView] mouseExited:event]; | 273 [[self controlView] mouseExited:event]; |
| 253 [super mouseExited:event]; | 274 [super mouseExited:event]; |
| 254 } | 275 } |
| 255 | 276 |
| 256 - (void)setDrawFolderArrow:(BOOL)draw { | 277 - (void)setDrawFolderArrow:(BOOL)draw { |
| 257 drawFolderArrow_ = draw; | 278 drawFolderArrow_ = draw; |
| 258 if (draw && !arrowImage_) { | 279 if (draw && !arrowImage_) { |
| 259 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 280 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 260 arrowImage_.reset( | 281 arrowImage_.reset( |
| 261 [rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage() retain]); | 282 [rb.GetNativeImageNamed(IDR_MENU_HIERARCHY_ARROW).ToNSImage() retain]); |
| 262 } | 283 } |
| 263 } | 284 } |
| 264 | 285 |
| 286 - (NSDictionary*)titleTextAttributes { |
| 287 base::scoped_nsobject<NSMutableParagraphStyle> style( |
| 288 [NSMutableParagraphStyle new]); |
| 289 [style setAlignment:NSNaturalTextAlignment]; |
| 290 [style setLineBreakMode:NSLineBreakByTruncatingTail]; |
| 291 NSColor* textColor = textColor_.get(); |
| 292 if (!textColor) { |
| 293 textColor = [NSColor blackColor]; |
| 294 } |
| 295 if (![self isEnabled]) { |
| 296 textColor = [textColor colorWithAlphaComponent:0.5]; |
| 297 } |
| 298 NSFont* theFont = [self font]; |
| 299 if (!theFont) { |
| 300 theFont = [NSFont systemFontOfSize:kDefaultFontSize]; |
| 301 } |
| 302 |
| 303 return @{ |
| 304 NSFontAttributeName : theFont, |
| 305 NSForegroundColorAttributeName : textColor, |
| 306 NSParagraphStyleAttributeName : style.get(), |
| 307 NSKernAttributeName : [NSNumber numberWithFloat:0.2] |
| 308 }; |
| 309 } |
| 310 |
| 311 - (NSString*)visibleTitle { |
| 312 return [self imagePosition] != NSImageOnly ? [self title] : @""; |
| 313 } |
| 314 |
| 265 // Add extra size for the arrow so it doesn't overlap the text. | 315 // Add extra size for the arrow so it doesn't overlap the text. |
| 266 // Does not sanity check to be sure this is actually a folder node. | 316 // Does not sanity check to be sure this is actually a folder node. |
| 267 - (NSSize)cellSize { | 317 - (NSSize)cellSize { |
| 268 NSSize cellSize = [super cellSize]; | 318 NSSize cellSize = NSZeroSize; |
| 319 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 320 cellSize = [super cellSize]; |
| 321 } else { |
| 322 // Return the space needed to display the image and title, with a little |
| 323 // distance between them. |
| 324 cellSize = NSMakeSize(kIconLeftPadding + [[self image] size].width, |
| 325 bookmarks::kMaterialBookmarkButtonHeight); |
| 326 NSString* title = [self visibleTitle]; |
| 327 if ([title length] > 0) { |
| 328 CGFloat textWidth = |
| 329 [title sizeWithAttributes:[self titleTextAttributes]].width; |
| 330 cellSize.width += |
| 331 kIconTextSpacer + std::ceil(textWidth) + kTextRightPadding; |
| 332 } |
| 333 } |
| 334 |
| 269 if (drawFolderArrow_) { | 335 if (drawFolderArrow_) { |
| 270 cellSize.width += [arrowImage_ size].width + 2 * kHierarchyButtonXMargin; | 336 cellSize.width += [arrowImage_ size].width + 2 * kHierarchyButtonXMargin; |
| 271 } | 337 } |
| 272 return cellSize; | 338 return cellSize; |
| 273 } | 339 } |
| 274 | 340 |
| 341 - (NSRect)imageRectForBounds:(NSRect)theRect { |
| 342 NSRect imageRect = [super imageRectForBounds:theRect]; |
| 343 // In Material Design, add a little space between the image and the button's |
| 344 // left edge, but only if there's a visible title. |
| 345 if ([[self visibleTitle] length] && |
| 346 ui::MaterialDesignController::IsModeMaterial()) { |
| 347 imageRect.origin.x += kIconLeftPadding; |
| 348 } |
| 349 return imageRect; |
| 350 } |
| 351 |
| 352 - (CGFloat)textStartXOffset { |
| 353 if (!ui::MaterialDesignController::IsModeMaterial()) { |
| 354 return [super textStartXOffset]; |
| 355 } |
| 356 return kIconLeftPadding + [[self image] size].width + kIconTextSpacer; |
| 357 } |
| 358 |
| 275 // Override cell drawing to add a submenu arrow like a real menu. | 359 // Override cell drawing to add a submenu arrow like a real menu. |
| 276 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { | 360 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { |
| 277 // First draw "everything else". | 361 // First draw "everything else". |
| 278 [super drawInteriorWithFrame:cellFrame inView:controlView]; | 362 [super drawInteriorWithFrame:cellFrame inView:controlView]; |
| 279 | 363 |
| 280 // If asked to do so, and if a folder, draw the arrow. | 364 // If asked to do so, and if a folder, draw the arrow. |
| 281 if (!drawFolderArrow_) | 365 if (!drawFolderArrow_) |
| 282 return; | 366 return; |
| 283 BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]); | 367 BookmarkButton* button = static_cast<BookmarkButton*>([self controlView]); |
| 284 DCHECK([button respondsToSelector:@selector(isFolder)]); | 368 DCHECK([button respondsToSelector:@selector(isFolder)]); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 298 respectFlipped:YES | 382 respectFlipped:YES |
| 299 hints:nil]; | 383 hints:nil]; |
| 300 } | 384 } |
| 301 } | 385 } |
| 302 | 386 |
| 303 - (int)verticalTextOffset { | 387 - (int)verticalTextOffset { |
| 304 return 0; | 388 return 0; |
| 305 } | 389 } |
| 306 | 390 |
| 307 @end | 391 @end |
| OLD | NEW |