blob: 8770866a8ebd288fe4aff13fd2ec756c2ea21516 [file] [log] [blame]
//
// 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 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];
}
- (void)setContentViewController:(UIViewController *)vc {
if (vc != contentViewController) {
contentViewController = vc;
popoverContentSize = CGSizeZero;
}
}
//Overridden setter to copy the passthroughViews to the background view if it exists already
- (void)setPassthroughViews:(NSArray *)array {
passthroughViews = nil;
if (array) {
passthroughViews = [[NSArray alloc] initWithArray:array];
}
[self updateBackgroundPassthroughViews];
}
- (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];
[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
// NEST: edit to avoid warning
if (contentViewController.view == nil) return;
if (CGSizeEqualToSize(popoverContentSize, CGSizeZero)) {
popoverContentSize = contentViewController.preferredContentSize;
}
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];
popoverArrowDirection = containerView.arrowDirection;
UIView *topView = theView;
while (topView.superview.superview != nil) topView = topView.superview;
UIView *keyView = topView;
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];
[contentViewController viewWillAppear:animated];
[self.view becomeFirstResponder];
if (animated) {
self.view.alpha = 0.0;
[UIView animateWithDuration:FADE_DURATION animations:^{
self.view.alpha = 1.0;
} completion:^(BOOL finished) {
self.view.userInteractionEnabled = YES;
popoverVisible = YES;
[contentViewController viewDidAppear:YES];
}];
} else {
popoverVisible = YES;
[contentViewController viewDidAppear:animated];
}
}
- (void)repositionPopoverFromRect:(CGRect)rect
inView:(UIView *)theView
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections {
CGRect displayArea = [self displayAreaForView:theView];
WEPopoverContainerView *containerView = (WEPopoverContainerView *)self.view;
[containerView updatePositionWithAnchorRect:rect
displayArea:displayArea
permittedArrowDirections:arrowDirections];
popoverArrowDirection = containerView.arrowDirection;
containerView.frame = [theView convertRect:containerView.frame toView:backgroundView];
}
#pragma mark -
#pragma mark WETouchableViewDelegate implementation
- (void)viewWasTouched:(WETouchableView *)view {
if (popoverVisible) {
if (!delegate || [delegate popoverControllerShouldDismissPopover:self]) {
[self dismissPopoverAnimated:YES userInitiated:YES];
}
}
}
@end
@implementation WEPopoverController(Private)
- (UIView *)keyView {
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 = v;
}
}
- (void)updateBackgroundPassthroughViews {
backgroundView.passthroughViews = passthroughViews;
}
- (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated {
if (self.view) {
[contentViewController viewWillDisappear:animated];
popoverVisible = NO;
[self.view resignFirstResponder];
if (animated) {
self.view.userInteractionEnabled = NO;
[UIView animateWithDuration:FADE_DURATION animations:^{
self.view.alpha = 0.0;
} completion:^(BOOL finished) {
popoverVisible = NO;
[contentViewController viewDidDisappear:YES];
[self.view removeFromSuperview];
self.view = nil;
[backgroundView removeFromSuperview];
backgroundView = nil;
if (userInitiated) {
//Only send message to delegate in case the user initiated this event, which is if he touched outside the view
[delegate popoverControllerDidDismissPopover:self];
}
}];
} else {
[contentViewController viewDidDisappear:animated];
[self.view removeFromSuperview];
self.view = nil;
[backgroundView removeFromSuperview];
backgroundView = nil;
}
}
}
- (CGRect)displayAreaForView:(UIView *)theView {
CGRect displayArea = CGRectZero;
if ([theView conformsToProtocol:@protocol(WEPopoverParentView)] && [theView respondsToSelector:@selector(displayAreaForPopover)]) {
displayArea = [(id <WEPopoverParentView>)theView displayAreaForPopover];
} else {
displayArea = [[[UIApplication sharedApplication] keyWindow] convertRect:[[UIScreen mainScreen] applicationFrame] toView:theView];
displayArea = CGRectInset(displayArea, 6, 6); // give some margin from the edges of the screen
}
return displayArea;
}
//Enable to use the simple popover style
- (WEPopoverContainerViewProperties *)defaultContainerViewProperties {
WEPopoverContainerViewProperties *ret = [WEPopoverContainerViewProperties new];
CGSize imageSize = CGSizeMake(30.0f, 30.0f);
NSString *bgImageName = nl_img_popover_bg_simple;
CGFloat bgMargin = 0.0f;
CGFloat contentMargin = 12.0f;
ret.leftBgMargin = bgMargin;
ret.rightBgMargin = bgMargin;
ret.topBgMargin = bgMargin;
ret.bottomBgMargin = bgMargin;
ret.leftBgCapSize = (NSInteger)(imageSize.width/2);
ret.topBgCapSize = (NSInteger)(imageSize.height/2);
ret.bgImageName = bgImageName;
ret.leftContentMargin = contentMargin;
ret.rightContentMargin = contentMargin;
ret.topContentMargin = contentMargin;
ret.bottomContentMargin = contentMargin;
ret.arrowMargin = 1.0f;
ret.upArrowImageName = nl_img_popover_arrow_up_simple;
ret.downArrowImageName = nl_img_popover_arrow_down_simple;
ret.leftArrowImageName = nl_img_popover_arrow_left_simple;
ret.rightArrowImageName = nl_img_popover_arrow_right_simple;
return ret;
}
@end