NewsBlur-viq/clients/ios/Popover/WEPopoverController.m
2013-06-27 09:43:22 -07:00

377 lines
12 KiB
Objective-C
Executable file

//
// WEPopoverController.m
// WEPopover
//
// Created by Werner Altewischer on 02/09/10.
// Copyright 2010 Werner IT Consultancy. All rights reserved.
//
#import "WEPopoverController.h"
#import "WEPopoverParentView.h"
#import "UIBarButtonItem+WEPopover.h"
#define FADE_DURATION 0.3
@interface WEPopoverController(Private)
- (UIView *)keyView;
- (void)updateBackgroundPassthroughViews;
- (void)setView:(UIView *)v;
- (CGRect)displayAreaForView:(UIView *)theView;
- (WEPopoverContainerViewProperties *)defaultContainerViewProperties;
- (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated;
@end
@implementation WEPopoverController
@synthesize contentViewController;
@synthesize popoverContentSize;
@synthesize popoverVisible;
@synthesize popoverArrowDirection;
@synthesize delegate;
@synthesize view;
@synthesize parentView;
@synthesize containerViewProperties;
@synthesize context;
@synthesize passthroughViews;
- (id)init {
if ((self = [super init])) {
}
return self;
}
- (id)initWithContentViewController:(UIViewController *)viewController {
if ((self = [self init])) {
self.contentViewController = viewController;
}
return self;
}
- (void)dealloc {
[self dismissPopoverAnimated:NO];
[contentViewController release];
[containerViewProperties release];
[passthroughViews release];
self.context = nil;
[super dealloc];
}
- (void)setContentViewController:(UIViewController *)vc {
if (vc != contentViewController) {
[contentViewController release];
contentViewController = [vc retain];
popoverContentSize = CGSizeZero;
}
}
- (BOOL)forwardAppearanceMethods {
return YES;
return ![contentViewController respondsToSelector:@selector(shouldAutomaticallyForwardAppearanceMethods)];
}
//Overridden setter to copy the passthroughViews to the background view if it exists already
- (void)setPassthroughViews:(NSArray *)array {
[passthroughViews release];
passthroughViews = nil;
if (array) {
passthroughViews = [[NSArray alloc] initWithArray:array];
}
[self updateBackgroundPassthroughViews];
}
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)theContext {
if ([animationID isEqual:@"FadeIn"]) {
self.view.userInteractionEnabled = YES;
popoverVisible = YES;
if ([self forwardAppearanceMethods]) {
[contentViewController viewDidAppear:YES];
}
} else if ([animationID isEqual:@"FadeOut"]) {
popoverVisible = NO;
if ([self forwardAppearanceMethods]) {
[contentViewController viewDidDisappear:YES];
}
[self.view removeFromSuperview];
self.view = nil;
[backgroundView removeFromSuperview];
[backgroundView release];
backgroundView = nil;
BOOL userInitiatedDismissal = [(NSNumber *)theContext boolValue];
if (userInitiatedDismissal) {
//Only send message to delegate in case the user initiated this event, which is if he touched outside the view
[delegate popoverControllerDidDismissPopover:self];
}
}
}
- (void)dismissPopoverAnimated:(BOOL)animated {
[self dismissPopoverAnimated:animated userInitiated:NO];
}
- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
animated:(BOOL)animated {
UIView *v = [self keyView];
CGRect rect = [item frameInView:v];
return [self presentPopoverFromRect:rect inView:v permittedArrowDirections:arrowDirections animated:animated];
}
- (void)presentPopoverFromRect:(CGRect)rect
inView:(UIView *)theView
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
animated:(BOOL)animated {
[self dismissPopoverAnimated:NO];
//First force a load view for the contentViewController so the popoverContentSize is properly initialized
[contentViewController view];
if (CGSizeEqualToSize(popoverContentSize, CGSizeZero)) {
popoverContentSize = contentViewController.contentSizeForViewInPopover;
}
CGRect displayArea = [self displayAreaForView:theView];
WEPopoverContainerViewProperties *props = self.containerViewProperties ? self.containerViewProperties : [self defaultContainerViewProperties];
WEPopoverContainerView *containerView = [[[WEPopoverContainerView alloc] initWithSize:self.popoverContentSize anchorRect:rect displayArea:displayArea permittedArrowDirections:arrowDirections properties:props] autorelease];
popoverArrowDirection = containerView.arrowDirection;
UIView *keyView = self.keyView;
backgroundView = [[WETouchableView alloc] initWithFrame:keyView.bounds];
backgroundView.contentMode = UIViewContentModeScaleToFill;
backgroundView.autoresizingMask = ( UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleBottomMargin);
backgroundView.backgroundColor = [UIColor clearColor];
backgroundView.delegate = self;
[keyView addSubview:backgroundView];
containerView.frame = [theView convertRect:containerView.frame toView:backgroundView];
[backgroundView addSubview:containerView];
containerView.contentView = contentViewController.view;
containerView.autoresizingMask = ( UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin);
self.view = containerView;
[self updateBackgroundPassthroughViews];
if ([self forwardAppearanceMethods]) {
[contentViewController viewWillAppear:animated];
}
[self.view becomeFirstResponder];
popoverVisible = YES;
if (animated) {
self.view.alpha = 0.0;
[UIView animateWithDuration:FADE_DURATION
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
self.view.alpha = 1.0;
} completion:^(BOOL finished) {
[self animationDidStop:@"FadeIn" finished:[NSNumber numberWithBool:finished] context:nil];
}];
} else {
if ([self forwardAppearanceMethods]) {
[contentViewController viewDidAppear:animated];
}
}
}
- (void)repositionPopoverFromRect:(CGRect)rect
inView:(UIView *)theView
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
{
[self repositionPopoverFromRect:rect
inView:theView
permittedArrowDirections:arrowDirections
animated:NO];
}
- (void)repositionPopoverFromRect:(CGRect)rect
inView:(UIView *)theView
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
animated:(BOOL)animated {
if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:FADE_DURATION];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
}
if (CGSizeEqualToSize(popoverContentSize, CGSizeZero)) {
popoverContentSize = contentViewController.contentSizeForViewInPopover;
}
CGRect displayArea = [self displayAreaForView:theView];
WEPopoverContainerView *containerView = (WEPopoverContainerView *)self.view;
[containerView updatePositionWithSize:self.popoverContentSize
anchorRect:rect
displayArea:displayArea
permittedArrowDirections:arrowDirections];
popoverArrowDirection = containerView.arrowDirection;
containerView.frame = [theView convertRect:containerView.frame toView:backgroundView];
if (animated) {
[UIView commitAnimations];
}
}
#pragma mark -
#pragma mark WETouchableViewDelegate implementation
- (void)viewWasTouched:(WETouchableView *)view {
if (popoverVisible) {
if (!delegate || [delegate popoverControllerShouldDismissPopover:self]) {
[self dismissPopoverAnimated:YES userInitiated:YES];
}
}
}
- (BOOL)isPopoverVisible {
if (!popoverVisible) {
return NO;
}
UIView *sv = self.view;
BOOL foundWindowAsSuperView = NO;
while ((sv = sv.superview) != nil) {
if ([sv isKindOfClass:[UIWindow class]]) {
foundWindowAsSuperView = YES;
break;
}
}
return foundWindowAsSuperView;
}
@end
@implementation WEPopoverController(Private)
- (UIView *)keyView {
if (self.parentView) {
return self.parentView;
} else {
UIWindow *w = [[UIApplication sharedApplication] keyWindow];
if (w.subviews.count > 0) {
return [w.subviews objectAtIndex:0];
} else {
return w;
}
}
}
- (void)setView:(UIView *)v {
if (view != v) {
[view release];
view = [v retain];
}
}
- (void)updateBackgroundPassthroughViews {
backgroundView.passthroughViews = passthroughViews;
}
- (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated {
if (self.view) {
if ([self forwardAppearanceMethods]) {
[contentViewController viewWillDisappear:animated];
}
popoverVisible = NO;
[self.view resignFirstResponder];
if (animated) {
self.view.userInteractionEnabled = NO;
[UIView animateWithDuration:FADE_DURATION
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
self.view.alpha = 0.0;
} completion:^(BOOL finished) {
[self animationDidStop:@"FadeOut" finished:[NSNumber numberWithBool:finished] context:[NSNumber numberWithBool:userInitiated]];
}];
} else {
if ([self forwardAppearanceMethods]) {
[contentViewController viewDidDisappear:animated];
}
[self.view removeFromSuperview];
self.view = nil;
[backgroundView removeFromSuperview];
[backgroundView release];
backgroundView = nil;
}
}
}
- (CGRect)displayAreaForView:(UIView *)theView {
CGRect displayArea = CGRectZero;
if ([theView conformsToProtocol:@protocol(WEPopoverParentView)] && [theView respondsToSelector:@selector(displayAreaForPopover)]) {
displayArea = [(id <WEPopoverParentView>)theView displayAreaForPopover];
} else {
UIView *keyView = [self keyView];
displayArea = [keyView convertRect:keyView.bounds toView:theView];
}
return displayArea;
}
//Enable to use the simple popover style
- (WEPopoverContainerViewProperties *)defaultContainerViewProperties {
WEPopoverContainerViewProperties *ret = [[WEPopoverContainerViewProperties new] autorelease];
CGSize imageSize = CGSizeMake(30.0f, 30.0f);
NSString *bgImageName = @"popoverBgSimple.png";
CGFloat bgMargin = 6.0;
CGFloat contentMargin = 2.0;
ret.leftBgMargin = bgMargin;
ret.rightBgMargin = bgMargin;
ret.topBgMargin = bgMargin;
ret.bottomBgMargin = bgMargin;
ret.leftBgCapSize = imageSize.width/2;
ret.topBgCapSize = imageSize.height/2;
ret.bgImageName = bgImageName;
ret.leftContentMargin = contentMargin;
ret.rightContentMargin = contentMargin;
ret.topContentMargin = contentMargin;
ret.bottomContentMargin = contentMargin;
ret.arrowMargin = 1.0;
ret.upArrowImageName = @"popoverArrowUpSimple.png";
ret.downArrowImageName = @"popoverArrowDownSimple.png";
ret.leftArrowImageName = @"popoverArrowLeftSimple.png";
ret.rightArrowImageName = @"popoverArrowRightSimple.png";
return ret;
}
@end