| 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/toolbar/toolbar_button_cocoa.h" | 5 #import "chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.h" |
| 6 | 6 |
| 7 #include "base/mac/foundation_util.h" |
| 8 #include "base/mac/sdk_forward_declarations.h" |
| 9 #import "chrome/browser/ui/cocoa/image_button_cell.h" |
| 10 #import "chrome/browser/ui/cocoa/themed_window.h" |
| 11 #import "chrome/browser/ui/cocoa/view_id_util.h" |
| 12 #include "skia/ext/skia_utils_mac.h" |
| 13 #import "ui/base/cocoa/nsview_additions.h" |
| 14 #include "ui/base/material_design/material_design_controller.h" |
| 15 #include "ui/base/theme_provider.h" |
| 16 #include "ui/gfx/image/image_skia_util_mac.h" |
| 17 #include "ui/gfx/paint_vector_icon.h" |
| 18 |
| 19 namespace { |
| 20 |
| 21 // The bounds of toolbar buttons in Material Design. |
| 22 const NSRect kMDButtonBounds = NSMakeRect(0, 0, 28, 28); |
| 23 |
| 24 // The size of a toolbar button icon in Material Design. A toolbar button image |
| 25 // consists of a border and background, with a centered icon. |
| 26 const NSSize kMDButtonIconSize = NSMakeSize(16, 16); |
| 27 |
| 28 } // namespace |
| 29 |
| 30 // An NSCustomImageRep subclass that creates the "three dots" image of the |
| 31 // Material Design browser tools icon. |
| 32 @interface BrowserToolsImageRep : NSCustomImageRep |
| 33 @property (retain, nonatomic) NSColor* fillColor; |
| 34 // NSCustomImageRep delegate method that performs the drawing. |
| 35 + (void)drawBrowserToolsIcon:(BrowserToolsImageRep*)imageRep; |
| 36 @end |
| 37 |
| 38 @implementation BrowserToolsImageRep |
| 39 |
| 40 @synthesize fillColor = fillColor_; |
| 41 |
| 42 - (void)dealloc { |
| 43 [fillColor_ release]; |
| 44 [super dealloc]; |
| 45 } |
| 46 |
| 47 + (void)drawBrowserToolsIcon:(BrowserToolsImageRep*)imageRep { |
| 48 [imageRep.fillColor set]; |
| 49 NSBezierPath* dotPath = |
| 50 [NSBezierPath bezierPathWithOvalInRect:NSMakeRect(6.5, 1.5, 3, 3)]; |
| 51 CGContextRef context = static_cast<CGContextRef>( |
| 52 [[NSGraphicsContext currentContext] graphicsPort]); |
| 53 // Draw the three dots by drawing |dotPath| in three different locations. |
| 54 for (NSUInteger i = 0; i < 3; i++) { |
| 55 [dotPath fill]; |
| 56 CGContextTranslateCTM(context, 0, 5); |
| 57 } |
| 58 } |
| 59 |
| 60 @end |
| 61 |
| 62 // An NSCustomImageRep subclass that draws a Material Design background behind |
| 63 // and border around a centered icon image. |
| 64 @interface ToolbarButtonImageRep : NSCustomImageRep |
| 65 @property (retain, nonatomic) NSImage* icon; |
| 66 @property (assign, nonatomic) ToolbarButtonImageBackgroundStyle style; |
| 67 // NSCustomImageRep delegate method that performs the drawing. |
| 68 + (void)drawImage:(ToolbarButtonImageRep*)imageRep; |
| 69 @end |
| 70 |
| 71 @implementation ToolbarButtonImageRep |
| 72 |
| 73 @synthesize icon = icon_; |
| 74 @synthesize style = style_; |
| 75 |
| 76 - (void)dealloc { |
| 77 [icon_ release]; |
| 78 [super dealloc]; |
| 79 } |
| 80 |
| 81 + (void)drawImage:(ToolbarButtonImageRep*)imageRep { |
| 82 // Create the path used for the background fill. |
| 83 NSRect destRect = NSInsetRect(kMDButtonBounds, 2, 2); |
| 84 NSBezierPath* roundedRectPath = |
| 85 [NSBezierPath bezierPathWithRoundedRect:destRect xRadius:2 yRadius:2]; |
| 86 |
| 87 // Determine the fill color. |
| 88 NSColor* fillColor = nil; |
| 89 switch (imageRep.style) { |
| 90 case ToolbarButtonImageBackgroundStyle::HOVER: |
| 91 fillColor = [NSColor colorWithCalibratedWhite:0 alpha:0.08]; |
| 92 break; |
| 93 case ToolbarButtonImageBackgroundStyle::HOVER_THEMED: |
| 94 fillColor = [NSColor colorWithCalibratedWhite:1 alpha:0.08]; |
| 95 break; |
| 96 case ToolbarButtonImageBackgroundStyle::PRESSED: |
| 97 fillColor = [NSColor colorWithCalibratedWhite:0 alpha:0.12]; |
| 98 break; |
| 99 case ToolbarButtonImageBackgroundStyle::PRESSED_THEMED: |
| 100 fillColor = [NSColor colorWithCalibratedWhite:1 alpha:0.12]; |
| 101 break; |
| 102 } |
| 103 |
| 104 // Fill the path. |
| 105 [fillColor set]; |
| 106 [roundedRectPath fill]; |
| 107 |
| 108 // Compute the icon's location and draw it there. |
| 109 CGFloat iconInset = |
| 110 (kMDButtonBounds.size.width - kMDButtonIconSize.width) / 2; |
| 111 NSRect iconDestRect = NSInsetRect(kMDButtonBounds, iconInset, iconInset); |
| 112 [imageRep.icon drawInRect:iconDestRect |
| 113 fromRect:NSZeroRect |
| 114 operation:NSCompositeSourceOver |
| 115 fraction:1]; |
| 116 } |
| 117 |
| 118 @end |
| 119 |
| 120 @interface ToolbarButton () |
| 121 // Returns an image that draws the browser tools button icon using vector |
| 122 // commands. |
| 123 - (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor; |
| 124 // Returns an button image by combining |iconImage| with the specified button |
| 125 // background. |
| 126 - (NSImage*)imageForIcon:(NSImage*)iconImage |
| 127 withBackgroundStyle:(ToolbarButtonImageBackgroundStyle)style; |
| 128 // Creates and assigns images for the button's various states (pressed, hover, |
| 129 // etc.). |
| 130 - (void)setImagesFromIconId:(gfx::VectorIconId)iconId; |
| 131 // Implemented to set the button's icon when added to the browser window. We |
| 132 // can't set the image before this because its appearance depends upon the |
| 133 // browser window's theme. |
| 134 - (void)viewDidMoveToWindow; |
| 135 |
| 136 @end |
| 137 |
| 138 |
| 7 @implementation ToolbarButton | 139 @implementation ToolbarButton |
| 8 | 140 |
| 9 @synthesize handleMiddleClick = handleMiddleClick_; | 141 @synthesize handleMiddleClick = handleMiddleClick_; |
| 10 | 142 |
| 11 - (void)otherMouseDown:(NSEvent*)theEvent { | 143 - (void)otherMouseDown:(NSEvent*)theEvent { |
| 12 if (![self shouldHandleEvent:theEvent]) { | 144 if (![self shouldHandleEvent:theEvent]) { |
| 13 [super otherMouseDown:theEvent]; | 145 [super otherMouseDown:theEvent]; |
| 14 return; | 146 return; |
| 15 } | 147 } |
| 16 | 148 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 return handleMiddleClick_ && [theEvent buttonNumber] == 2; | 180 return handleMiddleClick_ && [theEvent buttonNumber] == 2; |
| 49 } | 181 } |
| 50 | 182 |
| 51 - (void)drawFocusRingMask { | 183 - (void)drawFocusRingMask { |
| 52 // Match the hover image's bezel. | 184 // Match the hover image's bezel. |
| 53 [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect([self bounds], 2, 2) | 185 [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect([self bounds], 2, 2) |
| 54 xRadius:2 | 186 xRadius:2 |
| 55 yRadius:2] fill]; | 187 yRadius:2] fill]; |
| 56 } | 188 } |
| 57 | 189 |
| 190 - (SkColor)iconColor:(BOOL)themeIsDark { |
| 191 return themeIsDark ? SK_ColorWHITE : SkColorSetRGB(0x5A, 0x5A, 0x5A); |
| 192 } |
| 193 |
| 194 - (NSImage*)browserToolsIconForFillColor:(SkColor)fillColor { |
| 195 // Create a |BrowserToolsImageRep| to draw the browser tools icon using |
| 196 // the provided fill color. |
| 197 base::scoped_nsobject<BrowserToolsImageRep> imageRep = |
| 198 [[BrowserToolsImageRep alloc] |
| 199 initWithDrawSelector:@selector(drawBrowserToolsIcon:) |
| 200 delegate:[BrowserToolsImageRep class]]; |
| 201 [imageRep setFillColor:skia::SkColorToCalibratedNSColor(fillColor)]; |
| 202 |
| 203 // Create the image from the image rep. |
| 204 NSImage* browserToolsIcon = |
| 205 [[[NSImage alloc] initWithSize:kMDButtonIconSize] autorelease]; |
| 206 [browserToolsIcon setCacheMode:NSImageCacheAlways]; |
| 207 [browserToolsIcon addRepresentation:imageRep]; |
| 208 |
| 209 return browserToolsIcon; |
| 210 } |
| 211 |
| 212 - (NSImage*)imageForIcon:(NSImage*)iconImage |
| 213 withBackgroundStyle:(ToolbarButtonImageBackgroundStyle)style { |
| 214 // Create a |ToolbarButtonImageRep| to draw the button image using |
| 215 // the provided icon and background style. |
| 216 base::scoped_nsobject<ToolbarButtonImageRep> imageRep = |
| 217 [[ToolbarButtonImageRep alloc] |
| 218 initWithDrawSelector:@selector(drawImage:) |
| 219 delegate:[ToolbarButtonImageRep class]]; |
| 220 [imageRep setIcon:iconImage]; |
| 221 [imageRep setStyle:style]; |
| 222 |
| 223 // Create the image from the image rep. |
| 224 NSImage* image = |
| 225 [[[NSImage alloc] initWithSize:kMDButtonBounds.size] autorelease]; |
| 226 [image setCacheMode:NSImageCacheAlways]; |
| 227 [image addRepresentation:imageRep]; |
| 228 |
| 229 return image; |
| 230 } |
| 231 |
| 232 - (void)setImagesFromIconId:(gfx::VectorIconId)iconId { |
| 233 // Compute the normal and disabled icon colors. |
| 234 BOOL isDarkTheme = [[self window] hasDarkTheme]; |
| 235 const SkColor iconColor = [self iconColor:isDarkTheme]; |
| 236 CGFloat normalAlpha = isDarkTheme ? 0xCC : 0xFF; |
| 237 const SkColor normalColor = SkColorSetA(iconColor, normalAlpha); |
| 238 const SkColor disabledColor = SkColorSetA(iconColor, 0x33); |
| 239 |
| 240 // Create the normal and disabled state icons. These icons are |
| 241 // always the same shape, but use a different color. |
| 242 NSImage* normalIcon = nil; |
| 243 NSImage* disabledIcon = nil; |
| 244 if (iconId == gfx::VectorIconId::BROWSER_TOOLS) { |
| 245 normalIcon = [self browserToolsIconForFillColor:normalColor]; |
| 246 disabledIcon = [self browserToolsIconForFillColor:disabledColor]; |
| 247 } else { |
| 248 normalIcon = NSImageFromImageSkia( |
| 249 gfx::CreateVectorIcon(iconId, kMDButtonIconSize.width, normalColor)); |
| 250 disabledIcon = NSImageFromImageSkia( |
| 251 gfx::CreateVectorIcon(iconId, kMDButtonIconSize.width, disabledColor)); |
| 252 } |
| 253 |
| 254 ImageButtonCell* theCell = base::mac::ObjCCast<ImageButtonCell>([self cell]); |
| 255 // Set the image for the default state, which is just the icon. |
| 256 [theCell setImage:normalIcon forButtonState:image_button_cell::kDefaultState]; |
| 257 |
| 258 // Determine the appropriate image background style for the hover and pressed |
| 259 // states. |
| 260 ToolbarButtonImageBackgroundStyle hoverStyle; |
| 261 ToolbarButtonImageBackgroundStyle pressedStyle; |
| 262 const ui::ThemeProvider* themeProvider = [[self window] themeProvider]; |
| 263 bool isNonIncognitoSystemTheme = themeProvider && |
| 264 !themeProvider->InIncognitoMode() && themeProvider->UsingSystemTheme(); |
| 265 // Use the regular style only when using the system (i.e. non-custom) theme |
| 266 // and not in Incognito mode. |
| 267 if (isNonIncognitoSystemTheme) { |
| 268 hoverStyle = ToolbarButtonImageBackgroundStyle::HOVER; |
| 269 pressedStyle = ToolbarButtonImageBackgroundStyle::PRESSED; |
| 270 } else { |
| 271 hoverStyle = ToolbarButtonImageBackgroundStyle::HOVER_THEMED; |
| 272 pressedStyle = ToolbarButtonImageBackgroundStyle::PRESSED_THEMED; |
| 273 } |
| 274 |
| 275 // Create and set the image for the hover state. |
| 276 NSImage* hoverImage = |
| 277 [self imageForIcon:normalIcon withBackgroundStyle:hoverStyle]; |
| 278 [theCell setImage:hoverImage |
| 279 forButtonState:image_button_cell::kHoverState]; |
| 280 |
| 281 // Create and set the image for the pressed state. |
| 282 NSImage* pressedImage = |
| 283 [self imageForIcon:normalIcon withBackgroundStyle:pressedStyle]; |
| 284 [theCell setImage:pressedImage |
| 285 forButtonState:image_button_cell::kPressedState]; |
| 286 |
| 287 // Set the image for the disabled state, which is just the disabled icon, |
| 288 // except if this is the home button. |
| 289 if (iconId == gfx::VectorIconId::NAVIGATE_RELOAD) { |
| 290 [theCell setImage:nil forButtonState:image_button_cell::kDisabledState]; |
| 291 } else { |
| 292 [theCell setImage:disabledIcon |
| 293 forButtonState:image_button_cell::kDisabledState]; |
| 294 } |
| 295 [self setNeedsDisplay:YES]; |
| 296 } |
| 297 |
| 298 - (void)resetIcons { |
| 299 // Compute the button's icon. |
| 300 gfx::VectorIconId icon_id = gfx::VectorIconId::VECTOR_ICON_NONE; |
| 301 switch ([self viewID]) { |
| 302 case VIEW_ID_BACK_BUTTON: |
| 303 icon_id = gfx::VectorIconId::NAVIGATE_BACK; |
| 304 break; |
| 305 case VIEW_ID_FORWARD_BUTTON: |
| 306 icon_id = gfx::VectorIconId::NAVIGATE_FORWARD; |
| 307 break; |
| 308 case VIEW_ID_HOME_BUTTON: |
| 309 icon_id = gfx::VectorIconId::NAVIGATE_HOME; |
| 310 break; |
| 311 case VIEW_ID_APP_MENU: |
| 312 icon_id = gfx::VectorIconId::BROWSER_TOOLS; |
| 313 break; |
| 314 default: |
| 315 break; |
| 316 } |
| 317 |
| 318 // Set it. |
| 319 if (icon_id != gfx::VectorIconId::VECTOR_ICON_NONE) { |
| 320 [self setImagesFromIconId:icon_id]; |
| 321 } |
| 322 } |
| 323 |
| 324 - (void)viewDidMoveToWindow { |
| 325 // In Material Design we want to catch when the button is attached to its |
| 326 // window so that we can configure its appearance based on the window's |
| 327 // theme. |
| 328 if ([self window] && ui::MaterialDesignController::IsModeMaterial()) { |
| 329 [self resetIcons]; |
| 330 } |
| 331 } |
| 332 |
| 333 // ThemedWindowDrawing implementation. |
| 334 |
| 335 - (void)windowDidChangeTheme { |
| 336 [self resetIcons]; |
| 337 } |
| 338 |
| 339 - (void)windowDidChangeActive { |
| 340 } |
| 341 |
| 58 @end | 342 @end |
| OLD | NEW |