Chromium Code Reviews| Index: ui/message_center/cocoa/popup_controller.mm |
| diff --git a/ui/message_center/cocoa/popup_controller.mm b/ui/message_center/cocoa/popup_controller.mm |
| index f574fc08062d87bb0ea1ba5d4ce5b43e124436c0..05635b7ce66713b4c7c04fe36a023ca819e0edb4 100644 |
| --- a/ui/message_center/cocoa/popup_controller.mm |
| +++ b/ui/message_center/cocoa/popup_controller.mm |
| @@ -4,6 +4,9 @@ |
| #import "ui/message_center/cocoa/popup_controller.h" |
| +#include <cmath> |
| + |
| +#import "base/mac/foundation_util.h" |
| #import "ui/base/cocoa/window_size_constants.h" |
| #import "ui/message_center/cocoa/notification_controller.h" |
| #include "ui/message_center/message_center.h" |
| @@ -13,21 +16,117 @@ |
| enum { |
| NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8 |
| }; |
| + |
| +enum { |
|
Robert Sesek
2013/05/22 23:54:29
This is copied verbatim from RenderWidgetHostViewD
Nico
2013/05/23 01:02:56
Probably a good idea. Can be in a follow-up if you
|
| + NSEventPhaseNone = 0, // event not associated with a phase. |
| + NSEventPhaseBegan = 0x1 << 0, |
| + NSEventPhaseStationary = 0x1 << 1, |
| + NSEventPhaseChanged = 0x1 << 2, |
| + NSEventPhaseEnded = 0x1 << 3, |
| + NSEventPhaseCancelled = 0x1 << 4, |
| +}; |
| +typedef NSUInteger NSEventPhase; |
| + |
| +enum { |
| + NSEventSwipeTrackingLockDirection = 0x1 << 0, |
| + NSEventSwipeTrackingClampGestureAmount = 0x1 << 1 |
| +}; |
| +typedef NSUInteger NSEventSwipeTrackingOptions; |
| + |
| +@interface NSEvent (LionAPI) |
| +- (NSEventPhase)phase; |
| +- (CGFloat)scrollingDeltaX; |
| +- (CGFloat)scrollingDeltaY; |
| +- (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options |
| + dampenAmountThresholdMin:(CGFloat)minDampenThreshold |
| + max:(CGFloat)maxDampenThreshold |
| + usingHandler:(void (^)(CGFloat gestureAmount, |
| + NSEventPhase phase, |
| + BOOL isComplete, |
| + BOOL* stop))trackingHandler; |
| +@end |
| #endif // MAC_OS_X_VERSION_10_7 |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| +@interface MCPopupController (Private) |
| +- (void)notificationSwipeStarted; |
| +- (void)notificationSwipeMoved:(CGFloat)amount; |
| +- (void)notificationSwipeEnded:(BOOL)ended complete:(BOOL)isComplete; |
| +@end |
| + |
| +// Window Subclass ///////////////////////////////////////////////////////////// |
| + |
| +@interface MCPopupWindow : NSWindow { |
| + // The cumulative X and Y scrollingDeltas since the -scrollWheel: event began. |
| + NSPoint totalScrollDelta_; |
| +} |
| +@end |
| + |
| +@implementation MCPopupWindow |
| + |
| +- (void)scrollWheel:(NSEvent*)event { |
| + // Gesture swiping only exists on 10.7+. |
| + if (![event respondsToSelector:@selector(phase)]) |
| + return; |
| + |
| + NSEventPhase phase = [event phase]; |
| + BOOL shouldTrackSwipe = NO; |
| + |
| + if (phase == NSEventPhaseBegan) { |
| + totalScrollDelta_ = NSZeroPoint; |
| + } else if (phase == NSEventPhaseChanged) { |
| + shouldTrackSwipe = YES; |
| + totalScrollDelta_.x += [event scrollingDeltaX]; |
| + totalScrollDelta_.y += [event scrollingDeltaY]; |
| + } |
| + |
| + // Only allow horizontal scrolling. |
| + if (std::abs(totalScrollDelta_.x) < std::abs(totalScrollDelta_.y)) |
| + return; |
| + |
| + if (shouldTrackSwipe) { |
| + MCPopupController* controller = |
| + base::mac::ObjCCastStrict<MCPopupController>([self windowController]); |
| + |
| + auto handler = ^(CGFloat gestureAmount, NSEventPhase phase, |
| + BOOL isComplete, BOOL* stop) { |
| + if (phase == NSEventPhaseBegan) { |
| + [controller notificationSwipeStarted]; |
| + return; |
| + } |
| + |
| + [controller notificationSwipeMoved:gestureAmount]; |
| + |
| + BOOL ended = phase == NSEventPhaseEnded; |
| + if (ended || isComplete) |
| + [controller notificationSwipeEnded:ended complete:isComplete]; |
| + }; |
| + [event trackSwipeEventWithOptions:0 |
| + dampenAmountThresholdMin:-1 |
| + max:1 |
| + usingHandler:handler]; |
| + } |
| +} |
| + |
| +@end |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| @implementation MCPopupController |
| - (id)initWithNotification:(const message_center::Notification*)notification |
| messageCenter:(message_center::MessageCenter*)messageCenter { |
| - scoped_nsobject<NSWindow> window( |
| - [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater |
| - styleMask:NSBorderlessWindowMask |
| - backing:NSBackingStoreBuffered |
| - defer:YES]); |
| + scoped_nsobject<MCPopupWindow> window( |
| + [[MCPopupWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater |
| + styleMask:NSBorderlessWindowMask |
| + backing:NSBackingStoreBuffered |
| + defer:YES]); |
| if ((self = [super initWithWindow:window])) { |
| + messageCenter_ = messageCenter; |
| notificationController_.reset( |
| [[MCNotificationController alloc] initWithNotification:notification |
| - messageCenter:messageCenter]); |
| + messageCenter:messageCenter_]); |
| [window setReleasedWhenClosed:NO]; |
| [window setLevel:NSFloatingWindowLevel]; |
| @@ -55,4 +154,28 @@ enum { |
| return [notificationController_ notificationID]; |
| } |
| +// Private ///////////////////////////////////////////////////////////////////// |
| + |
| +- (void)notificationSwipeStarted { |
| + originalFrame_ = [[self window] frame]; |
| + swipeGestureEnded_ = NO; |
| +} |
| + |
| +- (void)notificationSwipeMoved:(CGFloat)amount { |
| + NSWindow* window = [self window]; |
| + |
| + [window setAlphaValue:1.0 - std::abs(amount)]; |
|
dewittj
2013/05/23 16:28:37
Is the linear reduction of alpha the most natural?
Robert Sesek
2013/05/23 16:31:13
This isn't actually linear. |amount| is done throu
|
| + NSRect frame = [window frame]; |
| + CGFloat originalMin = NSMinX(originalFrame_); |
| + frame.origin.x = originalMin + (NSMidX(originalFrame_) - originalMin) * |
| + -amount; |
| + [window setFrame:frame display:YES]; |
| +} |
| + |
| +- (void)notificationSwipeEnded:(BOOL)ended complete:(BOOL)isComplete { |
| + swipeGestureEnded_ |= ended; |
| + if (swipeGestureEnded_ && isComplete) |
| + messageCenter_->RemoveNotification([self notificationID], /*by_user=*/true); |
|
Nico
2013/05/23 01:02:56
If the user cancels a swipe, does appkit animate b
Robert Sesek
2013/05/23 13:00:58
Yup! AppKit will run the animation back for us.
dewittj
2013/05/23 16:28:37
nit: spaces between comment markers and other text
Robert Sesek
2013/05/23 16:31:13
When doing this to "name" parameters, I think this
|
| +} |
| + |
| @end |