diff --git a/keycastr/About.ca/index.xml b/keycastr/About.ca/index.xml
index 751b6da..fd2fd8d 100644
--- a/keycastr/About.ca/index.xml
+++ b/keycastr/About.ca/index.xml
@@ -32,6 +32,8 @@
multitouchEnabled
+ playerBackgroundColor
+ 0.95 0.95 0.95 1
presentationMouseEventsEnabled
presentationShowsCursor
@@ -43,7 +45,7 @@
savesWindowFrame
scalesToFitInPlayer
-
+
showsTouches
snappingEnabled
diff --git a/keycastr/About.ca/main.caml b/keycastr/About.ca/main.caml
index 62c8c9f..8dfa369 100644
--- a/keycastr/About.ca/main.caml
+++ b/keycastr/About.ca/main.caml
@@ -1,44 +1,12 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
@@ -78,46 +46,110 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/keycastr/KCAboutView.m b/keycastr/KCAboutView.m
index 4804f9d..42203bb 100644
--- a/keycastr/KCAboutView.m
+++ b/keycastr/KCAboutView.m
@@ -30,7 +30,14 @@
@interface KCAboutView : NSView
@end
-@implementation KCAboutView
+@implementation KCAboutView {
+ CALayer *_rootLayer;
+ CAStateController *_stateController;
+ CAState *_pressedState;
+
+ id _eventMonitor;
+}
+
- (void)awakeFromNib {
[super awakeFromNib];
@@ -38,15 +45,88 @@
NSError *outError;
CAPackage *package = [CAPackage packageWithContentsOfURL:url type:kCAPackageTypeCAMLBundle options:nil error:&outError];
-
if (outError) {
NSLog(@"%@", [outError description]);
+
+ return;
+ }
+
+ _rootLayer = package.rootLayer;
+
+ _stateController = [[CAStateController alloc] initWithLayer:_rootLayer];
+ [_stateController setInitialStatesOfLayer:package.rootLayer transitionSpeed:0.0];
+
+ _pressedState = [_rootLayer valueForKey:@"states"][0];
+
+ self.wantsLayer = YES;
+ self.layer = package.rootLayer;
+
+ // Track mouse hovering over app logo
+ CGRect appLogoRect = CGRectMake(84, 24, 94, 94);
+
+ NSTrackingArea* trackingArea = [[NSTrackingArea alloc] initWithRect:appLogoRect
+ options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways)
+ owner:self
+ userInfo:nil];
+
+ [self addTrackingArea:trackingArea];
+}
+
+- (void)setPressedState:(BOOL)pressed {
+ if (pressed) {
+ [_stateController setState:_pressedState ofLayer:_rootLayer transitionSpeed:1.0];
}
else {
- self.wantsLayer = YES;
- self.layer = package.rootLayer;
+ [_stateController setState:nil ofLayer:_rootLayer transitionSpeed:1.0];
}
}
+
+// MARK: Event monitoring
+
+- (void)removeMonitor {
+ if (_eventMonitor) {
+ [NSEvent removeMonitor:_eventMonitor];
+ _eventMonitor = nil;
+ }
+}
+
+- (void)viewDidMoveToWindow {
+ [super viewDidMoveToWindow];
+
+ if (self.window) {
+ __weak typeof(self) weakSelf = self;
+
+ // Track command button being held
+ _eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged
+ handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) {
+ BOOL heldCommand = event.modifierFlags & NSEventModifierFlagCommand;
+
+ [weakSelf handleCommandPress:heldCommand];
+
+ return event;
+ }];
+ }
+ else {
+ [self removeMonitor];
+ }
+}
+
+- (void)dealloc {
+ [self removeMonitor];
+}
+
+// MARK: Event handling
+
+- (void)handleCommandPress:(BOOL)heldCommand {
+ [self setPressedState:heldCommand];
+}
+
+- (void)mouseEntered:(NSEvent *)event {
+ [self setPressedState:YES];
+}
+- (void)mouseExited:(NSEvent *)event {
+ [self setPressedState:NO];
+}
@end
diff --git a/keycastr/QuartzCorePrivate.h b/keycastr/QuartzCorePrivate.h
index 272d831..99c0b60 100644
--- a/keycastr/QuartzCorePrivate.h
+++ b/keycastr/QuartzCorePrivate.h
@@ -6,12 +6,25 @@ extern NSString *kCAPackageTypeCAMLBundle;
@interface CAPackage : NSObject
+@property(readonly) CALayer *rootLayer;
+
+ (id)packageWithData:(NSData *)data type:(NSString *)type options:(id)opts error:(NSError **)outError;
+ (id)packageWithContentsOfURL:(NSURL *)url type:(NSString *)type options:(id)opts error:(NSError **)outError;
-- (NSArray *)publishedObjectNames;
+@end
-@property(readonly, getter=isGeometryFlipped) BOOL geometryFlipped;
-@property(readonly) CALayer *rootLayer;
+
+@interface CAState : NSObject;
+@end
+
+
+@interface CAStateController : NSObject;
+
+@property (readonly) CALayer* layer;
+
+- (void)setState:(id)state ofLayer:(id)layer transitionSpeed:(float)speed;
+- (void)setState:(id)state ofLayer:(id)layer;
+- (id)initWithLayer:(id)layer;
+- (void)setInitialStatesOfLayer:(id)layer transitionSpeed:(float)speed;
@end