diff options
-rw-r--r-- | chrome/browser/ui/panels/panel_titlebar_view_cocoa.h | 16 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm | 93 |
2 files changed, 108 insertions, 1 deletions
diff --git a/chrome/browser/ui/panels/panel_titlebar_view_cocoa.h b/chrome/browser/ui/panels/panel_titlebar_view_cocoa.h index 0a97f4b..0623408 100644 --- a/chrome/browser/ui/panels/panel_titlebar_view_cocoa.h +++ b/chrome/browser/ui/panels/panel_titlebar_view_cocoa.h @@ -32,6 +32,14 @@ enum PanelDragState { PANEL_DRAG_SUPPRESSED // Ignore drag events until PANEL_DRAG_CAN_START. }; +@interface RepaintAnimation : NSAnimation { + @private + NSView* targetView_; +} +- (id)initWithView:(NSView*)targetView duration:(double) duration; +- (void)setCurrentProgress:(NSAnimationProgress)progress; +@end + @interface PanelTitlebarViewCocoa : NSView { @private IBOutlet PanelWindowControllerCocoa* controller_; @@ -50,6 +58,10 @@ enum PanelDragState { PanelDragState dragState_; BOOL isDrawingAttention_; NSPoint dragStartLocation_; + // "Glint" animation is used in "Draw Attention" mode. + scoped_nsobject<RepaintAnimation> glintAnimation_; + scoped_nsobject<NSTimer> glintAnimationTimer_; + double glintInterval_; } // Callback from Close button. @@ -88,6 +100,10 @@ enum PanelDragState { - (void)drawAttention; - (void)stopDrawingAttention; - (BOOL)isDrawingAttention; +- (void)startGlintAnimation; +- (void)restartGlintAnimation:(NSTimer*)timer; +- (void)stopGlintAnimation; + @end // @interface PanelTitlebarView // Methods which are either only for testing, or only public for testing. diff --git a/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm b/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm index 83b8bdf..31b1dfc 100644 --- a/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm +++ b/chrome/browser/ui/panels/panel_titlebar_view_cocoa.mm @@ -30,6 +30,15 @@ const int kIconAndTextPadding = 5; // titlebar with a twitch of the mouse pointer. const int kDragThreshold = 3; +// 'Glint' is a speck of light that moves across the titlebar to attract a bit +// more attention using movement in addition to color of the titlebar. +// It initially moves fast, then starts to slow down to avoid being annoying +// if the user chooses not to react on it. +const double kGlintAnimationDuration = 0.6; +const double kStartGlintRepeatIntervalSeconds = 0.1; +const double kFinalGlintRepeatIntervalSeconds = 2.0; +const double kGlintRepeatIntervalIncreaseFactor = 1.5; + // Used to implement TestingAPI static NSEvent* MakeMouseEvent(NSEventType type, NSPoint point, @@ -45,6 +54,22 @@ static NSEvent* MakeMouseEvent(NSEventType type, pressure:0.0]; } +@implementation RepaintAnimation +- (id)initWithView:(NSView*)targetView duration:(double) duration { + if (![super initWithDuration:duration animationCurve:NSAnimationEaseInOut]) + return nil; + [self setAnimationBlockingMode:NSAnimationNonblocking]; + targetView_ = targetView; + return self; +} + +- (void)setCurrentProgress:(NSAnimationProgress)progress { + [super setCurrentProgress:progress]; + [targetView_ setNeedsDisplay:YES]; +} +@end + + @implementation PanelTitlebarViewCocoa - (id)initWithFrame:(NSRect)frame { @@ -64,6 +89,7 @@ static NSEvent* MakeMouseEvent(NSEventType type, if (closeButtonTrackingArea_.get()) [self removeTrackingArea:closeButtonTrackingArea_.get()]; [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self stopGlintAnimation]; [super dealloc]; } @@ -100,6 +126,30 @@ static NSEvent* MakeMouseEvent(NSEventType type, strokeColor = [NSColor colorWithCalibratedWhite:0.6 alpha:1.0]; titleColor = [attentionColor gtm_legibleTextColor]; + + if ([glintAnimation_ isAnimating]) { + scoped_nsobject<NSGradient> glint([NSGradient alloc]); + NSColor* gold = + [NSColor colorWithCalibratedRed:0.8 green:0.8 blue:0.0 alpha:1.0]; + [glint initWithColorsAndLocations:gold, 0.0, + [NSColor colorWithCalibratedWhite:1.0 alpha:0.4], 0.3, + [NSColor colorWithCalibratedWhite:1.0 alpha:0.0], 1.0, + nil]; + NSRect bounds = [self bounds]; + NSPoint point = bounds.origin; + // The size and position values are experimentally choosen to create + // a "speck of light attached to the top edge" effect. + int gradientRadius = NSHeight(bounds) * 2; + point.y += gradientRadius / 2; + double rangeOfMotion = NSWidth(bounds) + 4 * gradientRadius; + double startPoint = - 2 * gradientRadius; + point.x = startPoint + rangeOfMotion * [glintAnimation_ currentValue]; + [glint drawFromCenter:point + radius:0.0 + toCenter:point + radius:gradientRadius + options:NSGradientDrawsBeforeStartingLocation]; + } } else if (theme && !theme->UsingDefaultTheme()) { NSColor* backgroundColor = nil; if ([[self window] isMainWindow]) { @@ -439,13 +489,16 @@ static NSEvent* MakeMouseEvent(NSEventType type, if (isDrawingAttention_) return; isDrawingAttention_ = YES; - [self setNeedsDisplay:YES]; + + [self startGlintAnimation]; } - (void)stopDrawingAttention { if (!isDrawingAttention_) return; isDrawingAttention_ = NO; + + [self stopGlintAnimation]; [self setNeedsDisplay:YES]; } @@ -453,6 +506,44 @@ static NSEvent* MakeMouseEvent(NSEventType type, return isDrawingAttention_; } +- (void)startGlintAnimation { + glintInterval_ = kStartGlintRepeatIntervalSeconds; + [self restartGlintAnimation:nil]; +} + +- (void)stopGlintAnimation { + if (glintAnimationTimer_.get()) { + [glintAnimationTimer_ invalidate]; + glintAnimationTimer_.reset(); + } + if ([glintAnimation_ isAnimating]) + [glintAnimation_ stopAnimation]; +} + +- (void)restartGlintAnimation:(NSTimer*)timer { + if (!glintAnimation_.get()) { + glintAnimation_.reset( + [[RepaintAnimation alloc] initWithView:self + duration:kGlintAnimationDuration]); + [glintAnimation_ setDelegate:self]; + } + [glintAnimation_ startAnimation]; +} + +- (void)animationDidEnd:(NSAnimation*)animation { + if (animation == glintAnimation_.get()) { // Restart after a timeout. + glintAnimationTimer_.reset([[NSTimer + scheduledTimerWithTimeInterval:glintInterval_ + target:self + selector:@selector(restartGlintAnimation:) + userInfo:nil + repeats:NO] retain]); + // Gradually reduce the frequency of repeating the animation, + // calming it down if user decides not to act upon it. + if (glintInterval_ < kFinalGlintRepeatIntervalSeconds) + glintInterval_ *= kGlintRepeatIntervalIncreaseFactor; + } +} // (Private/TestingAPI) - (PanelWindowControllerCocoa*)controller { |