Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(382)

Side by Side Diff: chrome/browser/cocoa/gradient_button_cell.mm

Issue 2805099: Pulse new bookmarks (as triggered by bookmark bubble). If not possible, ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 #include "chrome/browser/cocoa/gradient_button_cell.h" 5 #include "chrome/browser/cocoa/gradient_button_cell.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #import "base/scoped_nsobject.h" 8 #import "base/scoped_nsobject.h"
9 #import "chrome/browser/browser_theme_provider.h" 9 #import "chrome/browser/browser_theme_provider.h"
10 #import "chrome/browser/cocoa/image_utils.h" 10 #import "chrome/browser/cocoa/image_utils.h"
11 #import "chrome/browser/cocoa/themed_window.h" 11 #import "chrome/browser/cocoa/themed_window.h"
12 #include "grit/theme_resources.h" 12 #include "grit/theme_resources.h"
13 #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h" 13 #import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
14 14
15 @interface GradientButtonCell (Private) 15 @interface GradientButtonCell (Private)
16 - (void)sharedInit; 16 - (void)sharedInit;
17 17
18 // Get drawing parameters for a given cell frame in a given view. The inner 18 // Get drawing parameters for a given cell frame in a given view. The inner
19 // frame is the one required by |-drawInteriorWithFrame:inView:|. The inner and 19 // frame is the one required by |-drawInteriorWithFrame:inView:|. The inner and
20 // outer paths are the ones required by |-drawBorderAndFillForTheme:...|. The 20 // outer paths are the ones required by |-drawBorderAndFillForTheme:...|. The
21 // outer path also gives the area in which to clip. Any of the |return...| 21 // outer path also gives the area in which to clip. Any of the |return...|
22 // arguments may be NULL (in which case the given parameter won't be returned). 22 // arguments may be NULL (in which case the given parameter won't be returned).
23 // If |returnInnerPath| or |returnOuterPath|, |*returnInnerPath| or 23 // If |returnInnerPath| or |returnOuterPath|, |*returnInnerPath| or
24 // |*returnOuterPath| should be nil, respectively. 24 // |*returnOuterPath| should be nil, respectively.
25 - (void)getDrawParamsForFrame:(NSRect)cellFrame 25 - (void)getDrawParamsForFrame:(NSRect)cellFrame
26 inView:(NSView*)controlView 26 inView:(NSView*)controlView
27 innerFrame:(NSRect*)returnInnerFrame 27 innerFrame:(NSRect*)returnInnerFrame
28 innerPath:(NSBezierPath**)returnInnerPath 28 innerPath:(NSBezierPath**)returnInnerPath
29 clipPath:(NSBezierPath**)returnClipPath; 29 clipPath:(NSBezierPath**)returnClipPath;
30
31
30 @end 32 @end
31 33
34
32 static const NSTimeInterval kAnimationShowDuration = 0.2; 35 static const NSTimeInterval kAnimationShowDuration = 0.2;
33 static const NSTimeInterval kAnimationHideDuration = 0.4; 36 static const NSTimeInterval kAnimationHideDuration = 0.4;
37 static const NSTimeInterval kAnimationContinuousCycleDuration = 0.4;
34 38
35 @implementation GradientButtonCell 39 @implementation GradientButtonCell
40
36 @synthesize hoverAlpha = hoverAlpha_; 41 @synthesize hoverAlpha = hoverAlpha_;
37 42
38 - (void)adjustHoverValue {
39 NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
40
41 NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
42
43 CGFloat opacity = [self hoverAlpha];
44 if (isMouseInside_) {
45 opacity += elapsed / kAnimationShowDuration;
46 } else {
47 opacity -= elapsed / kAnimationHideDuration;
48 }
49
50 if (!isMouseInside_ && opacity < 0) {
51 opacity = 0;
52 } else if (isMouseInside_ && opacity > 1) {
53 opacity = 1;
54 } else {
55 [self performSelector:_cmd withObject:nil afterDelay:0.02];
56 }
57 lastHoverUpdate_ = thisUpdate;
58 [self setHoverAlpha:opacity];
59
60 [[self controlView] setNeedsDisplay:YES];
61 }
62
63 - (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
64 isMouseInside_ = flag;
65 if (animated) {
66 lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
67 [self adjustHoverValue];
68 } else {
69 [NSObject cancelPreviousPerformRequestsWithTarget:self];
70 [self setHoverAlpha:flag ? 1.0 : 0.0];
71 }
72 [[self controlView] setNeedsDisplay:YES];
73 }
74
75 // For nib instantiations 43 // For nib instantiations
76 - (id)initWithCoder:(NSCoder*)decoder { 44 - (id)initWithCoder:(NSCoder*)decoder {
77 if ((self = [super initWithCoder:decoder])) { 45 if ((self = [super initWithCoder:decoder])) {
78 [self sharedInit]; 46 [self sharedInit];
79 } 47 }
80 return self; 48 return self;
81 } 49 }
82 50
83 // For programmatic instantiations 51 // For programmatic instantiations
84 - (id)initTextCell:(NSString*)string { 52 - (id)initTextCell:(NSString*)string {
85 if ((self = [super initTextCell:string])) { 53 if ((self = [super initTextCell:string])) {
86 [self sharedInit]; 54 [self sharedInit];
87 } 55 }
88 return self; 56 return self;
89 } 57 }
90 58
91 - (void)dealloc { 59 - (void)dealloc {
92 if (trackingArea_) { 60 if (trackingArea_) {
93 [[self controlView] removeTrackingArea:trackingArea_]; 61 [[self controlView] removeTrackingArea:trackingArea_];
94 trackingArea_.reset(); 62 trackingArea_.reset();
95 } 63 }
96 [super dealloc]; 64 [super dealloc];
97 } 65 }
98 66
67 // Return YES if we are pulsing (towards another state or continuously).
68 - (BOOL)pulsing {
69 if ((pulseState_ == gradient_button_cell::kPulsingOn) ||
70 (pulseState_ == gradient_button_cell::kPulsingOff) ||
71 (pulseState_ == gradient_button_cell::kPulsingContinuous))
72 return YES;
73 return NO;
74 }
75
76 // Perform one pulse step when animating a pulse.
77 - (void)performOnePulseStep {
78 NSTimeInterval thisUpdate = [NSDate timeIntervalSinceReferenceDate];
79 NSTimeInterval elapsed = thisUpdate - lastHoverUpdate_;
80 CGFloat opacity = [self hoverAlpha];
81
82 // Update opacity based on state.
83 // Adjust state if we have finished.
84 switch (pulseState_) {
85 case gradient_button_cell::kPulsingOn:
86 opacity += elapsed / kAnimationShowDuration;
87 if (opacity > 1.0) {
88 [self setPulseState:gradient_button_cell::kPulsedOn];
89 return;
90 }
91 break;
92 case gradient_button_cell::kPulsingOff:
93 opacity -= elapsed / kAnimationHideDuration;
94 if (opacity < 0.0) {
95 [self setPulseState:gradient_button_cell::kPulsedOff];
96 return;
97 }
98 break;
99 case gradient_button_cell::kPulsingContinuous:
100 opacity += elapsed / kAnimationContinuousCycleDuration * pulseMultiplier_;
101 if (opacity > 1.0) {
102 opacity = 1.0;
103 pulseMultiplier_ *= -1.0;
104 } else if (opacity < 0.0) {
105 opacity = 0.0;
106 pulseMultiplier_ *= -1.0;
107 }
108 outerStrokeAlphaMult_ = opacity;
109 break;
110 default:
111 NOTREACHED() << "unknown pulse state";
112 }
113
114 // Update our control.
115 lastHoverUpdate_ = thisUpdate;
116 [self setHoverAlpha:opacity];
117 [[self controlView] setNeedsDisplay:YES];
118
119 // If our state needs it, keep going.
120 if ([self pulsing]) {
121 [self performSelector:_cmd withObject:nil afterDelay:0.02];
122 }
123 }
124
125 - (gradient_button_cell::PulseState)pulseState {
126 return pulseState_;
127 }
128
129 // Set the pulsing state. This can either set the pulse to on or off
130 // immediately (e.g. kPulsedOn, kPulsedOff) or initiate an animated
131 // state change.
132 - (void)setPulseState:(gradient_button_cell::PulseState)pstate {
133 pulseState_ = pstate;
134 pulseMultiplier_ = 0.0;
135 [NSObject cancelPreviousPerformRequestsWithTarget:self];
136 lastHoverUpdate_ = [NSDate timeIntervalSinceReferenceDate];
137
138 switch (pstate) {
139 case gradient_button_cell::kPulsedOn:
140 case gradient_button_cell::kPulsedOff:
141 outerStrokeAlphaMult_ = 1.0;
142 [self setHoverAlpha:((pulseState_ == gradient_button_cell::kPulsedOn) ?
143 1.0 : 0.0)];
144 [[self controlView] setNeedsDisplay:YES];
145 break;
146 case gradient_button_cell::kPulsingOn:
147 case gradient_button_cell::kPulsingOff:
148 outerStrokeAlphaMult_ = 1.0;
149 // Set initial value then engage timer.
150 [self setHoverAlpha:((pulseState_ == gradient_button_cell::kPulsingOn) ?
151 0.0 : 1.0)];
152 [self performOnePulseStep];
153 break;
154 case gradient_button_cell::kPulsingContinuous:
155 // Semantics of continuous pulsing are that we pulse independent
156 // of mouse position.
157 pulseMultiplier_ = 1.0;
158 [self performOnePulseStep];
159 break;
160 default:
161 CHECK(0);
162 break;
163 }
164 }
165
166 - (void)safelyStopPulsing {
167 [NSObject cancelPreviousPerformRequestsWithTarget:self];
168 }
169
170 - (void)setIsContinuousPulsing:(BOOL)continuous {
171 if (!continuous && pulseState_ != gradient_button_cell::kPulsingContinuous)
172 return;
173 if (continuous) {
174 [self setPulseState:gradient_button_cell::kPulsingContinuous];
175 } else {
176 [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsedOn :
177 gradient_button_cell::kPulsedOff)];
178 }
179 }
180
181 - (BOOL)isContinuousPulsing {
182 return (pulseState_ == gradient_button_cell::kPulsingContinuous) ?
183 YES : NO;
184 }
185
186 // If we are not continuously pulsing, perform a pulse animation to
187 // reflect our new state.
188 - (void)setMouseInside:(BOOL)flag animate:(BOOL)animated {
189 isMouseInside_ = flag;
190 if (pulseState_ != gradient_button_cell::kPulsingContinuous) {
191 if (animated) {
192 [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsingOn :
193 gradient_button_cell::kPulsingOff)];
194 } else {
195 [self setPulseState:(isMouseInside_ ? gradient_button_cell::kPulsedOn :
196 gradient_button_cell::kPulsedOff)];
197 }
198 }
199 }
200
99 - (NSGradient*)gradientForHoverAlpha:(CGFloat)hoverAlpha 201 - (NSGradient*)gradientForHoverAlpha:(CGFloat)hoverAlpha
100 isThemed:(BOOL)themed { 202 isThemed:(BOOL)themed {
101 CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha; 203 CGFloat startAlpha = 0.6 + 0.3 * hoverAlpha;
102 CGFloat endAlpha = 0.333 * hoverAlpha; 204 CGFloat endAlpha = 0.333 * hoverAlpha;
103 205
104 if (themed) { 206 if (themed) {
105 startAlpha = 0.2 + 0.35 * hoverAlpha; 207 startAlpha = 0.2 + 0.35 * hoverAlpha;
106 endAlpha = 0.333 * hoverAlpha; 208 endAlpha = 0.333 * hoverAlpha;
107 } 209 }
108 210
109 NSColor* startColor = 211 NSColor* startColor =
110 [NSColor colorWithCalibratedWhite:1.0 212 [NSColor colorWithCalibratedWhite:1.0
111 alpha:startAlpha]; 213 alpha:startAlpha];
112 NSColor* endColor = 214 NSColor* endColor =
113 [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha 215 [NSColor colorWithCalibratedWhite:1.0 - 0.15 * hoverAlpha
114 alpha:endAlpha]; 216 alpha:endAlpha];
115 NSGradient* gradient = [[NSGradient alloc] initWithColorsAndLocations: 217 NSGradient* gradient = [[NSGradient alloc] initWithColorsAndLocations:
116 startColor, hoverAlpha * 0.33, 218 startColor, hoverAlpha * 0.33,
117 endColor, 1.0, nil]; 219 endColor, 1.0, nil];
118 220
119 return [gradient autorelease]; 221 return [gradient autorelease];
120 } 222 }
121 223
122 - (void)sharedInit { 224 - (void)sharedInit {
123 shouldTheme_ = YES; 225 shouldTheme_ = YES;
226 pulseState_ = gradient_button_cell::kPulsedOff;
227 pulseMultiplier_ = 1.0;
228 outerStrokeAlphaMult_ = 1.0;
124 gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]); 229 gradient_.reset([[self gradientForHoverAlpha:0.0 isThemed:NO] retain]);
125 } 230 }
126 231
127 - (void)setShouldTheme:(BOOL)shouldTheme { 232 - (void)setShouldTheme:(BOOL)shouldTheme {
128 shouldTheme_ = shouldTheme; 233 shouldTheme_ = shouldTheme;
129 } 234 }
130 235
131 - (NSImage*)overlayImage { 236 - (NSImage*)overlayImage {
132 return overlayImage_.get(); 237 return overlayImage_.get();
133 } 238 }
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 [NSGraphicsContext restoreGraphicsState]; 381 [NSGraphicsContext restoreGraphicsState];
277 } 382 }
278 383
279 // Don't draw anything else for disabled flat buttons. 384 // Don't draw anything else for disabled flat buttons.
280 if (isFlatButton && ![self isEnabled]) 385 if (isFlatButton && ![self isEnabled])
281 return; 386 return;
282 387
283 // Draw the outer stroke. 388 // Draw the outer stroke.
284 NSColor* strokeColor = nil; 389 NSColor* strokeColor = nil;
285 if (showClickedGradient) { 390 if (showClickedGradient) {
286 strokeColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.3]; 391 strokeColor = [NSColor
392 colorWithCalibratedWhite:0.0
393 alpha:0.3 * outerStrokeAlphaMult_];
287 } else { 394 } else {
288 strokeColor = themeProvider ? themeProvider->GetNSColor( 395 strokeColor = themeProvider ? themeProvider->GetNSColor(
289 active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE : 396 active ? BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE :
290 BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE, 397 BrowserThemeProvider::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
291 true) : [NSColor colorWithCalibratedWhite:0.0 alpha:0.6]; 398 true) : [NSColor colorWithCalibratedWhite:0.0
399 alpha:0.6 * outerStrokeAlphaMult_];
292 } 400 }
293 [strokeColor setStroke]; 401 [strokeColor setStroke];
294 402
295 [innerPath setLineWidth:1]; 403 [innerPath setLineWidth:1];
296 [innerPath stroke]; 404 [innerPath stroke];
297 } 405 }
298 406
299 // TODO(viettrungluu): clean this up. 407 // TODO(viettrungluu): clean this up.
300 // (Private) 408 // (Private)
301 - (void)getDrawParamsForFrame:(NSRect)cellFrame 409 - (void)getDrawParamsForFrame:(NSRect)cellFrame
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 467
360 BOOL pressed = [self isHighlighted]; 468 BOOL pressed = [self isHighlighted];
361 NSWindow* window = [controlView window]; 469 NSWindow* window = [controlView window];
362 ThemeProvider* themeProvider = [window themeProvider]; 470 ThemeProvider* themeProvider = [window themeProvider];
363 BOOL active = [window isKeyWindow] || [window isMainWindow]; 471 BOOL active = [window isKeyWindow] || [window isMainWindow];
364 472
365 // Stroke the borders and appropriate fill gradient. If we're borderless, 473 // Stroke the borders and appropriate fill gradient. If we're borderless,
366 // the only time we want to draw the inner gradient is if we're highlighted. 474 // the only time we want to draw the inner gradient is if we're highlighted.
367 if (([self isBordered] && ![self showsBorderOnlyWhileMouseInside]) || 475 if (([self isBordered] && ![self showsBorderOnlyWhileMouseInside]) ||
368 pressed || 476 pressed ||
369 [self isMouseInside]) { 477 [self isMouseInside] ||
478 [self pulsing]) {
479
480 // When pulsing we want the bookmark to stand out a little more.
481 BOOL showClickedGradient = pressed ||
482 (pulseState_ == gradient_button_cell::kPulsingContinuous);
370 483
371 [self drawBorderAndFillForTheme:themeProvider 484 [self drawBorderAndFillForTheme:themeProvider
372 controlView:controlView 485 controlView:controlView
373 innerPath:innerPath 486 innerPath:innerPath
374 showClickedGradient:pressed 487 showClickedGradient:showClickedGradient
375 showHighlightGradient:[self isHighlighted] 488 showHighlightGradient:[self isHighlighted]
376 hoverAlpha:[self hoverAlpha] 489 hoverAlpha:[self hoverAlpha]
377 active:active 490 active:active
378 cellFrame:cellFrame 491 cellFrame:cellFrame
379 defaultGradient:nil]; 492 defaultGradient:nil];
380 } 493 }
381 494
382 // If this is the left side of a segmented button, draw a slight shadow. 495 // If this is the left side of a segmented button, draw a slight shadow.
383 ButtonType type = [[(NSControl*)controlView cell] tag]; 496 ButtonType type = [[(NSControl*)controlView cell] tag];
384 if (type == kLeftButtonWithShadowType) { 497 if (type == kLeftButtonWithShadowType) {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 NSBezierPath* boundingPath = nil; 571 NSBezierPath* boundingPath = nil;
459 [self getDrawParamsForFrame:cellFrame 572 [self getDrawParamsForFrame:cellFrame
460 inView:controlView 573 inView:controlView
461 innerFrame:NULL 574 innerFrame:NULL
462 innerPath:NULL 575 innerPath:NULL
463 clipPath:&boundingPath]; 576 clipPath:&boundingPath];
464 return boundingPath; 577 return boundingPath;
465 } 578 }
466 579
467 @end 580 @end
OLDNEW
« no previous file with comments | « chrome/browser/cocoa/gradient_button_cell.h ('k') | chrome/browser/cocoa/gradient_button_cell_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698