Project import
diff --git a/WEPopover/LICENSE b/WEPopover/LICENSE
new file mode 100755
index 0000000..163d133
--- /dev/null
+++ b/WEPopover/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Werner IT Consultancy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/WEPopover/UIBarButtonItem+WEPopover.h b/WEPopover/UIBarButtonItem+WEPopover.h
new file mode 100755
index 0000000..0b8391a
--- /dev/null
+++ b/WEPopover/UIBarButtonItem+WEPopover.h
@@ -0,0 +1,15 @@
+/*
+ * UIBarButtonItem+WEPopover.h
+ * WEPopover
+ *
+ * Created by Werner Altewischer on 07/05/11.
+ * Copyright 2010 Werner IT Consultancy. All rights reserved.
+ *
+ */
+
+@interface UIBarButtonItem(WEPopover)
+
+- (CGRect)frameInView:(UIView *)v;
+- (UIView *)superview;
+
+@end
diff --git a/WEPopover/UIBarButtonItem+WEPopover.m b/WEPopover/UIBarButtonItem+WEPopover.m
new file mode 100755
index 0000000..06faf17
--- /dev/null
+++ b/WEPopover/UIBarButtonItem+WEPopover.m
@@ -0,0 +1,50 @@
+/*
+ * UIBarButtonItem+WEPopover.m
+ * WEPopover
+ *
+ * Created by Werner Altewischer on 07/05/11.
+ * Copyright 2010 Werner IT Consultancy. All rights reserved.
+ *
+ */
+
+#import "UIBarButtonItem+WEPopover.h"
+
+@implementation UIBarButtonItem(WEPopover)
+
+- (CGRect)frameInView:(UIView *)v {
+
+ BOOL hasCustomView = (self.customView != nil);
+
+ if (!hasCustomView) {
+ UIView *tempView = [[UIView alloc] initWithFrame:CGRectZero];
+ self.customView = tempView;
+ }
+
+ UIView *parentView = self.customView.superview;
+ NSUInteger indexOfView = [parentView.subviews indexOfObject:self.customView];
+
+ if (!hasCustomView) {
+ self.customView = nil;
+ }
+ UIView *button = [parentView.subviews objectAtIndex:indexOfView];
+ return [parentView convertRect:button.frame toView:v];
+}
+
+- (UIView *)superview {
+
+ BOOL hasCustomView = (self.customView != nil);
+
+ if (!hasCustomView) {
+ UIView *tempView = [[UIView alloc] initWithFrame:CGRectZero];
+ self.customView = tempView;
+ }
+
+ UIView *parentView = self.customView.superview;
+
+ if (!hasCustomView) {
+ self.customView = nil;
+ }
+ return parentView;
+}
+
+@end
diff --git a/WEPopover/WEPopoverContainerView.h b/WEPopover/WEPopoverContainerView.h
new file mode 100755
index 0000000..93d1d3e
--- /dev/null
+++ b/WEPopover/WEPopoverContainerView.h
@@ -0,0 +1,98 @@
+//
+// WEPopoverContainerView.h
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ * @brief Properties for the container view determining the area where the actual content view can/may be displayed. Also Images can be supplied for the arrow images and background.
+ */
+@interface WEPopoverContainerViewProperties : NSObject
+{
+ NSString *bgImageName;
+ NSString *upArrowImageName;
+ NSString *downArrowImageName;
+ NSString *leftArrowImageName;
+ NSString *rightArrowImageName;
+ CGFloat leftBgMargin;
+ CGFloat rightBgMargin;
+ CGFloat topBgMargin;
+ CGFloat bottomBgMargin;
+ NSInteger topBgCapSize;
+ NSInteger leftBgCapSize;
+ CGFloat arrowMargin;
+}
+
+@property(nonatomic, strong) NSString *bgImageName;
+@property(nonatomic, strong) NSString *upArrowImageName;
+@property(nonatomic, strong) NSString *downArrowImageName;
+@property(nonatomic, strong) NSString *leftArrowImageName;
+@property(nonatomic, strong) NSString *rightArrowImageName;
+@property(nonatomic, assign) CGFloat leftBgMargin;
+@property(nonatomic, assign) CGFloat rightBgMargin;
+@property(nonatomic, assign) CGFloat topBgMargin;
+@property(nonatomic, assign) CGFloat bottomBgMargin;
+@property(nonatomic, assign) CGFloat leftContentMargin;
+@property(nonatomic, assign) CGFloat rightContentMargin;
+@property(nonatomic, assign) CGFloat topContentMargin;
+@property(nonatomic, assign) CGFloat bottomContentMargin;
+@property(nonatomic, assign) NSInteger topBgCapSize;
+@property(nonatomic, assign) NSInteger leftBgCapSize;
+@property(nonatomic, assign) CGFloat arrowMargin;
+
+@end
+
+@class WEPopoverContainerView;
+
+/**
+ * @brief Container/background view for displaying a popover view.
+ */
+@interface WEPopoverContainerView : UIView {
+ UIImage *bgImage;
+ UIImage *arrowImage;
+
+ WEPopoverContainerViewProperties *properties;
+
+ UIPopoverArrowDirection arrowDirection;
+
+ CGRect arrowRect;
+ CGRect bgRect;
+ CGPoint offset;
+ CGPoint arrowOffset;
+
+ CGSize correctedSize;
+ UIView *contentView;
+}
+
+/**
+ * @brief The current arrow direction for the popover.
+ */
+@property (nonatomic, readonly) UIPopoverArrowDirection arrowDirection;
+
+/**
+ * @brief The content view being displayed.
+ */
+@property (nonatomic, strong) UIView *contentView;
+
+/**
+ * @brief Initializes the position of the popover with a size, anchor rect, display area and permitted arrow directions and optionally the properties.
+ * If the last is not supplied the defaults are taken (requires images to be present in bundle representing a black rounded background with partial transparency).
+ */
+- (id)initWithSize:(CGSize)theSize
+ anchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections
+ properties:(WEPopoverContainerViewProperties *)properties;
+
+/**
+ * @brief To update the position of the popover with a new anchor rect, display area and permitted arrow directions
+ */
+- (void)updatePositionWithAnchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+ permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
+
+@end
diff --git a/WEPopover/WEPopoverContainerView.m b/WEPopover/WEPopoverContainerView.m
new file mode 100755
index 0000000..b40f875
--- /dev/null
+++ b/WEPopover/WEPopoverContainerView.m
@@ -0,0 +1,204 @@
+//
+// WEPopoverContainerViewProperties.m
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import "WEPopoverContainerView.h"
+
+@implementation WEPopoverContainerViewProperties
+
+@synthesize bgImageName, upArrowImageName, downArrowImageName, leftArrowImageName, rightArrowImageName, topBgMargin, bottomBgMargin, leftBgMargin, rightBgMargin, topBgCapSize, leftBgCapSize;
+@synthesize leftContentMargin, rightContentMargin, topContentMargin, bottomContentMargin, arrowMargin;
+
+
+@end
+
+@interface WEPopoverContainerView(Private)
+
+- (void)determineGeometryForSize:(CGSize)theSize anchorRect:(CGRect)anchorRect displayArea:(CGRect)displayArea permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections;
+- (CGRect)contentRect;
+- (CGSize)contentSize;
+- (void)setProperties:(WEPopoverContainerViewProperties *)props;
+- (void)initFrame;
+
+@end
+
+@implementation WEPopoverContainerView
+
+@synthesize arrowDirection, contentView;
+
+- (id)initWithSize:(CGSize)theSize
+ anchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections
+ properties:(WEPopoverContainerViewProperties *)theProperties {
+ if ((self = [super initWithFrame:CGRectZero])) {
+
+ [self setProperties:theProperties];
+ correctedSize = CGSizeMake(theSize.width + properties.leftBgMargin + properties.rightBgMargin + properties.leftContentMargin + properties.rightContentMargin,
+ theSize.height + properties.topBgMargin + properties.bottomBgMargin + properties.topContentMargin + properties.bottomContentMargin);
+ [self determineGeometryForSize:correctedSize anchorRect:anchorRect displayArea:displayArea permittedArrowDirections:permittedArrowDirections];
+ [self initFrame];
+ self.backgroundColor = [UIColor clearColor];
+ UIImage *theImage = [UIImage imageNamed:properties.bgImageName];
+ bgImage = [theImage stretchableImageWithLeftCapWidth:properties.leftBgCapSize topCapHeight:properties.topBgCapSize];
+
+ self.clipsToBounds = YES;
+ self.userInteractionEnabled = YES;
+
+ self.layer.shadowOffset = CGSizeMake(3, 3);
+ self.layer.shadowRadius = 6;
+ self.layer.shadowOpacity = 0.3;
+ self.clipsToBounds = NO;
+ }
+ return self;
+}
+
+
+- (void)drawRect:(CGRect)rect {
+ [bgImage drawInRect:bgRect blendMode:kCGBlendModeNormal alpha:1.0];
+ [arrowImage drawInRect:arrowRect blendMode:kCGBlendModeNormal alpha:1.0];
+}
+
+- (void)updatePositionWithAnchorRect:(CGRect)anchorRect
+ displayArea:(CGRect)displayArea
+ permittedArrowDirections:(UIPopoverArrowDirection)permittedArrowDirections {
+ [self determineGeometryForSize:correctedSize anchorRect:anchorRect displayArea:displayArea permittedArrowDirections:permittedArrowDirections];
+ [self initFrame];
+}
+
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
+ return CGRectContainsPoint(self.contentRect, point);
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+
+}
+
+- (void)setContentView:(UIView *)v {
+ if (v != contentView) {
+ contentView = v;
+ contentView.frame = self.contentRect;
+ [self addSubview:contentView];
+ }
+}
+
+
+
+@end
+
+@implementation WEPopoverContainerView(Private)
+
+- (void)initFrame {
+ CGRect theFrame = CGRectOffset(CGRectUnion(bgRect, arrowRect), offset.x, offset.y);
+
+ //If arrow rect origin is < 0 the frame above is extended to include it so we should offset the other rects
+ arrowOffset = CGPointMake(MAX(0, -arrowRect.origin.x), MAX(0, -arrowRect.origin.y));
+ bgRect = CGRectOffset(bgRect, arrowOffset.x, arrowOffset.y);
+ arrowRect = CGRectOffset(arrowRect, arrowOffset.x, arrowOffset.y);
+
+ self.frame = theFrame;
+}
+
+- (CGSize)contentSize {
+ return self.contentRect.size;
+}
+
+- (CGRect)contentRect {
+ CGRect rect = CGRectMake(properties.leftBgMargin + properties.leftContentMargin + arrowOffset.x,
+ properties.topBgMargin + properties.topContentMargin + arrowOffset.y,
+ bgRect.size.width - properties.leftBgMargin - properties.rightBgMargin - properties.leftContentMargin - properties.rightContentMargin,
+ bgRect.size.height - properties.topBgMargin - properties.bottomBgMargin - properties.topContentMargin - properties.bottomContentMargin);
+ return rect;
+}
+
+- (void)setProperties:(WEPopoverContainerViewProperties *)props {
+ if (properties != props) {
+ properties = props;
+ }
+}
+
+// NOTE: this method is completely rewritten by Nest Labs to do layout that meets our UI needs.
+// It's kinda shoehorned in so we didn't need to modify other WEPopover code.
+// It's not a general solution, does not obey supportedArrowDirections, and has bugs.
+// Sorry.
+- (void)determineGeometryForSize:(CGSize)theSize anchorRect:(CGRect)anchorRect displayArea:(CGRect)displayArea permittedArrowDirections:(UIPopoverArrowDirection)supportedArrowDirections {
+ UIImage *downArrowImage = [UIImage imageNamed:properties.downArrowImageName];
+ UIImage *leftArrowImage = [UIImage imageNamed:properties.leftArrowImageName];
+ UIImage *rightArrowImage = [UIImage imageNamed:properties.rightArrowImageName];
+
+ // try displaying above anchor
+ float topFreeSpace = (anchorRect.origin.y - (theSize.height + downArrowImage.size.height)) - displayArea.origin.y;
+ float leftFreeSpace = CGRectGetMidX(anchorRect) - CGRectGetMinX(displayArea);
+ float rightFreeSpace = CGRectGetMaxX(displayArea) - CGRectGetMidX(anchorRect);
+ if ((topFreeSpace >= 0) && (leftFreeSpace >= (rightArrowImage.size.width / 2) + 16) && (rightFreeSpace >= (leftArrowImage.size.width / 2) + 16)) {
+ bgRect = CGRectMake(0, 0, theSize.width, theSize.height);
+ arrowRect = CGRectMake((theSize.width - downArrowImage.size.width) / 2, theSize.height, downArrowImage.size.width, downArrowImage.size.height);
+ offset = CGPointMake(CGRectGetMidX(anchorRect) - (bgRect.size.width / 2), -(arrowRect.origin.y + arrowRect.size.height - anchorRect.origin.y));
+ arrowDirection = UIPopoverArrowDirectionDown;
+ arrowImage = downArrowImage;
+
+ // ...check for going off right edge
+ float overage = (bgRect.size.width + offset.x) - (displayArea.origin.x + displayArea.size.width);
+ if (overage > 0) {
+ arrowRect = CGRectOffset(arrowRect, overage, 0);
+ offset.x -= overage;
+ }
+
+ // ...check for going off left edge
+ float underage = offset.x - displayArea.origin.x;
+ if (underage < 0) {
+ arrowRect = CGRectOffset(arrowRect, underage, 0);
+ offset.x -= underage;
+ }
+ } else {
+ // try left or right side
+ if (leftFreeSpace > rightFreeSpace) {
+ // ...to left
+ bgRect = CGRectMake(0, 0, theSize.width, theSize.height);
+ arrowRect = CGRectMake(theSize.width, (theSize.height - rightArrowImage.size.height) / 2, rightArrowImage.size.width, rightArrowImage.size.height);
+ offset = CGPointMake(anchorRect.origin.x - theSize.width - rightArrowImage.size.width, -((theSize.height - anchorRect.size.height) / 2) + anchorRect.origin.y);
+ arrowDirection = UIPopoverArrowDirectionRight;
+ arrowImage = rightArrowImage;
+ } else {
+ // ...to right
+ bgRect = CGRectMake(0, 0, theSize.width, theSize.height);
+ arrowRect = CGRectMake(-leftArrowImage.size.width, (theSize.height - leftArrowImage.size.height) / 2, leftArrowImage.size.width, leftArrowImage.size.height);
+ offset = CGPointMake(anchorRect.origin.x + anchorRect.size.width + leftArrowImage.size.width, -((theSize.height - anchorRect.size.height) / 2) + anchorRect.origin.y);
+ arrowDirection = UIPopoverArrowDirectionLeft;
+ arrowImage = leftArrowImage;
+ }
+
+ // ...check for going off bottom
+ float overage = (CGRectGetMaxY(bgRect) + offset.y) - CGRectGetMaxY(displayArea);
+ if (overage > 0) {
+ overage = MIN(overage, CGRectGetMaxY(bgRect) - CGRectGetMaxY(arrowRect) - 12);
+ arrowRect = CGRectOffset(arrowRect, 0, overage);
+ offset.y -= overage;
+ }
+
+ // ...check for going off top
+ float underage = (CGRectGetMinY(bgRect) + offset.y) - CGRectGetMinY(displayArea);
+ if (underage < 0) {
+ arrowRect = CGRectOffset(arrowRect, 0, underage);
+ offset.y -= underage;
+ }
+ }
+}
+
+@end
\ No newline at end of file
diff --git a/WEPopover/WEPopoverController.h b/WEPopover/WEPopoverController.h
new file mode 100755
index 0000000..aebc0f0
--- /dev/null
+++ b/WEPopover/WEPopoverController.h
@@ -0,0 +1,67 @@
+//
+// WEPopoverController.h
+// WEPopover
+//
+// Created by Werner Altewischer on 02/09/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "WEPopoverContainerView.h"
+#import "WETouchableView.h"
+
+@class WEPopoverController;
+
+@protocol WEPopoverControllerDelegate<NSObject>
+
+- (void)popoverControllerDidDismissPopover:(WEPopoverController *)popoverController;
+- (BOOL)popoverControllerShouldDismissPopover:(WEPopoverController *)popoverController;
+
+@end
+
+/**
+ * @brief Popover controller for the iPhone, mimicing the iPad UIPopoverController interface. See that class for more details.
+ */
+@interface WEPopoverController : NSObject<WETouchableViewDelegate> {
+ UIViewController *contentViewController;
+ UIView *__weak view;
+ WETouchableView *backgroundView;
+
+ BOOL popoverVisible;
+ UIPopoverArrowDirection popoverArrowDirection;
+ id <WEPopoverControllerDelegate> __weak delegate;
+ CGSize popoverContentSize;
+ WEPopoverContainerViewProperties *containerViewProperties;
+ id <NSObject> context;
+ NSArray *passthroughViews;
+}
+
+@property(nonatomic, strong) UIViewController *contentViewController;
+
+@property (weak, nonatomic, readonly) UIView *view;
+@property (nonatomic, readonly, getter=isPopoverVisible) BOOL popoverVisible;
+@property (nonatomic, readonly) UIPopoverArrowDirection popoverArrowDirection;
+@property (nonatomic, weak) id <WEPopoverControllerDelegate> delegate;
+@property (nonatomic, assign) CGSize popoverContentSize;
+@property (nonatomic, strong) WEPopoverContainerViewProperties *containerViewProperties;
+@property (nonatomic, strong) id <NSObject> context;
+@property (nonatomic, copy) NSArray *passthroughViews;
+
+- (id)initWithContentViewController:(UIViewController *)theContentViewController;
+
+- (void)dismissPopoverAnimated:(BOOL)animated;
+
+- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated;
+
+- (void)presentPopoverFromRect:(CGRect)rect
+ inView:(UIView *)view
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
+ animated:(BOOL)animated;
+
+- (void)repositionPopoverFromRect:(CGRect)rect
+ inView:(UIView *)view
+ permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections;
+
+@end
diff --git a/WEPopover/WEPopoverController.m b/WEPopover/WEPopoverController.m
new file mode 100755
index 0000000..b173ed0
--- /dev/null
+++ b/WEPopover/WEPopoverController.m
@@ -0,0 +1,278 @@
+//
+// 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];
+
+ 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
+ // NEST: edit to avoid warning
+ if (contentViewController.view == nil) return;
+
+ 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];
+ 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];
+
+ [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 = @"popoverBgSimple.png";
+ CGFloat bgMargin = 0.0;
+ CGFloat contentMargin = 12.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
diff --git a/WEPopover/WEPopoverParentView.h b/WEPopover/WEPopoverParentView.h
new file mode 100755
index 0000000..111f8fa
--- /dev/null
+++ b/WEPopover/WEPopoverParentView.h
@@ -0,0 +1,15 @@
+/*
+ * WEPopoverParentView.h
+ * WEPopover
+ *
+ * Created by Werner Altewischer on 02/09/10.
+ * Copyright 2010 Werner IT Consultancy. All rights reserved.
+ *
+ */
+
+@protocol WEPopoverParentView
+
+@optional
+- (CGRect)displayAreaForPopover;
+
+@end
\ No newline at end of file
diff --git a/WEPopover/WETouchableView.h b/WEPopover/WETouchableView.h
new file mode 100755
index 0000000..5b8321f
--- /dev/null
+++ b/WEPopover/WETouchableView.h
@@ -0,0 +1,36 @@
+//
+// WETouchableView.h
+// WEPopover
+//
+// Created by Werner Altewischer on 12/21/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class WETouchableView;
+
+/**
+ * @brief delegate to receive touch events
+ */
+@protocol WETouchableViewDelegate<NSObject>
+
+- (void)viewWasTouched:(WETouchableView *)view;
+
+@end
+
+/**
+ * @brief View that can handle touch events and/or disable touch forwording to child views
+ */
+@interface WETouchableView : UIView {
+ BOOL touchForwardingDisabled;
+ id <WETouchableViewDelegate> __weak delegate;
+ NSArray *passthroughViews;
+ BOOL testHits;
+}
+
+@property (nonatomic, assign) BOOL touchForwardingDisabled;
+@property (nonatomic, weak) id <WETouchableViewDelegate> delegate;
+@property (nonatomic, copy) NSArray *passthroughViews;
+
+@end
diff --git a/WEPopover/WETouchableView.m b/WEPopover/WETouchableView.m
new file mode 100755
index 0000000..304ed39
--- /dev/null
+++ b/WEPopover/WETouchableView.m
@@ -0,0 +1,66 @@
+//
+// WETouchableView.m
+// WEPopover
+//
+// Created by Werner Altewischer on 12/21/10.
+// Copyright 2010 Werner IT Consultancy. All rights reserved.
+//
+
+#import "WETouchableView.h"
+
+@interface WETouchableView(Private)
+
+- (BOOL)isPassthroughView:(UIView *)v;
+
+@end
+
+@implementation WETouchableView
+
+@synthesize touchForwardingDisabled, delegate, passthroughViews;
+
+
+- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
+ if (testHits) {
+ return nil;
+ } else if (touchForwardingDisabled) {
+ return self;
+ } else {
+ UIView *hitView = [super hitTest:point withEvent:event];
+
+ if (hitView == self) {
+ //Test whether any of the passthrough views would handle this touch
+ testHits = YES;
+ UIView *superHitView = [self.superview hitTest:point withEvent:event];
+ testHits = NO;
+
+ if ([self isPassthroughView:superHitView]) {
+ hitView = superHitView;
+ }
+ }
+
+ return hitView;
+ }
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ [self.delegate viewWasTouched:self];
+}
+
+@end
+
+@implementation WETouchableView(Private)
+
+- (BOOL)isPassthroughView:(UIView *)v {
+
+ if (v == nil) {
+ return NO;
+ }
+
+ if ([passthroughViews containsObject:v]) {
+ return YES;
+ }
+
+ return [self isPassthroughView:v.superview];
+}
+
+@end