[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / history_overlay_controller.mm
blobcdfb1962fac592e805d0cf41e60b25a576c9ab53
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/history_overlay_controller.h"
7 #include "base/logging.h"
8 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
9 #include "grit/theme_resources.h"
10 #include "ui/base/resource/resource_bundle.h"
11 #include "ui/gfx/image/image.h"
13 #import <QuartzCore/QuartzCore.h>
15 #include <cmath>
17 // Constants ///////////////////////////////////////////////////////////////////
19 // The radius of the circle drawn in the shield.
20 const CGFloat kShieldRadius = 70;
22 // The diameter of the circle and the width of its bounding box.
23 const CGFloat kShieldWidth = kShieldRadius * 2;
25 // The height of the shield.
26 const CGFloat kShieldHeight = 140;
28 // Additional height that is added to kShieldHeight when the gesture is
29 // considered complete.
30 const CGFloat kShieldHeightCompletionAdjust = 10;
32 // HistoryOverlayView //////////////////////////////////////////////////////////
34 // The content view that draws the semicircle and the arrow.
35 @interface HistoryOverlayView : NSView {
36  @private
37   HistoryOverlayMode mode_;
38   CGFloat shieldAlpha_;
40 @property(nonatomic) CGFloat shieldAlpha;
41 - (id)initWithMode:(HistoryOverlayMode)mode
42              image:(NSImage*)image;
43 @end
45 @implementation HistoryOverlayView
47 @synthesize shieldAlpha = shieldAlpha_;
49 - (id)initWithMode:(HistoryOverlayMode)mode
50              image:(NSImage*)image {
51   NSRect frame = NSMakeRect(0, 0, kShieldWidth, kShieldHeight);
52   if ((self = [super initWithFrame:frame])) {
53     mode_ = mode;
55     // If going backward, the arrow needs to be in the right half of the circle,
56     // so offset the X position.
57     CGFloat offset = mode_ == kHistoryOverlayModeBack ? kShieldRadius : 0;
58     NSRect arrowRect = NSMakeRect(offset, 0, kShieldRadius, kShieldHeight);
59     arrowRect = NSInsetRect(arrowRect, 10, 0);  // Give a little padding.
61     base::scoped_nsobject<NSImageView> imageView(
62         [[NSImageView alloc] initWithFrame:arrowRect]);
63     [imageView setImage:image];
64     [imageView setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin];
65     [self addSubview:imageView];
66   }
67   return self;
70 - (void)drawRect:(NSRect)dirtyRect {
71   NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:self.bounds];
72   NSColor* fillColor = [NSColor colorWithCalibratedWhite:0 alpha:shieldAlpha_];
73   [fillColor set];
74   [path fill];
77 @end
79 // HistoryOverlayController ////////////////////////////////////////////////////
81 @implementation HistoryOverlayController
83 - (id)initForMode:(HistoryOverlayMode)mode {
84   if ((self = [super init])) {
85     mode_ = mode;
86     DCHECK(mode == kHistoryOverlayModeBack ||
87            mode == kHistoryOverlayModeForward);
88   }
89   return self;
92 - (void)loadView {
93   const gfx::Image& image =
94       ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
95           mode_ == kHistoryOverlayModeBack ? IDR_SWIPE_BACK
96                                            : IDR_SWIPE_FORWARD);
97   contentView_.reset(
98       [[HistoryOverlayView alloc] initWithMode:mode_
99                                          image:image.ToNSImage()]);
100   self.view = contentView_;
103 - (void)setProgress:(CGFloat)gestureAmount finished:(BOOL)finished {
104   NSRect parentFrame = [parent_ frame];
105   // When tracking the gesture, the height is constant and the alpha value
106   // changes from [0.25, 0.65].
107   CGFloat height = kShieldHeight;
108   CGFloat shieldAlpha = std::min(static_cast<CGFloat>(0.65),
109                                  std::max(gestureAmount,
110                                           static_cast<CGFloat>(0.25)));
112   // When the gesture is very likely to be completed (90% in this case), grow
113   // the semicircle's height and lock the alpha to 0.75.
114   if (finished) {
115     height += kShieldHeightCompletionAdjust;
116     shieldAlpha = 0.75;
117   }
119   // Compute the new position based on the progress.
120   NSRect frame = self.view.frame;
121   frame.size.height = height;
122   frame.origin.y = (NSHeight(parentFrame) / 2) - (height / 2);
124   CGFloat width = std::min(kShieldRadius * gestureAmount, kShieldRadius);
125   if (mode_ == kHistoryOverlayModeForward)
126     frame.origin.x = NSMaxX(parentFrame) - width;
127   else if (mode_ == kHistoryOverlayModeBack)
128     frame.origin.x = NSMinX(parentFrame) - kShieldWidth + width;
130   self.view.frame = frame;
131   [contentView_ setShieldAlpha:shieldAlpha];
132   [contentView_ setNeedsDisplay:YES];
135 - (void)showPanelForView:(NSView*)view {
136   parent_.reset([view retain]);
137   [self setProgress:0 finished:NO];  // Set initial view position.
138   [parent_  addSubview:self.view];
139   [[BrowserWindowController
140       browserWindowControllerForView:[self view]] onOverlappedViewShown];
143 - (void)dismiss {
144   const CGFloat kFadeOutDurationSeconds = 0.4;
146   [NSAnimationContext beginGrouping];
147   [NSAnimationContext currentContext].duration = kFadeOutDurationSeconds;
148   NSView* overlay = self.view;
150   base::scoped_nsobject<CAAnimation> animation(
151       [[overlay animationForKey:@"alphaValue"] copy]);
152   [animation setDelegate:self];
153   [animation setDuration:kFadeOutDurationSeconds];
154   NSMutableDictionary* dictionary =
155       [NSMutableDictionary dictionaryWithCapacity:1];
156   [dictionary setObject:animation forKey:@"alphaValue"];
157   [overlay setAnimations:dictionary];
158   [[overlay animator] setAlphaValue:0.0];
159   [NSAnimationContext endGrouping];
162 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)finished {
163   [[BrowserWindowController
164       browserWindowControllerForView:[self view]] onOverlappedViewHidden];
165   [self.view removeFromSuperview];
166   // Destroy the CAAnimation and its strong reference to its delegate (this
167   // class).
168   [self.view setAnimations:nil];
171 @end