OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/history_overlay_controller.h" | 5 #import "chrome/browser/ui/cocoa/history_overlay_controller.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "grit/theme_resources.h" | 8 #include "grit/theme_resources.h" |
9 #include "ui/base/resource/resource_bundle.h" | 9 #include "ui/base/resource/resource_bundle.h" |
10 #include "ui/gfx/image/image.h" | 10 #include "ui/gfx/image/image.h" |
11 | 11 |
12 #import <QuartzCore/QuartzCore.h> | 12 #import <QuartzCore/QuartzCore.h> |
13 | 13 |
14 #include <cmath> | 14 #include <cmath> |
15 | 15 |
16 // Constants /////////////////////////////////////////////////////////////////// | 16 // Constants /////////////////////////////////////////////////////////////////// |
17 | 17 |
18 // The radius of the circle drawn in the shield. | 18 // The radius of the circle drawn in the shield. |
19 const CGFloat kShieldRadius = 70; | 19 const CGFloat kShieldRadius = 70; |
20 | 20 |
21 // The diameter of the circle and the width of its bounding box. | 21 // The diameter of the circle and the width of its bounding box. |
22 const CGFloat kShieldWidth = kShieldRadius * 2; | 22 const CGFloat kShieldWidth = kShieldRadius * 2; |
23 | 23 |
24 // The height of the shield. | 24 // The height of the shield. |
25 const CGFloat kShieldHeight = 140; | 25 const CGFloat kShieldHeight = 140; |
26 | 26 |
| 27 // Additional height that is added to kShieldHeight when the gesture is |
| 28 // considered complete. |
| 29 const CGFloat kShieldHeightCompletionAdjust = 10; |
| 30 |
27 // The amount of |gestureAmount| at which AppKit considers the gesture | 31 // The amount of |gestureAmount| at which AppKit considers the gesture |
28 // completed. This was derived more via art than science. | 32 // completed. This was derived more via art than science. |
29 const CGFloat kGestureCompleteProgress = 0.3; | 33 const CGFloat kGestureCompleteProgress = 0.3; |
30 | 34 |
31 // HistoryOverlayView ////////////////////////////////////////////////////////// | 35 // HistoryOverlayView ////////////////////////////////////////////////////////// |
32 | 36 |
33 // The content view that draws the semicircle and the arrow. | 37 // The content view that draws the semicircle and the arrow. |
34 @interface HistoryOverlayView : NSView { | 38 @interface HistoryOverlayView : NSView { |
35 @private | 39 @private |
36 HistoryOverlayMode mode_; | 40 HistoryOverlayMode mode_; |
37 CGFloat progress_; | 41 CGFloat shieldAlpha_; |
38 } | 42 } |
39 @property(nonatomic) CGFloat progress; | 43 @property(nonatomic) CGFloat shieldAlpha; |
40 - (id)initWithMode:(HistoryOverlayMode)mode | 44 - (id)initWithMode:(HistoryOverlayMode)mode |
41 image:(NSImage*)image; | 45 image:(NSImage*)image; |
42 @end | 46 @end |
43 | 47 |
44 @implementation HistoryOverlayView | 48 @implementation HistoryOverlayView |
45 | 49 |
46 @synthesize progress = progress_; | 50 @synthesize shieldAlpha = shieldAlpha_; |
47 | 51 |
48 - (id)initWithMode:(HistoryOverlayMode)mode | 52 - (id)initWithMode:(HistoryOverlayMode)mode |
49 image:(NSImage*)image { | 53 image:(NSImage*)image { |
50 NSRect frame = NSMakeRect(0, 0, kShieldWidth, kShieldHeight); | 54 NSRect frame = NSMakeRect(0, 0, kShieldWidth, kShieldHeight); |
51 if ((self = [super initWithFrame:frame])) { | 55 if ((self = [super initWithFrame:frame])) { |
52 mode_ = mode; | 56 mode_ = mode; |
53 | 57 |
54 // If going backward, the arrow needs to be in the right half of the circle, | 58 // If going backward, the arrow needs to be in the right half of the circle, |
55 // so offset the X position. | 59 // so offset the X position. |
56 CGFloat offset = mode_ == kHistoryOverlayModeBack ? kShieldRadius : 0; | 60 CGFloat offset = mode_ == kHistoryOverlayModeBack ? kShieldRadius : 0; |
57 NSRect arrowRect = NSMakeRect(offset, 0, kShieldRadius, kShieldHeight); | 61 NSRect arrowRect = NSMakeRect(offset, 0, kShieldRadius, kShieldHeight); |
58 arrowRect = NSInsetRect(arrowRect, 10, 0); // Give a little padding. | 62 arrowRect = NSInsetRect(arrowRect, 10, 0); // Give a little padding. |
59 | 63 |
60 scoped_nsobject<NSImageView> imageView( | 64 scoped_nsobject<NSImageView> imageView( |
61 [[NSImageView alloc] initWithFrame:arrowRect]); | 65 [[NSImageView alloc] initWithFrame:arrowRect]); |
62 [imageView setImage:image]; | 66 [imageView setImage:image]; |
| 67 [imageView setAutoresizingMask:NSViewMinYMargin | NSViewMaxYMargin]; |
63 [self addSubview:imageView]; | 68 [self addSubview:imageView]; |
64 } | 69 } |
65 return self; | 70 return self; |
66 } | 71 } |
67 | 72 |
68 - (void)drawRect:(NSRect)dirtyRect { | 73 - (void)drawRect:(NSRect)dirtyRect { |
69 NSRect ovalRect = NSMakeRect(0, 0, kShieldWidth, kShieldHeight); | 74 NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:self.bounds]; |
70 NSBezierPath* path = [NSBezierPath bezierPathWithOvalInRect:ovalRect]; | 75 NSColor* fillColor = [NSColor colorWithCalibratedWhite:0 alpha:shieldAlpha_]; |
71 NSColor* fillColor = | |
72 // Clamp the minimum ligtness to be 0.666. | |
73 [NSColor colorWithCalibratedWhite:std::min(2.0/3.0 - progress_, 2.0/3.0) | |
74 alpha:0.85]; | |
75 [fillColor set]; | 76 [fillColor set]; |
76 [path fill]; | 77 [path fill]; |
77 } | 78 } |
78 | 79 |
79 @end | 80 @end |
80 | 81 |
81 // HistoryOverlayController //////////////////////////////////////////////////// | 82 // HistoryOverlayController //////////////////////////////////////////////////// |
82 | 83 |
83 @implementation HistoryOverlayController | 84 @implementation HistoryOverlayController |
84 | 85 |
(...skipping 16 matching lines...) Expand all Loading... |
101 image:image.ToNSImage()]); | 102 image:image.ToNSImage()]); |
102 self.view = contentView_; | 103 self.view = contentView_; |
103 } | 104 } |
104 | 105 |
105 - (void)setProgress:(CGFloat)gestureAmount { | 106 - (void)setProgress:(CGFloat)gestureAmount { |
106 NSRect parentFrame = [parent_ frame]; | 107 NSRect parentFrame = [parent_ frame]; |
107 // Scale the gesture amount so that the progress is indicative of the gesture | 108 // Scale the gesture amount so that the progress is indicative of the gesture |
108 // being completed. | 109 // being completed. |
109 gestureAmount = std::abs(gestureAmount) / kGestureCompleteProgress; | 110 gestureAmount = std::abs(gestureAmount) / kGestureCompleteProgress; |
110 | 111 |
| 112 // When tracking the gesture, the height is constant and the alpha value |
| 113 // changes from [0.25, 0.65]. |
| 114 CGFloat height = kShieldHeight; |
| 115 CGFloat shieldAlpha = std::min(0.65f, std::max(gestureAmount, 0.25f)); |
| 116 |
| 117 // When the gesture is very likely to be completed (90% in this case), grow |
| 118 // the semicircle's height and lock the alpha to 0.75. |
| 119 if (gestureAmount > 0.9) { |
| 120 height += kShieldHeightCompletionAdjust; |
| 121 shieldAlpha = 0.75; |
| 122 } |
| 123 |
111 // Compute the new position based on the progress. | 124 // Compute the new position based on the progress. |
112 NSRect frame = self.view.frame; | 125 NSRect frame = self.view.frame; |
113 frame.origin.y = (NSHeight(parentFrame) / 2) - (kShieldHeight / 2); | 126 frame.size.height = height; |
| 127 frame.origin.y = (NSHeight(parentFrame) / 2) - (height / 2); |
114 | 128 |
115 CGFloat width = std::min(kShieldRadius * gestureAmount, kShieldRadius); | 129 CGFloat width = std::min(kShieldRadius * gestureAmount, kShieldRadius); |
116 if (mode_ == kHistoryOverlayModeForward) | 130 if (mode_ == kHistoryOverlayModeForward) |
117 frame.origin.x = NSMaxX(parentFrame) - width; | 131 frame.origin.x = NSMaxX(parentFrame) - width; |
118 else if (mode_ == kHistoryOverlayModeBack) | 132 else if (mode_ == kHistoryOverlayModeBack) |
119 frame.origin.x = NSMinX(parentFrame) - kShieldWidth + width; | 133 frame.origin.x = NSMinX(parentFrame) - kShieldWidth + width; |
120 | 134 |
121 self.view.frame = frame; | 135 self.view.frame = frame; |
122 [contentView_ setProgress:gestureAmount]; | 136 [contentView_ setShieldAlpha:shieldAlpha]; |
123 [contentView_ setNeedsDisplay:YES]; | 137 [contentView_ setNeedsDisplay:YES]; |
124 } | 138 } |
125 | 139 |
126 - (void)showPanelForView:(NSView*)view { | 140 - (void)showPanelForView:(NSView*)view { |
127 parent_.reset([view retain]); | 141 parent_.reset([view retain]); |
128 [self setProgress:0]; // Set initial view position. | 142 [self setProgress:0]; // Set initial view position. |
129 [[parent_ superview] addSubview:self.view | 143 [[parent_ superview] addSubview:self.view |
130 positioned:NSWindowAbove | 144 positioned:NSWindowAbove |
131 relativeTo:parent_]; | 145 relativeTo:parent_]; |
132 } | 146 } |
133 | 147 |
134 - (void)dismiss { | 148 - (void)dismiss { |
135 const CGFloat kFadeOutDurationSeconds = 0.2; | 149 const CGFloat kFadeOutDurationSeconds = 0.4; |
136 | 150 |
137 NSView* overlay = self.view; | 151 NSView* overlay = self.view; |
138 | 152 |
139 scoped_nsobject<CAAnimation> animation( | 153 scoped_nsobject<CAAnimation> animation( |
140 [[overlay animationForKey:@"alphaValue"] copy]); | 154 [[overlay animationForKey:@"alphaValue"] copy]); |
141 [animation setDelegate:self]; | 155 [animation setDelegate:self]; |
142 [animation setDuration:kFadeOutDurationSeconds]; | 156 [animation setDuration:kFadeOutDurationSeconds]; |
143 NSMutableDictionary* dictionary = | 157 NSMutableDictionary* dictionary = |
144 [NSMutableDictionary dictionaryWithCapacity:1]; | 158 [NSMutableDictionary dictionaryWithCapacity:1]; |
145 [dictionary setObject:animation forKey:@"alphaValue"]; | 159 [dictionary setObject:animation forKey:@"alphaValue"]; |
146 [overlay setAnimations:dictionary]; | 160 [overlay setAnimations:dictionary]; |
147 [[overlay animator] setAlphaValue:0.0]; | 161 [[overlay animator] setAlphaValue:0.0]; |
148 } | 162 } |
149 | 163 |
150 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)finished { | 164 - (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)finished { |
151 [self.view removeFromSuperview]; | 165 [self.view removeFromSuperview]; |
152 } | 166 } |
153 | 167 |
154 @end | 168 @end |
OLD | NEW |