blob: 9cfb4328b6343c9b585810d633dbef20d0f35e98 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/cocoa/info_bubble_window.h"
#include "base/logging.h"
#import "third_party/GTM/AppKit/GTMNSAnimation+Duration.h"
namespace {
const CGFloat kOrderInSlideOffset = 10;
const NSTimeInterval kOrderInAnimationDuration = 0.3;
const NSTimeInterval kOrderOutAnimationDuration = 0.15;
}
@implementation InfoBubbleWindow
- (id)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)aStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)flag {
if ((self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:bufferingType
defer:flag])) {
[self setBackgroundColor:[NSColor clearColor]];
[self setExcludedFromWindowsMenu:YES];
[self setOpaque:NO];
[self setHasShadow:YES];
// Start invisible. Will be made visible when ordered front.
[self setAlphaValue:0.0];
// Set up alphaValue animation so that self is delegate for the animation.
// Setting up the delegate is required so that the
// animationDidStop:finished: callback can be handled.
// Notice that only the alphaValue Animation is replaced in case
// superclasses set up animations.
CAAnimation* alphaAnimation = [CABasicAnimation animation];
[alphaAnimation setDelegate:self];
NSMutableDictionary* animations =
[NSMutableDictionary dictionaryWithDictionary:[self animations]];
[animations setObject:alphaAnimation forKey:@"alphaValue"];
}
return self;
}
// According to
// http://www.cocoabuilder.com/archive/message/cocoa/2006/6/19/165953,
// NSBorderlessWindowMask windows cannot become key or main. In this
// case, this is not a desired behavior. As an example, the bubble could have
// buttons.
- (BOOL)canBecomeKeyWindow {
return YES;
}
// Adds animation for info bubbles being ordered to the front and ordered out.
- (void)orderWindow:(NSWindowOrderingMode)orderingMode
relativeTo:(NSInteger)otherWindowNumber {
// According to the documentation '0' is the otherWindowNumber when the window
// is ordered front.
if (orderingMode == NSWindowAbove && otherWindowNumber == 0) {
// Order self appropriately assuming that its alpha is zero as set up
// in the designated initializer.
[super orderWindow:orderingMode relativeTo:otherWindowNumber];
// Set up frame so it can be adjust down by a few pixels.
NSRect frame = [self frame];
NSPoint newOrigin = frame.origin;
newOrigin.y += kOrderInSlideOffset;
[self setFrameOrigin:newOrigin];
// Apply animations to show and move self.
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext]
gtm_setDuration:kOrderInAnimationDuration];
[[self animator] setAlphaValue:1.0];
[[self animator] setFrame:frame display:YES];
[NSAnimationContext endGrouping];
} else if (orderingMode == NSWindowOut) {
// Flag self as closing to block events while animation is occurring.
closing_ = YES;
// Apply animations to hide self.
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext]
gtm_setDuration:kOrderOutAnimationDuration];
[[self animator] setAlphaValue:0.0];
[NSAnimationContext endGrouping];
} else {
[super orderWindow:orderingMode relativeTo:otherWindowNumber];
}
}
// If the window is currently animating a close, block all UI events to the
// window.
- (void)sendEvent:(NSEvent*)theEvent {
if (!closing_) {
[super sendEvent:theEvent];
}
}
// Callback for the alpha animation set up in designated initializer.
- (void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag {
// When alpha reaches zero, close self.
if ([self alphaValue] == 0.0) {
[self close];
}
}
@end
|