Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / hover_close_button.mm
blobc2fed3045b4c5f0978aeb46a7b2954d5906845a7
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/hover_close_button.h"
7 #include "chrome/grit/generated_resources.h"
8 #include "grit/theme_resources.h"
9 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMKeyValueAnimation.h"
10 #include "ui/base/cocoa/animation_utils.h"
11 #include "ui/base/l10n/l10n_util.h"
12 #include "ui/base/resource/resource_bundle.h"
13 #include "ui/resources/grit/ui_resources.h"
15 namespace  {
16 const CGFloat kFramesPerSecond = 16; // Determined experimentally to look good.
17 const CGFloat kCloseAnimationDuration = 0.1;
19 // Strings that are used for all close buttons. Set up in +initialize.
20 NSString* gTooltip = nil;
21 NSString* gDescription = nil;
23 // If this string is changed, the setter (currently setFadeOutValue:) must
24 // be changed as well to match.
25 NSString* const kFadeOutValueKeyPath = @"fadeOutValue";
26 }  // namespace
28 @interface HoverCloseButton ()
30 // Common initialization routine called from initWithFrame and awakeFromNib.
31 - (void)commonInit;
33 // Called by |fadeOutAnimation_| when animated value changes.
34 - (void)setFadeOutValue:(CGFloat)value;
36 // Gets the image for the given hover state.
37 - (NSImage*)imageForHoverState:(HoverState)hoverState;
39 @end
41 @implementation HoverCloseButton
43 + (void)initialize {
44   // Grab some strings that are used by all close buttons.
45   if (!gDescription)
46     gDescription = [l10n_util::GetNSStringWithFixup(IDS_ACCNAME_CLOSE) copy];
47   if (!gTooltip)
48     gTooltip = [l10n_util::GetNSStringWithFixup(IDS_TOOLTIP_CLOSE_TAB) copy];
51 - (id)initWithFrame:(NSRect)frameRect {
52   if ((self = [super initWithFrame:frameRect])) {
53     [self commonInit];
54   }
55   return self;
58 - (void)awakeFromNib {
59   [super awakeFromNib];
60   [self commonInit];
63 - (void)removeFromSuperview {
64   // -stopAnimation will call the animationDidStop: delegate method
65   // which will release our animation.
66   [fadeOutAnimation_ stopAnimation];
67   [super removeFromSuperview];
70 - (void)animationDidStop:(NSAnimation*)animation {
71   DCHECK(animation == fadeOutAnimation_);
72   [fadeOutAnimation_ setDelegate:nil];
73   [fadeOutAnimation_ release];
74   fadeOutAnimation_ = nil;
77 - (void)animationDidEnd:(NSAnimation*)animation {
78   [self animationDidStop:animation];
81 - (void)drawRect:(NSRect)dirtyRect {
82   NSImage* image = [self imageForHoverState:[self hoverState]];
84   // Close boxes align left horizontally, and align center vertically.
85   // http:crbug.com/14739 requires this.
86   NSRect imageRect = NSZeroRect;
87   imageRect.size = [image size];
89   NSRect destRect = [self bounds];
90   destRect.origin.y = floor((NSHeight(destRect) / 2)
91                             - (NSHeight(imageRect) / 2));
92   destRect.size = imageRect.size;
94   switch(self.hoverState) {
95     case kHoverStateMouseOver:
96       [image drawInRect:destRect
97                fromRect:imageRect
98               operation:NSCompositeSourceOver
99                fraction:1.0
100          respectFlipped:YES
101                   hints:nil];
102       break;
104     case kHoverStateMouseDown:
105       [image drawInRect:destRect
106                fromRect:imageRect
107               operation:NSCompositeSourceOver
108                fraction:1.0
109          respectFlipped:YES
110                   hints:nil];
111       break;
113     case kHoverStateNone: {
114       CGFloat value = 1.0;
115       if (fadeOutAnimation_) {
116         value = [fadeOutAnimation_ currentValue];
117         NSImage* previousImage = nil;
118         if (previousState_ == kHoverStateMouseOver)
119           previousImage = [self imageForHoverState:kHoverStateMouseOver];
120         else
121           previousImage = [self imageForHoverState:kHoverStateMouseDown];
122         [previousImage drawInRect:destRect
123                          fromRect:imageRect
124                         operation:NSCompositeSourceOver
125                          fraction:1.0 - value
126                    respectFlipped:YES
127                             hints:nil];
128       }
129       [image drawInRect:destRect
130                fromRect:imageRect
131               operation:NSCompositeSourceOver
132                fraction:value
133          respectFlipped:YES
134                   hints:nil];
135       break;
136     }
137   }
140 - (void)setFadeOutValue:(CGFloat)value {
141   [self setNeedsDisplay];
144 - (NSImage*)imageForHoverState:(HoverState)hoverState {
145   int imageID = IDR_CLOSE_1;
146   switch (hoverState) {
147     case kHoverStateNone:
148       imageID = IDR_CLOSE_1;
149       break;
150     case kHoverStateMouseOver:
151       imageID = IDR_CLOSE_1_H;
152       break;
153     case kHoverStateMouseDown:
154       imageID = IDR_CLOSE_1_P;
155       break;
156   }
157   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
158   return bundle.GetNativeImageNamed(imageID).ToNSImage();
161 - (void)setHoverState:(HoverState)state {
162   if (state != self.hoverState) {
163     previousState_ = self.hoverState;
164     [super setHoverState:state];
165     // Only animate the HoverStateNone case and only if this is still in the
166     // view hierarchy.
167     if (state == kHoverStateNone && [self superview] != nil) {
168       DCHECK(fadeOutAnimation_ == nil);
169       fadeOutAnimation_ =
170           [[GTMKeyValueAnimation alloc] initWithTarget:self
171                                                keyPath:kFadeOutValueKeyPath];
172       [fadeOutAnimation_ setDuration:kCloseAnimationDuration];
173       [fadeOutAnimation_ setFrameRate:kFramesPerSecond];
174       [fadeOutAnimation_ setDelegate:self];
175       [fadeOutAnimation_ startAnimation];
176     } else {
177       // -stopAnimation will call the animationDidStop: delegate method
178       // which will clean up the animation.
179       [fadeOutAnimation_ stopAnimation];
180     }
181   }
184 - (void)commonInit {
185   // Set accessibility description.
186   NSCell* cell = [self cell];
187   [cell accessibilitySetOverrideValue:gDescription
188                          forAttribute:NSAccessibilityTitleAttribute];
190   // Add a tooltip. Using 'owner:self' means that
191   // -view:stringForToolTip:point:userData: will be called to provide the
192   // tooltip contents immediately before showing it.
193   [self addToolTipRect:[self bounds] owner:self userData:NULL];
195   // Initialize previousState.
196   previousState_ = kHoverStateNone;
199 // Called each time a tooltip is about to be shown.
200 - (NSString*)view:(NSView*)view
201  stringForToolTip:(NSToolTipTag)tag
202             point:(NSPoint)point
203          userData:(void*)userData {
204   if (self.hoverState == kHoverStateMouseOver) {
205     // In some cases (e.g. the download tray), the button is still in the
206     // hover state, but is outside the bounds of its parent and not visible.
207     // Don't show the tooltip in that case.
208     NSRect buttonRect = [self frame];
209     NSRect parentRect = [[self superview] bounds];
210     if (NSIntersectsRect(buttonRect, parentRect))
211       return gTooltip;
212   }
214   return nil;  // Do not show the tooltip.
217 @end
219 @implementation WebUIHoverCloseButton
221 - (NSImage*)imageForHoverState:(HoverState)hoverState {
222   int imageID = IDR_CLOSE_DIALOG;
223   switch (hoverState) {
224     case kHoverStateNone:
225       imageID = IDR_CLOSE_DIALOG;
226       break;
227     case kHoverStateMouseOver:
228       imageID = IDR_CLOSE_DIALOG_H;
229       break;
230     case kHoverStateMouseDown:
231       imageID = IDR_CLOSE_DIALOG_P;
232       break;
233   }
234   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
235   return bundle.GetNativeImageNamed(imageID).ToNSImage();
238 @end