| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "base/scoped_nsobject.h" | 5 #import "base/scoped_nsobject.h" |
| 6 #include "chrome/browser/cocoa/gradient_button_cell.h" | 6 #include "chrome/browser/cocoa/gradient_button_cell.h" |
| 7 #import "third_party/GTM/AppKit/GTMTheme.h" | 7 #import "third_party/GTM/AppKit/GTMTheme.h" |
| 8 #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h" | 8 #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h" |
| 9 | 9 |
| 10 @interface GradientButtonCell (Private) | 10 @interface GradientButtonCell (Private) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 } | 65 } |
| 66 | 66 |
| 67 // For programmatic instantiations | 67 // For programmatic instantiations |
| 68 - (id)initTextCell:(NSString*)string { | 68 - (id)initTextCell:(NSString*)string { |
| 69 if ((self = [super initTextCell:string])) { | 69 if ((self = [super initTextCell:string])) { |
| 70 [self sharedInit]; | 70 [self sharedInit]; |
| 71 } | 71 } |
| 72 return self; | 72 return self; |
| 73 } | 73 } |
| 74 | 74 |
| 75 - (NSGradient *)gradientForHoverAlpha:(CGFloat)hoverAlpha | 75 - (NSGradient*)gradientForHoverAlpha:(CGFloat)hoverAlpha |
| 76 isThemed:(BOOL)themed { | 76 isThemed:(BOOL)themed { |
| 77 CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha; | 77 CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha; |
| 78 CGFloat endAlpha = 0.333 * hoverAlpha; | 78 CGFloat endAlpha = 0.333 * hoverAlpha; |
| 79 | 79 |
| 80 if (themed) { | 80 if (themed) { |
| 81 startAlpha = 0.2 + 0.35 * hoverAlpha; | 81 startAlpha = 0.2 + 0.35 * hoverAlpha; |
| 82 endAlpha = 0.333 * hoverAlpha; | 82 endAlpha = 0.333 * hoverAlpha; |
| 83 } | 83 } |
| 84 | 84 |
| 85 NSColor* startColor = | 85 NSColor* startColor = |
| 86 [NSColor colorWithCalibratedWhite:1.0 | 86 [NSColor colorWithCalibratedWhite:1.0 |
| 87 alpha:startAlpha]; | 87 alpha:startAlpha]; |
| 88 NSColor* endColor = | 88 NSColor* endColor = |
| 89 [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha | 89 [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha |
| 90 alpha:endAlpha]; | 90 alpha:endAlpha]; |
| 91 NSGradient *gradient = [[NSGradient alloc] initWithColorsAndLocations: | 91 NSGradient* gradient = [[NSGradient alloc] initWithColorsAndLocations: |
| 92 startColor, hoverAlpha * 0.33, | 92 startColor, hoverAlpha * 0.33, |
| 93 endColor, 1.0, nil]; | 93 endColor, 1.0, nil]; |
| 94 | 94 |
| 95 return [gradient autorelease]; | 95 return [gradient autorelease]; |
| 96 } | 96 } |
| 97 | 97 |
| 98 - (void)sharedInit { | 98 - (void)sharedInit { |
| 99 shouldTheme_ = YES; | 99 shouldTheme_ = YES; |
| 100 gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]); | 100 gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]); |
| 101 } | 101 } |
| 102 | 102 |
| 103 - (void)setShouldTheme:(BOOL)shouldTheme { | 103 - (void)setShouldTheme:(BOOL)shouldTheme { |
| 104 shouldTheme_ = shouldTheme; | 104 shouldTheme_ = shouldTheme; |
| 105 } | 105 } |
| 106 | 106 |
| 107 - (NSImage*)underlayImage { | 107 - (NSImage*)underlayImage { |
| 108 return underlayImage_; | 108 return underlayImage_; |
| 109 } | 109 } |
| 110 | 110 |
| 111 - (void)setUnderlayImage:(NSImage*)image { | 111 - (void)setUnderlayImage:(NSImage*)image { |
| 112 underlayImage_.reset([image retain]); | 112 underlayImage_.reset([image retain]); |
| 113 | 113 |
| 114 [[self controlView] setNeedsDisplay:YES]; | 114 [[self controlView] setNeedsDisplay:YES]; |
| 115 } | 115 } |
| 116 | 116 |
| 117 - (NSBackgroundStyle)interiorBackgroundStyle { | 117 - (NSBackgroundStyle)interiorBackgroundStyle { |
| 118 return [self isHighlighted] ? | 118 // Never lower the interior, since that just leads to a weird shadow which can |
| 119 NSBackgroundStyleLowered : NSBackgroundStyleRaised; | 119 // often interact badly with the theme. |
| 120 return NSBackgroundStyleRaised; |
| 120 } | 121 } |
| 121 | 122 |
| 122 - (void)mouseEntered:(NSEvent *)theEvent { | 123 - (void)mouseEntered:(NSEvent*)theEvent { |
| 123 [self setMouseInside:YES animate:YES]; | 124 [self setMouseInside:YES animate:YES]; |
| 124 } | 125 } |
| 125 | 126 |
| 126 - (void)mouseExited:(NSEvent *)theEvent { | 127 - (void)mouseExited:(NSEvent*)theEvent { |
| 127 [self setMouseInside:NO animate:YES]; | 128 [self setMouseInside:NO animate:YES]; |
| 128 } | 129 } |
| 129 | 130 |
| 130 - (BOOL)isMouseInside { | 131 - (BOOL)isMouseInside { |
| 131 return trackingArea_ && isMouseInside_; | 132 return trackingArea_ && isMouseInside_; |
| 132 } | 133 } |
| 133 | 134 |
| 134 // Since we have our own drawWithFrame:, we need to also have our own | 135 // Since we have our own drawWithFrame:, we need to also have our own |
| 135 // logic for determining when the mouse is inside for honoring this | 136 // logic for determining when the mouse is inside for honoring this |
| 136 // request. | 137 // request. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 150 [[self controlView] addTrackingArea:trackingArea_]; | 151 [[self controlView] addTrackingArea:trackingArea_]; |
| 151 } else { | 152 } else { |
| 152 if (trackingArea_) { | 153 if (trackingArea_) { |
| 153 [[self controlView] removeTrackingArea:trackingArea_]; | 154 [[self controlView] removeTrackingArea:trackingArea_]; |
| 154 trackingArea_.reset(nil); | 155 trackingArea_.reset(nil); |
| 155 isMouseInside_ = NO; | 156 isMouseInside_ = NO; |
| 156 } | 157 } |
| 157 } | 158 } |
| 158 } | 159 } |
| 159 | 160 |
| 161 // TODO(viettrungluu): clean up/reorganize. |
| 160 - (void)drawBorderAndFillForTheme:(GTMTheme*)theme | 162 - (void)drawBorderAndFillForTheme:(GTMTheme*)theme |
| 161 controlView:(NSView*)controlView | 163 controlView:(NSView*)controlView |
| 162 outerPath:(NSBezierPath*)outerPath | 164 outerPath:(NSBezierPath*)outerPath |
| 163 innerPath:(NSBezierPath*)innerPath | 165 innerPath:(NSBezierPath*)innerPath |
| 164 showClickedGradient:(BOOL)showClickedGradient | 166 showClickedGradient:(BOOL)showClickedGradient |
| 165 showHighlightGradient:(BOOL)showHighlightGradient | 167 showHighlightGradient:(BOOL)showHighlightGradient |
| 166 hoverAlpha:(CGFloat)hoverAlpha | 168 hoverAlpha:(CGFloat)hoverAlpha |
| 167 active:(BOOL)active | 169 active:(BOOL)active |
| 168 cellFrame:(NSRect)cellFrame | 170 cellFrame:(NSRect)cellFrame |
| 169 defaultGradient:(NSGradient*)defaultGradient { | 171 defaultGradient:(NSGradient*)defaultGradient { |
| 170 NSImage* backgroundImage = | 172 BOOL isFlatButton = [self showsBorderOnlyWhileMouseInside]; |
| 171 [theme backgroundImageForStyle:GTMThemeStyleToolBarButton state:YES]; | |
| 172 | 173 |
| 173 if (!defaultGradient) | 174 // For flat (unbordered when not hovered) buttons, never use the toolbar |
| 174 defaultGradient = gradient_; | 175 // button background image, but the modest gradient used for themed buttons. |
| 176 // To make things even more modest, scale the hover alpha down by 40 percent |
| 177 // unless clicked. |
| 178 NSImage* backgroundImage; |
| 179 BOOL useThemeGradient; |
| 180 if (isFlatButton) { |
| 181 backgroundImage = nil; |
| 182 useThemeGradient = YES; |
| 183 if (!showClickedGradient) |
| 184 hoverAlpha *= 0.6; |
| 185 } else { |
| 186 backgroundImage = [theme backgroundImageForStyle:GTMThemeStyleToolBarButton |
| 187 state:YES]; |
| 188 useThemeGradient = backgroundImage ? YES : NO; |
| 189 } |
| 175 | 190 |
| 191 // The basic gradient shown inside; see above. |
| 192 NSGradient* gradient; |
| 193 if (hoverAlpha == 0 && !useThemeGradient) { |
| 194 gradient = defaultGradient ? defaultGradient |
| 195 : gradient_; |
| 196 } else { |
| 197 gradient = [self gradientForHoverAlpha:hoverAlpha |
| 198 isThemed:useThemeGradient]; |
| 199 } |
| 200 |
| 201 // If we're drawing a background image, show that; else possibly show the |
| 202 // clicked gradient. |
| 176 if (backgroundImage) { | 203 if (backgroundImage) { |
| 177 NSColor* patternColor = [NSColor colorWithPatternImage:backgroundImage]; | 204 NSColor* patternColor = [NSColor colorWithPatternImage:backgroundImage]; |
| 178 [patternColor set]; | 205 [patternColor set]; |
| 179 // Set the phase to match window. | 206 // Set the phase to match window. |
| 180 NSRect trueRect = [controlView convertRectToBase:cellFrame]; | 207 NSRect trueRect = [controlView convertRectToBase:cellFrame]; |
| 181 [[NSGraphicsContext currentContext] | 208 [[NSGraphicsContext currentContext] |
| 182 setPatternPhase:NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect))]; | 209 setPatternPhase:NSMakePoint(NSMinX(trueRect), NSMaxY(trueRect))]; |
| 183 [innerPath fill]; | 210 [innerPath fill]; |
| 184 } else { | 211 } else { |
| 185 if (showClickedGradient) { | 212 if (showClickedGradient) { |
| 186 NSGradient* gradient = | 213 NSGradient* clickedGradient; |
| 187 [theme gradientForStyle:GTMThemeStyleToolBarButtonPressed | 214 if (isFlatButton) { |
| 188 state:active]; | 215 clickedGradient = gradient; |
| 189 [gradient drawInBezierPath:innerPath angle:90.0]; | 216 } else { |
| 217 clickedGradient = |
| 218 [theme gradientForStyle:GTMThemeStyleToolBarButtonPressed |
| 219 state:active]; |
| 220 } |
| 221 [clickedGradient drawInBezierPath:innerPath angle:90.0]; |
| 190 } | 222 } |
| 191 } | 223 } |
| 192 | 224 |
| 193 BOOL isCustomTheme = backgroundImage != nil; | 225 // Visually indicate unclicked, enabled buttons. |
| 194 | |
| 195 if (!showClickedGradient && [self isEnabled]) { | 226 if (!showClickedGradient && [self isEnabled]) { |
| 196 [NSGraphicsContext saveGraphicsState]; | 227 [NSGraphicsContext saveGraphicsState]; |
| 197 [innerPath addClip]; | 228 [innerPath addClip]; |
| 198 | 229 |
| 199 // Draw the inner glow. | 230 // Draw the inner glow. |
| 200 if (hoverAlpha > 0) { | 231 if (hoverAlpha > 0) { |
| 201 [innerPath setLineWidth:2]; | 232 [innerPath setLineWidth:2]; |
| 202 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 * hoverAlpha] setStroke]; | 233 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2 * hoverAlpha] setStroke]; |
| 203 [innerPath stroke]; | 234 [innerPath stroke]; |
| 204 } | 235 } |
| 205 | 236 |
| 206 // Draw the top inner highlight. | 237 // Draw the top inner highlight. |
| 207 NSAffineTransform* highlightTransform = [NSAffineTransform transform]; | 238 NSAffineTransform* highlightTransform = [NSAffineTransform transform]; |
| 208 [highlightTransform translateXBy:1 yBy:1]; | 239 [highlightTransform translateXBy:1 yBy:1]; |
| 209 scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]); | 240 scoped_nsobject<NSBezierPath> highlightPath([innerPath copy]); |
| 210 [highlightPath transformUsingAffineTransform:highlightTransform]; | 241 [highlightPath transformUsingAffineTransform:highlightTransform]; |
| 211 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setStroke]; | 242 [[NSColor colorWithCalibratedWhite:1.0 alpha:0.2] setStroke]; |
| 212 [highlightPath stroke]; | 243 [highlightPath stroke]; |
| 213 | 244 |
| 214 NSGradient *gradient = nil; | 245 // Draw the gradient inside. |
| 215 if (hoverAlpha == 0 && !isCustomTheme) { | |
| 216 gradient = defaultGradient; | |
| 217 } else { | |
| 218 gradient = [self gradientForHoverAlpha:hoverAlpha isThemed:isCustomTheme]; | |
| 219 } | |
| 220 [gradient drawInBezierPath:innerPath angle:90.0]; | 246 [gradient drawInBezierPath:innerPath angle:90.0]; |
| 221 | 247 |
| 222 [NSGraphicsContext restoreGraphicsState]; | 248 [NSGraphicsContext restoreGraphicsState]; |
| 223 } | 249 } |
| 224 | 250 |
| 225 // Draw the outer stroke | 251 // Draw the outer stroke. |
| 226 NSColor* stroke = [theme strokeColorForStyle:GTMThemeStyleToolBarButton | 252 NSColor* strokeColor = showClickedGradient ? |
| 227 state:active]; | 253 [NSColor colorWithCalibratedWhite:0.0 alpha:0.3] : |
| 228 | 254 [theme strokeColorForStyle:GTMThemeStyleToolBarButton state:active]; |
| 229 if (showClickedGradient) { | 255 [strokeColor setStroke]; |
| 230 stroke = [NSColor colorWithCalibratedWhite:0.0 alpha:0.3]; | |
| 231 } | |
| 232 [stroke setStroke]; | |
| 233 | 256 |
| 234 [innerPath setLineWidth:1]; | 257 [innerPath setLineWidth:1]; |
| 235 [innerPath stroke]; | 258 [innerPath stroke]; |
| 236 } | 259 } |
| 237 | 260 |
| 238 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { | 261 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { |
| 239 // Constants from Cole. Will kConstant them once the feedback loop | 262 // Constants from Cole. Will kConstant them once the feedback loop |
| 240 // is complete. | 263 // is complete. |
| 241 NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5); | 264 NSRect drawFrame = NSInsetRect(cellFrame, 1.5, 1.5); |
| 242 NSRect innerFrame = NSInsetRect(cellFrame, 2, 1); | 265 NSRect innerFrame = NSInsetRect(cellFrame, 2, 1); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 256 innerFrame.size.width += 2; | 279 innerFrame.size.width += 2; |
| 257 default: | 280 default: |
| 258 break; | 281 break; |
| 259 } | 282 } |
| 260 | 283 |
| 261 const float radius = 3.5; | 284 const float radius = 3.5; |
| 262 BOOL pressed = [self isHighlighted]; | 285 BOOL pressed = [self isHighlighted]; |
| 263 NSWindow* window = [controlView window]; | 286 NSWindow* window = [controlView window]; |
| 264 BOOL active = [window isKeyWindow] || [window isMainWindow]; | 287 BOOL active = [window isKeyWindow] || [window isMainWindow]; |
| 265 | 288 |
| 266 GTMTheme *theme = [controlView gtm_theme]; | 289 GTMTheme* theme = [controlView gtm_theme]; |
| 267 | 290 |
| 268 NSBezierPath* innerPath = | 291 NSBezierPath* innerPath = |
| 269 [NSBezierPath bezierPathWithRoundedRect:drawFrame | 292 [NSBezierPath bezierPathWithRoundedRect:drawFrame |
| 270 xRadius:radius | 293 xRadius:radius |
| 271 yRadius:radius]; | 294 yRadius:radius]; |
| 272 NSBezierPath* outerPath = | 295 NSBezierPath* outerPath = |
| 273 [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(drawFrame, -1, -1) | 296 [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(drawFrame, -1, -1) |
| 274 xRadius:radius + 1 | 297 xRadius:radius + 1 |
| 275 yRadius:radius + 1]; | 298 yRadius:radius + 1]; |
| 276 | 299 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 [NSGraphicsContext saveGraphicsState]; | 338 [NSGraphicsContext saveGraphicsState]; |
| 316 | 339 |
| 317 CGContextRef context = | 340 CGContextRef context = |
| 318 (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); | 341 (CGContextRef)([[NSGraphicsContext currentContext] graphicsPort]); |
| 319 | 342 |
| 320 NSColor* color = [theme iconColorForStyle:GTMThemeStyleToolBarButton | 343 NSColor* color = [theme iconColorForStyle:GTMThemeStyleToolBarButton |
| 321 state:YES]; | 344 state:YES]; |
| 322 | 345 |
| 323 if (isTemplate) { | 346 if (isTemplate) { |
| 324 scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); | 347 scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); |
| 325 NSColor *shadowColor = [color gtm_legibleTextColor]; | 348 NSColor* shadowColor = [color gtm_legibleTextColor]; |
| 326 shadowColor = [shadowColor colorWithAlphaComponent:0.25]; | 349 shadowColor = [shadowColor colorWithAlphaComponent:0.25]; |
| 327 [shadow.get() setShadowColor:shadowColor]; | 350 [shadow.get() setShadowColor:shadowColor]; |
| 328 [shadow.get() setShadowOffset:NSMakeSize(0, -1.0)]; | 351 [shadow.get() setShadowOffset:NSMakeSize(0, -1.0)]; |
| 329 [shadow setShadowBlurRadius:1.0]; | 352 [shadow setShadowBlurRadius:1.0]; |
| 330 [shadow set]; | 353 [shadow set]; |
| 331 } | 354 } |
| 332 | 355 |
| 333 [self drawUnderlayImageWithFrame:cellFrame inView:controlView]; | 356 [self drawUnderlayImageWithFrame:cellFrame inView:controlView]; |
| 334 | 357 |
| 335 CGContextBeginTransparencyLayer(context, 0); | 358 CGContextBeginTransparencyLayer(context, 0); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 imageRect.size = [underlayImage_ size]; | 390 imageRect.size = [underlayImage_ size]; |
| 368 [underlayImage_ setFlipped:[controlView isFlipped]]; | 391 [underlayImage_ setFlipped:[controlView isFlipped]]; |
| 369 [underlayImage_ drawInRect:[self imageRectForBounds:cellFrame] | 392 [underlayImage_ drawInRect:[self imageRectForBounds:cellFrame] |
| 370 fromRect:imageRect | 393 fromRect:imageRect |
| 371 operation:NSCompositeSourceOver | 394 operation:NSCompositeSourceOver |
| 372 fraction:[self isEnabled] ? 1.0 : 0.5]; | 395 fraction:[self isEnabled] ? 1.0 : 0.5]; |
| 373 } | 396 } |
| 374 } | 397 } |
| 375 | 398 |
| 376 @end | 399 @end |
| OLD | NEW |