You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

347 lines
11 KiB

//
// VLCMediaListLayer.m
// VLC
//
// Created by Pierre d'Herbemont on 1/14/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "VLCMediaListLayer.h"
/*****************************************************************************
* @implementation VLCMediaListLayer
*/
@interface VLCMediaListLayer (Private)
- (VLCMediaLayer *)selectedLayer;
- (VLCMediaLayer *)previousLayer;
- (VLCMediaLayer *)nextLayer;
- (void)changeSelectedLayerToNextIndex;
- (void)changeSelectedLayerToPreviousIndex;
- (void)resetLayers;
- (void)setSelectedLayer:(VLCMediaLayer *)layer;
- (void)setPreviousLayer:(VLCMediaLayer *)layer;
- (void)setNextLayer:(VLCMediaLayer *)layer;
@end
/*****************************************************************************
* @implementation VLCMediaListLayer
*/
@implementation VLCMediaListLayer
@synthesize selectedIndex;
@synthesize content;
@synthesize controller;
+ (id)layer
{
VLCMediaListLayer * me = [super layer];
me.layoutManager = [CAConstraintLayoutManager layoutManager];
[CATransaction commit];
me->selectedIndex = NSNotFound;
return me;
}
+ (id)layerWithMediaArrayController:(VLCMediaArrayController *)aController
{
VLCMediaListLayer * me = [VLCMediaListLayer layer];
me.controller = aController;
/* The following will trigger -observeValueForKeyPath: ofObject: change: context: */
[me.controller addObserver:me forKeyPath:@"arrangedObjects" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[me.controller addObserver:me forKeyPath:@"selectionIndex" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
[me.controller addObserver:me forKeyPath:@"contentMediaList" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
return me;
}
- (void)dealloc
{
/* Previously registered in +layerWithMediaArrayController: */
[self.controller removeObserver:self forKeyPath:@"arrangedObjects"];
[self.controller removeObserver:self forKeyPath:@"contentMediaList"];
[self.controller removeObserver:self forKeyPath:@"selectionIndex"];
[super dealloc];
}
@end
/*****************************************************************************
* @implementation VLCMediaListLayer (Private)
*/
@implementation VLCMediaListLayer (Private)
+ (NSSet *)keyPathsForValuesAffectingSelectedLayer
{
return [NSSet setWithObjects:@"selectedLayer", @"content", nil];
}
- (VLCMediaLayer *)selectedLayer
{
VLCMedia * media = (self.selectedIndex != NSNotFound) ? [self.content objectAtIndex:self.selectedIndex ] : nil;
if( !media )
{
CATextLayer * layer = [CATextLayer layer];
CALayer * container = [CALayer layer];
container.layoutManager = [CAConstraintLayoutManager layoutManager];
if([self.controller.contentMediaList isReadOnly])
layer.string = @"Empty";
else if ([self.content count])
layer.string = @"Empty search.";
else
layer.string = @"Drag and Drop a movie or a music here.";
layer.alignmentMode = kCAAlignmentCenter;
layer.wrapped = YES;
[layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidY relativeTo:@"superlayer" attribute:kCAConstraintMidY]];
[layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintMidX relativeTo:@"superlayer" attribute:kCAConstraintMidX]];
[layer addConstraint:[CAConstraint constraintWithAttribute:kCAConstraintWidth relativeTo:@"superlayer" attribute:kCAConstraintWidth]];
[container addSublayer:layer];
return (VLCMediaLayer *)container;
}
if( [selectedLayer isKindOfClass:[VLCMediaLayer class]] && [media compare:[selectedLayer media]] == NSOrderedSame )
return [[selectedLayer retain] autorelease];
return [VLCMediaLayer layerWithMedia:[self.content objectAtIndex:self.selectedIndex]];
}
- (VLCMediaLayer *)previousLayer
{
if( self.selectedIndex == NSNotFound )
return nil;
VLCMedia * media = self.selectedIndex > 0 ? [self.content objectAtIndex:self.selectedIndex - 1] : nil;
if( !media )
return nil;
if( [previousLayer isKindOfClass:[VLCMediaLayer class]] && [media compare:[previousLayer media]] == NSOrderedSame )
return [[previousLayer retain] autorelease];
return [VLCMediaLayer layerWithMedia: media ];
}
- (VLCMediaLayer *)nextLayer
{
if( self.selectedIndex == NSNotFound )
return nil;
VLCMedia * media = self.selectedIndex + 1 < [content count] ? [self.content objectAtIndex:self.selectedIndex + 1] : nil;
if( !media )
return nil;
if( [nextLayer isKindOfClass:[VLCMediaLayer class]] && [media compare:[nextLayer media]] == NSOrderedSame )
return [[nextLayer retain] autorelease];
return [VLCMediaLayer layerWithMedia: media ];
}
- (void)changeSelectedLayerToNextIndex
{
if(!nextLayer)
{
/* Can't do anything */
return;
}
selectedIndex++;
/* Remove offscreen layer. Without actions */
if( previousLayer )
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions];
[previousLayer removeFromSuperlayer];
[CATransaction commit];
}
[CATransaction begin];
if ( [[NSApp currentEvent] modifierFlags] & NSShiftKeyMask )
[CATransaction setValue:[NSNumber numberWithFloat:1.5] forKey:kCATransactionAnimationDuration];
[self setPreviousLayer: selectedLayer];
[self setSelectedLayer: nextLayer];
[self setNextLayer: [self nextLayer]];
[CATransaction commit];
/* Move the new nextLayer layer on screen. Without Actions */
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions];
[self addSublayer: nextLayer];
[CATransaction commit];
}
- (void)changeSelectedLayerToPreviousIndex
{
if(!previousLayer)
{
/* Can't do anything */
return;
}
selectedIndex--;
/* Remove offscreen layer. Without actions */
if( nextLayer )
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions];
[nextLayer removeFromSuperlayer];
[CATransaction commit];
}
[CATransaction begin];
if ( [[NSApp currentEvent] modifierFlags] & NSShiftKeyMask )
[CATransaction setValue:[NSNumber numberWithFloat:1.5] forKey:kCATransactionAnimationDuration];
[self setNextLayer: selectedLayer];
[self setSelectedLayer: previousLayer];
[self setPreviousLayer: [self previousLayer]];
[CATransaction commit];
/* Move the new previous layer on screen. Without Actions */
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions];
[self addSublayer:previousLayer];
[CATransaction commit];
}
- (void)gotoIndex:(NSUInteger)index;
{
if( selectedIndex == index )
return;
if( selectedIndex > index )
{
/* It is ok to scroll five layers */
if( selectedIndex - index < 5 )
{
while( index < selectedIndex )
[self changeSelectedLayerToPreviousIndex];
return;
}
[self changeSelectedLayerToPreviousIndex];
[self changeSelectedLayerToPreviousIndex];
selectedIndex = index;
[self resetLayers];
}
else
{
if( index - selectedIndex < 5 )
{
while( index > selectedIndex )
[self changeSelectedLayerToNextIndex];
return;
}
[self changeSelectedLayerToNextIndex];
[self changeSelectedLayerToNextIndex];
selectedIndex = index;
[self resetLayers];
}
}
- (void)resetLayers
{
VLCMediaLayer * layer;
[CATransaction begin];
layer = [self previousLayer];
if( previousLayer != layer )
{
if( previousLayer ) [self replaceSublayer:previousLayer with:layer];
else [self addSublayer:layer];
[self setPreviousLayer:layer];
}
layer = [self selectedLayer];
if( selectedLayer != layer )
{
if( selectedLayer ) [self replaceSublayer:selectedLayer with:layer];
else [self addSublayer:layer];
[self setSelectedLayer:layer];
}
layer = [self nextLayer];
if( nextLayer != layer )
{
if( nextLayer ) [self replaceSublayer:nextLayer with:layer];
else [self addSublayer:layer];
[self setNextLayer:layer];
}
[CATransaction commit];
}
- (void)setSelectedLayer:(VLCMediaLayer *)layer
{
[selectedLayer autorelease];
if( !layer )
{
selectedLayer = nil;
return;
}
selectedLayer = [layer retain];
selectedLayer.frame = [self bounds];
[selectedLayer setAutoresizingMask:kCALayerWidthSizable|kCALayerHeightSizable];
}
- (void)setPreviousLayer:(VLCMediaLayer *)layer
{
[previousLayer autorelease];
if( !layer )
{
previousLayer = nil;
return;
}
previousLayer = [layer retain];
CGRect frame = [self bounds];
frame.origin.x -= frame.size.width;
previousLayer.frame = frame;
[previousLayer setAutoresizingMask:kCALayerMaxXMargin|kCALayerHeightSizable];
}
- (void)setNextLayer:(VLCMediaLayer *)layer
{
[nextLayer autorelease];
if( !layer )
{
nextLayer = nil;
return;
}
nextLayer = [layer retain];
CGRect frame = [self bounds];
frame.origin.x += frame.size.width;
nextLayer.frame = frame;
[nextLayer setAutoresizingMask:kCALayerMinXMargin|kCALayerHeightSizable];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:@"selectionIndex"])
{
if ( selectedIndex == NSNotFound || [object selectionIndex] == NSNotFound )
{
selectedIndex = [object selectionIndex];
if(selectedIndex == NSNotFound && [content count])
{
selectedIndex = 0;
}
[self resetLayers];
return;
}
[self gotoIndex: [object selectionIndex]];
return;
}
if([keyPath isEqualToString:@"arrangedObjects"] || [keyPath isEqualToString:@"contentMediaList"])
{
selectedIndex = [object selectionIndex];
if(selectedIndex == NSNotFound && [[object arrangedObjects] count])
{
selectedIndex = 0;
}
[content release];
content = [[object arrangedObjects] retain];
[self resetLayers];
return;
}
[self observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
@end