├── FWTPopoverView_Test ├── icon.png ├── FWTPopoverView_Test │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Default.png │ ├── Default@2x.png │ ├── button_back.png │ ├── button_back@2x.png │ ├── button_trash.png │ ├── icon_project.png │ ├── Default-568h@2x.png │ ├── button_trash@2x.png │ ├── icon_project@2x.png │ ├── AppDelegate.h │ ├── ViewController.h │ ├── main.m │ ├── FWTPopoverView_Test-Prefix.pch │ ├── AppDelegate.m │ ├── FWTPopoverView_Test-Info.plist │ └── ViewController.m ├── icon@2x.png └── FWTPopoverView_Test.xcodeproj │ └── project.pbxproj ├── .gitmodules ├── FWTPopoverView ├── FWTPopoverView │ ├── FWTPopoverView-Prefix.pch │ ├── FWTPopoverArrow.h │ ├── FWTPopoverBackgroundHelper.h │ ├── FWTPopoverAnimationHelper.h │ ├── FWTPopoverView.h │ ├── FWTPopoverArrow.m │ ├── FWTPopoverAnimationHelper.m │ ├── FWTPopoverBackgroundHelper.m │ └── FWTPopoverView.m └── FWTPopoverView.xcodeproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ └── project.pbxproj ├── FWTPopover.xcworkspace └── contents.xcworkspacedata ├── .gitignore ├── FWTPopover.podspec ├── README.md └── LICENSE /FWTPopoverView_Test/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/icon.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "RistrettoUI"] 2 | path = RistrettoUI 3 | url = git@github.com:marciomeschini/RistrettoUI.git 4 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/icon@2x.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/Default.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/Default@2x.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/button_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/button_back.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/button_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/button_back@2x.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/button_trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/button_trash.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/icon_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/icon_project.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/Default-568h@2x.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/button_trash@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/button_trash@2x.png -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/icon_project@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FutureWorkshops/FWTPopover/HEAD/FWTPopoverView_Test/FWTPopoverView_Test/icon_project@2x.png -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverView-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'FWTPopoverView' target in the 'FWTPopoverView' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FWTPopoverView_Test 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FWTPopoverView_Test 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import "RistrettoViewController.h" 10 | 11 | @interface ViewController : RistrettoViewController 12 | @property (nonatomic, assign) BOOL manyPopoversEnabled; 13 | @end 14 | -------------------------------------------------------------------------------- /FWTPopover.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FWTPopoverView_Test 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/FWTPopoverView_Test-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'FWTPopoverView_Test' target in the 'FWTPopoverView_Test' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iOS SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #import "RistrettoUI.h" 15 | #endif 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ruby 2 | tmp/ 3 | log/ 4 | db/production.sqlite3 5 | db/development.sqlite3 6 | 7 | # Xcode 8 | build/* 9 | *.pbxuser 10 | !default.pbxuser 11 | *.mode1v3 12 | !default.mode1v3 13 | *.mode2v3 14 | !default.mode2v3 15 | *.perspectivev3 16 | !default.perspectivev3 17 | !default.xcworkspace 18 | xcuserdata 19 | profile 20 | *.moved-aside 21 | # Finder 22 | .DS_Store 23 | .svn 24 | *.swp 25 | *.~nib 26 | 27 | # Frank 28 | Frank/frankified_build/ 29 | Frank/rerun.txt 30 | 31 | # Cocoapods 32 | /Pods/ 33 | 34 | /.idea/ 35 | /features 36 | -------------------------------------------------------------------------------- /FWTPopover.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "FWTPopover" 3 | s.version = "1.3.0" 4 | s.summary = "FWTPopoverView is a pretty flexible custom view for when you need a classic popover with a pointing arrow." 5 | s.homepage = "https://github.com/FutureWorkshops/FWTPopover" 6 | s.license = { :type => 'Apache License Version 2.0', :file => 'LICENSE' } 7 | s.author = { 'Marco Meschini' => 'marco@futureworkshops.com' } 8 | s.source = { :git => "https://github.com/FutureWorkshops/FWTPopover.git", :tag => "1.3.0" } 9 | s.platform = :ios 10 | s.source_files = 'FWTPopoverView/FWTPopoverView' 11 | s.framework = 'QuartzCore' 12 | end 13 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverArrow.h: -------------------------------------------------------------------------------- 1 | // 2 | // FWTAnnotationArrow.h 3 | // FWTAnnotationManager 4 | // 5 | // Created by Marco Meschini on 30/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_OPTIONS(NSUInteger, FWTPopoverArrowDirection) { 12 | FWTPopoverArrowDirectionNone = 1UL << 0, 13 | FWTPopoverArrowDirectionUp = 1UL << 1, 14 | FWTPopoverArrowDirectionDown = 1UL << 2, 15 | FWTPopoverArrowDirectionLeft = 1UL << 3, 16 | FWTPopoverArrowDirectionRight = 1UL << 4, 17 | }; 18 | 19 | @interface FWTPopoverArrow : NSObject 20 | 21 | @property (nonatomic, readonly, assign) FWTPopoverArrowDirection direction; 22 | @property (nonatomic, assign) CGSize size; 23 | @property (nonatomic, readonly, assign) CGFloat offset; 24 | @property (nonatomic, assign) CGFloat cornerOffset; 25 | 26 | - (UIEdgeInsets)adjustedEdgeInsetsForEdgeInsets:(UIEdgeInsets)edgeInsets; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverBackgroundHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // FWTAnnotationBackgroundHelper.h 3 | // FWTAnnotationManager 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class FWTPopoverView, FWTPopoverBackgroundHelper; 13 | 14 | typedef void (^FWTAnnotationViewDrawBezierPathBlock)(FWTPopoverBackgroundHelper *, CGContextRef); 15 | 16 | @interface FWTPopoverBackgroundHelper : CAShapeLayer 17 | 18 | @property (nonatomic, readonly, assign) FWTPopoverView *annotationView; 19 | @property (nonatomic, copy) FWTAnnotationViewDrawBezierPathBlock drawPathBlock; 20 | @property (nonatomic, readonly, assign) CGRect pathFrame; 21 | 22 | - (id)initWithAnnotationView:(FWTPopoverView *)annotationView; 23 | 24 | - (UIImage *)resizableBackgroundImageForSize:(CGSize)size edgeInsets:(UIEdgeInsets)edgeInsets; 25 | 26 | - (UIBezierPath *)bezierPathForRect:(CGRect)rect; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverAnimationHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // FWTAnnotationAnimationHelper.h 3 | // FWTAnnotationManager 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class FWTPopoverView; 12 | typedef void (^FWTAnnotationAnimationPrepareBlock)(void); 13 | typedef void (^FWTAnnotationAnimationChangesBlock)(void); 14 | typedef void (^FWTAnnotationAnimationCompletionBlock)(BOOL finished); 15 | 16 | @interface FWTPopoverAnimationHelper : NSObject 17 | 18 | @property (nonatomic, readonly, assign) FWTPopoverView *annotationView; 19 | @property (nonatomic, assign) CGFloat presentDuration, dismissDuration, adjustPositionDuration; 20 | @property (nonatomic, assign) CGFloat presentDelay, dismissDelay; 21 | @property (nonatomic, assign) UIViewAnimationOptions presentOptions, dismissOptions; 22 | @property (nonatomic, copy) FWTAnnotationAnimationPrepareBlock prepareBlock; 23 | @property (nonatomic, copy) FWTAnnotationAnimationChangesBlock presentAnimationsBlock, dismissAnimationsBlock; 24 | @property (nonatomic, copy) FWTAnnotationAnimationCompletionBlock presentCompletionBlock, dismissCompletionBlock; 25 | 26 | - (id)initWithAnnotationView:(FWTPopoverView *)annotationView; 27 | 28 | - (void)safePerformBlock:(void (^)(void))block; 29 | - (void)safePerformCompletionBlock:(void (^)(BOOL finished))block finished:(BOOL)finished; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FWTPopoverHintView.h 3 | // FWTPopoverHintView 4 | // 5 | // Created by Marco Meschini on 7/12/12. 6 | // Copyright (c) 2012 Futureworkshops. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FWTPopoverArrow.h" 11 | #import "FWTPopoverBackgroundHelper.h" 12 | #import "FWTPopoverAnimationHelper.h" 13 | 14 | @class FWTPopoverView; 15 | typedef void (^FWTPopoverViewDidPresentBlock)(FWTPopoverView *); 16 | typedef void (^FWTPopoverViewDidDismissBlock)(FWTPopoverView *); 17 | 18 | @interface FWTPopoverView : UIView 19 | 20 | @property (nonatomic, readonly, retain) UIView *contentView; 21 | @property (nonatomic, assign) CGSize contentSize; 22 | @property (nonatomic, assign) BOOL adjustPositionInSuperviewEnabled; 23 | 24 | @property (nonatomic, retain) FWTPopoverBackgroundHelper *backgroundHelper; 25 | @property (nonatomic, retain) FWTPopoverArrow *arrow; 26 | @property (nonatomic, retain) FWTPopoverAnimationHelper *animationHelper; 27 | 28 | @property (nonatomic, copy) FWTPopoverViewDidPresentBlock didPresentBlock; 29 | @property (nonatomic, copy) FWTPopoverViewDidDismissBlock didDismissBlock; 30 | 31 | // 32 | - (void)presentFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirection:(FWTPopoverArrowDirection)arrowDirection animated:(BOOL)animated; 33 | 34 | // 35 | - (void)adjustPositionToRect:(CGRect)rect; 36 | - (void)adjustPositionToRect:(CGRect)rect animated:(BOOL)animated; 37 | 38 | // 39 | - (void)dismissPopoverAnimated:(BOOL)animated; 40 | 41 | // 42 | - (CGRect)arrowRect; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverArrow.m: -------------------------------------------------------------------------------- 1 | // 2 | // FWTAnnotationArrow.m 3 | // FWTAnnotationManager 4 | // 5 | // Created by Marco Meschini on 30/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import "FWTPopoverArrow.h" 10 | 11 | #define FWT_PA_DIRECTION FWTPopoverArrowDirectionNone 12 | #define FWT_PA_SIZE CGSizeMake(10.0f, 10.0f) 13 | #define FWT_PA_OFFSET .0f 14 | #define FWT_PA_CORNER_OFFSET .0f 15 | 16 | @interface FWTPopoverArrow () 17 | @property (nonatomic, readwrite, assign) FWTPopoverArrowDirection direction; 18 | @property (nonatomic, readwrite, assign) CGFloat offset; 19 | @end 20 | 21 | @implementation FWTPopoverArrow 22 | @synthesize direction = _direction; 23 | 24 | - (id)init 25 | { 26 | if ((self = [super init])) 27 | { 28 | self.direction = FWT_PA_DIRECTION; 29 | self.size = FWT_PA_SIZE; 30 | self.offset = FWT_PA_OFFSET; 31 | self.cornerOffset = FWT_PA_CORNER_OFFSET; 32 | } 33 | return self; 34 | } 35 | 36 | - (UIEdgeInsets)adjustedEdgeInsetsForEdgeInsets:(UIEdgeInsets)edgeInsets 37 | { 38 | UIEdgeInsets adjustedEdgeInsets = edgeInsets; 39 | CGFloat dY = self.size.height; 40 | 41 | if (self.direction & FWTPopoverArrowDirectionUp) adjustedEdgeInsets.top += dY; 42 | else if (self.direction & FWTPopoverArrowDirectionLeft) adjustedEdgeInsets.left += dY; 43 | else if (self.direction & FWTPopoverArrowDirectionRight) adjustedEdgeInsets.right += dY; 44 | else if (self.direction & FWTPopoverArrowDirectionDown) adjustedEdgeInsets.bottom += dY; 45 | return adjustedEdgeInsets; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FWTPopoverView_Test 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @implementation AppDelegate 13 | 14 | - (void)dealloc 15 | { 16 | [_window release]; 17 | [super dealloc]; 18 | } 19 | 20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 21 | { 22 | self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; 23 | self.window.backgroundColor = [UIColor whiteColor]; 24 | 25 | ViewController *defaultVC = [[[ViewController alloc] init] autorelease]; 26 | ViewController *manyVC = [[[ViewController alloc] init] autorelease]; 27 | manyVC.manyPopoversEnabled = YES; 28 | 29 | NSArray *samples = @[[RistrettoSampleDescriptor descriptorWithTitle:@"Default" instance:defaultVC], 30 | [RistrettoSampleDescriptor descriptorWithTitle:@"Custom - Multiples" instance:manyVC], 31 | ]; 32 | 33 | RistrettoTableViewController *rootViewController = [[[RistrettoTableViewController alloc] init] autorelease]; 34 | rootViewController.items = samples; 35 | self.window.rootViewController = [UINavigationController Ristretto_navigationControllerWithRootViewController:rootViewController 36 | defaultHeaderEnabled:YES]; 37 | [self.window makeKeyAndVisible]; 38 | return YES; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/FWTPopoverView_Test-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIcons 12 | 13 | CFBundlePrimaryIcon 14 | 15 | CFBundleIconFiles 16 | 17 | icon.png 18 | icon@2x.png 19 | 20 | 21 | 22 | CFBundleIdentifier 23 | com.futureworkshops.${PRODUCT_NAME:rfc1034identifier} 24 | CFBundleInfoDictionaryVersion 25 | 6.0 26 | CFBundleName 27 | ${PRODUCT_NAME} 28 | CFBundlePackageType 29 | APPL 30 | CFBundleShortVersionString 31 | 1.0 32 | CFBundleSignature 33 | ???? 34 | CFBundleVersion 35 | 1.0 36 | LSRequiresIPhoneOS 37 | 38 | UIRequiredDeviceCapabilities 39 | 40 | armv7 41 | 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | 46 | UISupportedInterfaceOrientations~ipad 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationPortraitUpsideDown 50 | UIInterfaceOrientationLandscapeLeft 51 | UIInterfaceOrientationLandscapeRight 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverAnimationHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // FWTAnnotationAnimationHelper.m 3 | // FWTAnnotationManager 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import "FWTPopoverAnimationHelper.h" 10 | #import "FWTPopoverView.h" 11 | 12 | #define FWT_PAH_PRESENT_DURATION .25f 13 | #define FWT_PAH_DISMISS_DURATION .25f 14 | #define FWT_PAH_ADJUST_POSITION_DURATION .25f 15 | #define FWT_PAH_PRESENT_DELAY .0f 16 | #define FWT_PAH_DISMISS_DELAY .0f 17 | #define FWT_PAH_PRESENT_OPTIONS UIViewAnimationOptionCurveEaseIn 18 | #define FWT_PAH_DISMISS_OPTIONS UIViewAnimationOptionCurveEaseIn 19 | 20 | @interface FWTPopoverAnimationHelper () 21 | @property (nonatomic, readwrite, assign) FWTPopoverView *annotationView; 22 | @end 23 | 24 | @implementation FWTPopoverAnimationHelper 25 | 26 | - (void)dealloc 27 | { 28 | self.prepareBlock = nil; 29 | self.presentAnimationsBlock = nil; 30 | self.dismissAnimationsBlock = nil; 31 | self.presentCompletionBlock = nil; 32 | self.dismissCompletionBlock = nil; 33 | self.annotationView = nil; 34 | [super dealloc]; 35 | } 36 | 37 | - (id)initWithAnnotationView:(FWTPopoverView *)annotationView 38 | { 39 | if ((self = [super init])) 40 | { 41 | self.annotationView = annotationView; 42 | self.presentDuration = FWT_PAH_PRESENT_DURATION; 43 | self.dismissDuration = FWT_PAH_DISMISS_DURATION; 44 | self.adjustPositionDuration = FWT_PAH_ADJUST_POSITION_DURATION; 45 | self.presentDelay = FWT_PAH_PRESENT_DELAY; 46 | self.dismissDelay = FWT_PAH_DISMISS_DELAY; 47 | self.presentOptions = FWT_PAH_PRESENT_OPTIONS; 48 | self.dismissOptions = FWT_PAH_DISMISS_OPTIONS; 49 | 50 | __block typeof(self.annotationView) theAnnotationView = self.annotationView; 51 | self.prepareBlock = ^{ theAnnotationView.alpha = .0f; }; 52 | self.presentAnimationsBlock = ^{ theAnnotationView.alpha = 1.0f; }; 53 | self.presentCompletionBlock = nil; 54 | self.dismissAnimationsBlock = ^{ theAnnotationView.alpha = .0f; }; 55 | self.dismissCompletionBlock = nil; 56 | } 57 | 58 | return self; 59 | } 60 | 61 | - (void)safePerformBlock:(void (^)(void))block 62 | { 63 | if (block) block(); 64 | } 65 | 66 | - (void)safePerformCompletionBlock:(void (^)(BOOL finished))block finished:(BOOL)finished; 67 | { 68 | if (block) block(finished); 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #FWTPopoverView 2 | 3 | ![FWTPopoverView screenshot](http://grab.by/hc1q) 4 | 5 | FWTPopoverView is a pretty flexible custom view for when you need a classic popover with a pointing arrow. The idea behind it was to create a very simple and basic API and make it easy to extend by accessing its custom objects/blocks entrypoints. FWTPopoverView is pure CG code, so no need to add assets and resolution independent for free. 6 | 7 | ##Requirements 8 | * XCode 4.4.1 or higher 9 | * iOS 5.0 10 | 11 | ##Features 12 | FWTPopoverView has few properties but uses several custom objects. 13 | If you want to adjust/change the appearance of the background, you change properties inside the background custom object; that also goes for animations and so on. 14 | On the other hand, if you're happy with the default style, all you need to do is set your contentSize and add your content to the contentView property. 15 | 16 | There are two optional blocks that can be executed when the popover is presented/dismissed. 17 | 18 | This project is not yet ARC-ready. 19 | 20 | ##Comparison with UIPopoverController * Block based API * Appearance/dismiss animations are easy to customise through animation blocks * Clean API to present/dismiss more than one popover either sequentially or all at once * No minimum size restrictions for the popover content * Works on the iPhone as well as on the iPad 21 | 22 | ##How to use it: initializing 23 | 24 | Generally you don't initialize FWTPopoverView with a frame instead you set the contentSize and then call: 25 | 26 | * **presentFromRect: inView: permittedArrowDirection: animated:** 27 | 28 | The default behaviour of the FWTPopoverView is to adjust its frame position to fit inside the superview bounds, when it falls on an intersection with the superview. You can change this by setting **adjustPositionInSuperviewEnabled** to NO. 29 | 30 | ##How to use it: configuration 31 | 32 | ####FWTPopoverBackgroundHelper 33 | This class needs a quick introduction: the popover image is a runtime image generated by a CAShapeLayer subclass. The layer is not directly added to the view hierarchy, instead is rendered in a separate context and the resulting image is used. The image is stretchable and takes up only a small chunk of memory. 34 | As with every CAShapeLayer you have access to all shape & style properties (clearly they're not animatable this time). The cornerRadius property is used as a property for the path. 35 | 36 | * **drawPathBlock** this block is executed just before return the image. It's a good point to customize or add more drawing stuff to your context 37 | * **(UIBezierPath *)bezierPathForRect:** returns the path for the current state/frame 38 | 39 | ####FWTPopoverAnimationHelper 40 | This class is a simple animation properties container. 41 | 42 | ####FWTPopoverArrow 43 | This class encapsulates some arrow specific properties. 44 | 45 | * **direction** (*readonly*) the direction in which the popover arrow is pointing 46 | * **size** the size of the arrow 47 | * **offset** (*readonly*) the distance (measured in points) from the center of the view to the center line of the arrow 48 | * **cornerOffset** the distance (measured in points) from the center of the arrow to the pointing edge of the arrow 49 | 50 | 51 | ##View hierarchy 52 | For a better understanding see the subviews/sublayers involved. Available public properties are in brackets. 53 | 54 | - **popoverView** {contentSize, adjustPositionInSuperviewEnabled} 55 | - **backgroundImageView** 56 | - **contentView** 57 | 58 | ##For your interest 59 | Future release of the backgroundHelper will include support for png images, as in UIPopoverBackgroundView. 60 | 61 | ##Demo 62 | The sample project shows how to use and how to create a custom FWTPopoverView. 63 | If you don't have time to read it this is what you need: 64 | 65 | ``` objective-c 66 | 67 | // present 68 | FWTPopoverView *popoverView = [[[FWTPopoverView alloc] init] autorelease]; 69 | popoverView.contentSize = CGSizeMake(240, 140); 70 | [popoverView presentFromRect:rect 71 | inView:self.view 72 | permittedArrowDirection:FWTPopoverArrowDirectionUp 73 | animated:YES]; 74 | 75 | // … 76 | 77 | // dismiss 78 | [popoverView dismissPopoverAnimated:YES]; 79 | ``` 80 | 81 | ##Licensing 82 | Apache License Version 2.0 83 | 84 | ##Credits 85 | [Saudi Telecom](http://www.stc.com.sa) Mobile Apps team, who enabled and collaborated with us to extract source code from My STC App for this library. 86 | 87 | ##Support, bugs and feature requests 88 | If you want to submit a feature request, please do so via the issue tracker on github. 89 | If you want to submit a bug report, please also do so via the issue tracker, including a diagnosis of the problem and a suggested fix (in code). 90 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FWTPopoverHintView_Test 4 | // 5 | // Created by Marco Meschini on 8/6/12. 6 | // Copyright (c) 2012 Futureworkshops. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "FWTPopoverView.h" 11 | 12 | CGFloat(^FWTRandomFloat)(CGFloat, CGFloat) = ^(CGFloat lowerBound, CGFloat upperBound){ 13 | CGFloat diff = upperBound - lowerBound; 14 | return (((float) (arc4random() % ((unsigned)RAND_MAX + 1)) / RAND_MAX) * diff) + lowerBound; 15 | }; 16 | 17 | @interface ViewController () 18 | @property (nonatomic, retain) FWTPopoverView *popoverView; 19 | @property (nonatomic, retain) UIView *touchPointView; 20 | @property (nonatomic, assign) FWTPopoverArrowDirection popoverArrowDirection; 21 | @property (nonatomic, retain) UISegmentedControl *segmentedControl; 22 | @end 23 | 24 | @implementation ViewController 25 | 26 | - (void)dealloc 27 | { 28 | self.segmentedControl = nil; 29 | self.touchPointView = nil; 30 | self.popoverView = nil; 31 | [super dealloc]; 32 | } 33 | 34 | - (void)loadView 35 | { 36 | [super loadView]; 37 | 38 | if (self.manyPopoversEnabled) 39 | { 40 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 41 | button.bounds = (CGRect){.0f, .0f, 32.0f, 32.0f}; 42 | [button setImage:[UIImage imageNamed:@"button_trash.png"] forState:UIControlStateNormal]; 43 | [button addTarget:self action:@selector(_didPressRightBarButton:) forControlEvents:UIControlEventTouchUpInside]; 44 | self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:button] autorelease]; 45 | } 46 | 47 | self.popoverArrowDirection = pow(2, 0); // store the selected arrow type 48 | } 49 | 50 | - (void)viewDidAppear:(BOOL)animated 51 | { 52 | [super viewDidAppear:animated]; 53 | 54 | CGRect bounds = self.navigationController.toolbar.bounds; 55 | self.segmentedControl.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds)); 56 | [self.navigationController.toolbar addSubview:self.segmentedControl]; 57 | 58 | [self.navigationController setToolbarHidden:NO animated:YES]; 59 | } 60 | 61 | - (void)viewWillDisappear:(BOOL)animated 62 | { 63 | [super viewWillDisappear:animated]; 64 | 65 | [self.navigationController setToolbarHidden:YES animated:YES]; 66 | } 67 | 68 | - (void)viewDidDisappear:(BOOL)animated 69 | { 70 | [super viewDidDisappear:animated]; 71 | 72 | [self.popoverView removeFromSuperview]; 73 | self.popoverView = nil; 74 | 75 | [self.view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 76 | } 77 | 78 | #pragma mark - Getters 79 | - (UIView *)touchPointView 80 | { 81 | if (!self->_touchPointView) 82 | { 83 | self->_touchPointView = [[UIView alloc] initWithFrame:CGRectMake(.0f, .0f, 4.0f, 4.0f)]; 84 | self->_touchPointView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:.5f]; 85 | self->_touchPointView.layer.borderWidth = 1.0f; 86 | self->_touchPointView.layer.cornerRadius = 2.0f; 87 | } 88 | 89 | return self->_touchPointView; 90 | } 91 | 92 | - (UISegmentedControl *)segmentedControl 93 | { 94 | if (!self->_segmentedControl) 95 | { 96 | self->_segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"N", @"U", @"D", @"L", @"R"]]; 97 | self->_segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; 98 | self->_segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth; 99 | [self->_segmentedControl addTarget:self action:@selector(_valueChangedForSegmentedControl:) forControlEvents:UIControlEventValueChanged]; 100 | self->_segmentedControl.selectedSegmentIndex = log2(self.popoverArrowDirection); 101 | [self->_segmentedControl sizeToFit]; 102 | } 103 | 104 | return self->_segmentedControl; 105 | } 106 | 107 | #pragma mark - Actions 108 | - (void)_valueChangedForSegmentedControl:(UISegmentedControl *)segmentedControl 109 | { 110 | self.popoverArrowDirection = pow(2, segmentedControl.selectedSegmentIndex); 111 | } 112 | 113 | - (void)_didPressRightBarButton:(UIBarButtonItem *)barButton 114 | { 115 | NSArray *arrayCopy = [NSArray arrayWithArray:self.view.subviews]; 116 | [arrayCopy enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop) { 117 | if ([subview isKindOfClass:[FWTPopoverView class]]) 118 | [(FWTPopoverView *)subview dismissPopoverAnimated:YES]; 119 | }]; 120 | } 121 | 122 | #pragma mark - UIResponder 123 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 124 | { 125 | // 126 | CGPoint point = [[touches anyObject] locationInView:self.view]; 127 | 128 | // 129 | if (!self.popoverView || self.manyPopoversEnabled) 130 | { 131 | self.popoverView = [[[FWTPopoverView alloc] init] autorelease]; 132 | self.popoverView.contentSize = CGSizeMake(self.popoverView.contentSize.width, ((int)FWTRandomFloat(60, 100))); // random height 133 | __block typeof(self) myself = self; 134 | self.popoverView.didDismissBlock = ^(FWTPopoverView *av){ myself.popoverView = nil; }; // release 135 | CGColorRef fillColor = self.manyPopoversEnabled ? [self _pleaseGiveMeARandomColor].CGColor : self.popoverView.backgroundHelper.fillColor; 136 | self.popoverView.backgroundHelper.fillColor = fillColor; // random color if many popover at the same time is enabled 137 | [self.popoverView presentFromRect:CGRectMake(point.x, point.y, 1.0f, 1.0f) 138 | inView:self.view 139 | permittedArrowDirection:self.popoverArrowDirection 140 | animated:YES]; 141 | } 142 | else if (!self.manyPopoversEnabled) 143 | [self.popoverView dismissPopoverAnimated:YES]; 144 | 145 | 146 | // show the touch (useful to see how the adjustPositionInSuperviewEnabled works) 147 | // 148 | if (!self.touchPointView.superview) [self.view addSubview:self.touchPointView]; 149 | self.touchPointView.center = point; 150 | [self.view bringSubviewToFront:self.touchPointView]; 151 | } 152 | 153 | #pragma mark - Private 154 | - (UIColor *)_pleaseGiveMeARandomColor 155 | { 156 | NSInteger countOfItems = 200; 157 | NSInteger random = arc4random()%countOfItems; 158 | UIColor *color = [UIColor colorWithHue:(CGFloat)random/countOfItems saturation:.6f brightness:.7f alpha:.5f]; 159 | return color; 160 | } 161 | 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverBackgroundHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // FWTAnnotationBackgroundHelper.m 3 | // FWTAnnotationManager 4 | // 5 | // Created by Marco Meschini on 31/10/2012. 6 | // Copyright (c) 2012 Marco Meschini. All rights reserved. 7 | // 8 | 9 | #import "FWTPopoverBackgroundHelper.h" 10 | #import "FWTPopoverView.h" 11 | 12 | #define FWT_PBH_CORNER_RADIUS 6.0f 13 | #define FWT_PBH_FILL_COLOR [[UIColor blackColor] colorWithAlphaComponent:.5f].CGColor 14 | #define FWT_PBH_STROKE_COLOR [UIColor blackColor].CGColor 15 | #define FWT_PBH_LINE_WIDTH 1.0f 16 | #define FWT_PBH_LINE_JOIN kCALineJoinRound 17 | #define FWT_PBH_SHADOW_RADIUS 5.0f 18 | #define FWT_PBH_SHADOW_OFFSET CGSizeMake(.0f, 1.0f) 19 | #define FWT_PBH_SHADOW_COLOR [UIColor blackColor].CGColor 20 | #define FWT_PBH_SHADOW_OPACITY .7f 21 | 22 | enum { 23 | AxisTypeHorizontal = 0, 24 | AxisTypeVertical, 25 | }; 26 | typedef NSUInteger AxisType; 27 | 28 | @interface FWTPopoverBackgroundHelper () 29 | @property (nonatomic, readwrite, assign) FWTPopoverView *annotationView; 30 | @property (nonatomic, readwrite, assign) CGRect pathFrame; 31 | @end 32 | 33 | @implementation FWTPopoverBackgroundHelper 34 | 35 | - (void)dealloc 36 | { 37 | self.annotationView = nil; 38 | [super dealloc]; 39 | } 40 | 41 | - (id)initWithAnnotationView:(FWTPopoverView *)annotationView 42 | { 43 | if ((self = [super init])) 44 | { 45 | self.annotationView = annotationView; 46 | 47 | // 48 | self.cornerRadius = FWT_PBH_CORNER_RADIUS; 49 | 50 | // 51 | self.fillColor = FWT_PBH_FILL_COLOR; 52 | self.strokeColor = FWT_PBH_STROKE_COLOR; 53 | 54 | // 55 | self.lineWidth = FWT_PBH_LINE_WIDTH; 56 | self.lineJoin = FWT_PBH_LINE_JOIN; 57 | 58 | // 59 | self.shadowRadius = FWT_PBH_SHADOW_RADIUS; 60 | self.shadowOffset = FWT_PBH_SHADOW_OFFSET; 61 | self.shadowColor = FWT_PBH_SHADOW_COLOR; 62 | self.shadowOpacity = FWT_PBH_SHADOW_OPACITY; 63 | } 64 | 65 | return self; 66 | } 67 | 68 | - (UIImage *)resizableBackgroundImageForSize:(CGSize)size edgeInsets:(UIEdgeInsets)edgeInsets 69 | { 70 | // 71 | CGFloat radius = self.cornerRadius; 72 | FWTPopoverArrowDirection arrowDirection = self.annotationView.arrow.direction; 73 | UIEdgeInsets capInsets = UIEdgeInsetsZero; 74 | CGSize contextSize = size; 75 | if (arrowDirection & FWTPopoverArrowDirectionUp || arrowDirection & FWTPopoverArrowDirectionDown) 76 | { 77 | contextSize.height = (radius * 2) + edgeInsets.top + edgeInsets.bottom + 1.0f; 78 | capInsets = UIEdgeInsetsMake(edgeInsets.top + radius, .0f, edgeInsets.bottom + radius, .0f); 79 | } 80 | else if (arrowDirection & FWTPopoverArrowDirectionLeft || arrowDirection & FWTPopoverArrowDirectionRight) 81 | { 82 | contextSize.width = (radius * 2) + edgeInsets.left + edgeInsets.right + 1.0f; 83 | capInsets = UIEdgeInsetsMake(.0f, edgeInsets.left + radius, .0f, edgeInsets.right + radius); 84 | } 85 | else if (arrowDirection & FWTPopoverArrowDirectionNone) 86 | { 87 | contextSize.width = (radius * 2) + edgeInsets.left + edgeInsets.right + 1.0f; 88 | contextSize.height = (radius * 2) + edgeInsets.top + edgeInsets.bottom + 1.0f; 89 | capInsets = UIEdgeInsetsMake(edgeInsets.top + radius, edgeInsets.left + radius, edgeInsets.bottom + radius, edgeInsets.right + radius); 90 | } 91 | 92 | // 93 | CGRect rect = CGRectMake(.0f, .0f, contextSize.width, contextSize.height); 94 | self.pathFrame = UIEdgeInsetsInsetRect(rect, edgeInsets); 95 | self.path = [self bezierPathForRect:self.pathFrame].CGPath; 96 | 97 | // 98 | UIImage *image = [self _backgroundImageForSize:contextSize]; 99 | return [image resizableImageWithCapInsets:capInsets]; 100 | } 101 | 102 | - (UIBezierPath *)bezierPathForRect:(CGRect)rect 103 | { 104 | CGFloat radius = self.cornerRadius; 105 | 106 | // 107 | // ab b c cd 108 | // a d 109 | // h e 110 | // gh g f ef 111 | // 112 | CGPoint a = CGPointMake(rect.origin.x, rect.origin.y + radius); 113 | CGPoint ab = CGPointMake(a.x, a.y - radius); 114 | CGPoint b = CGPointMake(a.x + radius, a.y - radius); 115 | CGPoint c = CGPointMake(a.x + rect.size.width - radius, rect.origin.y); 116 | CGPoint cd = CGPointMake(c.x + radius, c.y); 117 | CGPoint d = CGPointMake(c.x + radius, c.y + radius); 118 | CGPoint e = CGPointMake(a.x + rect.size.width, rect.origin.y + rect.size.height - radius); 119 | CGPoint ef = CGPointMake(e.x, e.y + radius); 120 | CGPoint f = CGPointMake(e.x - radius, e.y + radius); 121 | CGPoint g = CGPointMake(a.x + radius, rect.origin.y + rect.size.height); 122 | CGPoint gh = CGPointMake(g.x - radius, g.y); 123 | CGPoint h = CGPointMake(g.x - radius, g.y - radius); 124 | 125 | FWTPopoverArrowDirection arrowDirection = self.annotationView.arrow.direction; 126 | CGSize arrowSize = self.annotationView.arrow.size; 127 | CGFloat halfArrowWidth = arrowSize.width*.5f; 128 | CGSize availableHalfRectSize = CGSizeMake((rect.size.width-2*radius)*.5f, (rect.size.height-2*radius)*.5f); 129 | CGFloat ao = self.annotationView.arrow.offset; 130 | CGFloat ao_aco = self.annotationView.arrow.offset + self.annotationView.arrow.cornerOffset; 131 | void(^AppendArrowBlock)(UIBezierPath *, CGPoint, NSInteger, AxisType) = ^(UIBezierPath *bezierPath, CGPoint point, NSInteger sign, AxisType axisType) { 132 | 133 | CGPoint a0, a1, a2; 134 | if (axisType == AxisTypeHorizontal) 135 | { 136 | a0 = CGPointMake(point.x + sign*(availableHalfRectSize.width - halfArrowWidth) + ao, point.y); 137 | a1 = CGPointMake(point.x + sign*(availableHalfRectSize.width) + ao_aco, point.y - sign*(arrowSize.height)); 138 | a2 = CGPointMake(point.x + sign*(availableHalfRectSize.width + halfArrowWidth) + ao, point.y); 139 | } 140 | else 141 | { 142 | a0 = CGPointMake(point.x, point.y + sign*(availableHalfRectSize.height - halfArrowWidth) + ao); 143 | a1 = CGPointMake(point.x + sign*(arrowSize.height), point.y + sign*(availableHalfRectSize.height) + ao_aco); 144 | a2 = CGPointMake(point.x, point.y + sign*(availableHalfRectSize.height + halfArrowWidth) + ao); 145 | } 146 | 147 | [bezierPath addLineToPoint:a0]; 148 | [bezierPath addLineToPoint:a1]; 149 | [bezierPath addLineToPoint:a2]; 150 | }; 151 | 152 | // 153 | UIBezierPath *bp = [UIBezierPath bezierPath]; 154 | [bp moveToPoint:a]; 155 | [bp addQuadCurveToPoint:b controlPoint:ab]; 156 | if (arrowDirection == FWTPopoverArrowDirectionUp) AppendArrowBlock(bp, b, 1, AxisTypeHorizontal); 157 | [bp addLineToPoint:c]; 158 | [bp addQuadCurveToPoint:d controlPoint:cd]; 159 | if (arrowDirection == FWTPopoverArrowDirectionRight) AppendArrowBlock(bp, d, 1, AxisTypeVertical); 160 | [bp addLineToPoint:e]; 161 | [bp addQuadCurveToPoint:f controlPoint:ef]; 162 | if (arrowDirection == FWTPopoverArrowDirectionDown) AppendArrowBlock(bp, f, -1, AxisTypeHorizontal); 163 | [bp addLineToPoint:g]; 164 | [bp addQuadCurveToPoint:h controlPoint:gh]; 165 | if (arrowDirection == FWTPopoverArrowDirectionLeft) AppendArrowBlock(bp, h, -1, AxisTypeVertical); 166 | [bp closePath]; 167 | return bp; 168 | } 169 | 170 | #pragma mark - Private 171 | - (UIImage *)_backgroundImageForSize:(CGSize)size 172 | { 173 | // 174 | self.frame = CGRectMake(.0f, .0f, size.width, size.height); 175 | 176 | // 177 | UIGraphicsBeginImageContextWithOptions(size, NO, .0f); 178 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 179 | 180 | // 181 | CGFloat savedLineWidth = self.lineWidth; 182 | CGColorRef savedFillColorRef = self.fillColor; 183 | CGFloat savedShadowOpacity = self.shadowOpacity; 184 | 185 | // render the shadow at first 186 | if (self.shadowOpacity != .0f) 187 | { 188 | self.lineWidth = .0f; // hide stroke 189 | self.fillColor = [UIColor blackColor].CGColor; // use a solid fill color 190 | [self renderInContext:ctx]; 191 | CGContextSaveGState(ctx); 192 | CGContextAddPath(ctx, self.path); 193 | CGContextClip(ctx); 194 | CGContextClearRect(ctx, CGContextGetClipBoundingBox(ctx)); 195 | CGContextRestoreGState(ctx); 196 | } 197 | 198 | // render the fill without shadow 199 | self.fillColor = savedFillColorRef; 200 | self.shadowOpacity = .0f; 201 | [self renderInContext:ctx]; 202 | 203 | // give a chanche to do some extra stuff 204 | if (self.drawPathBlock) self.drawPathBlock(self, ctx); 205 | 206 | // render the border 207 | self.lineWidth = savedLineWidth; 208 | self.fillColor = [UIColor clearColor].CGColor; 209 | [self renderInContext:ctx]; 210 | 211 | // restore properties 212 | self.fillColor = savedFillColorRef; 213 | self.shadowOpacity = savedShadowOpacity; 214 | 215 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 216 | UIGraphicsEndImageContext(); 217 | return image; 218 | } 219 | 220 | 221 | @end 222 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2009 Two Toasters 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A94900AE1641942800864A8B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900AD1641942800864A8B /* Foundation.framework */; }; 11 | A94900BC1641943C00864A8B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900BB1641943C00864A8B /* QuartzCore.framework */; }; 12 | A94900BE1641944300864A8B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900BD1641944300864A8B /* CoreGraphics.framework */; }; 13 | A94900C01641944D00864A8B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900BF1641944D00864A8B /* UIKit.framework */; }; 14 | A94900C91641948700864A8B /* FWTPopoverAnimationHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = A94900C21641948700864A8B /* FWTPopoverAnimationHelper.m */; }; 15 | A94900CA1641948700864A8B /* FWTPopoverArrow.m in Sources */ = {isa = PBXBuildFile; fileRef = A94900C41641948700864A8B /* FWTPopoverArrow.m */; }; 16 | A94900CB1641948700864A8B /* FWTPopoverBackgroundHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = A94900C61641948700864A8B /* FWTPopoverBackgroundHelper.m */; }; 17 | A94900CC1641948700864A8B /* FWTPopoverView.m in Sources */ = {isa = PBXBuildFile; fileRef = A94900C81641948700864A8B /* FWTPopoverView.m */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | A94900A81641942800864A8B /* CopyFiles */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = "include/${PRODUCT_NAME}"; 25 | dstSubfolderSpec = 16; 26 | files = ( 27 | ); 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | /* End PBXCopyFilesBuildPhase section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | A94900AA1641942800864A8B /* libFWTPopoverView.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libFWTPopoverView.a; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | A94900AD1641942800864A8B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 35 | A94900B11641942800864A8B /* FWTPopoverView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FWTPopoverView-Prefix.pch"; sourceTree = ""; }; 36 | A94900BB1641943C00864A8B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 37 | A94900BD1641944300864A8B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 38 | A94900BF1641944D00864A8B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 39 | A94900C11641948700864A8B /* FWTPopoverAnimationHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FWTPopoverAnimationHelper.h; sourceTree = ""; }; 40 | A94900C21641948700864A8B /* FWTPopoverAnimationHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWTPopoverAnimationHelper.m; sourceTree = ""; }; 41 | A94900C31641948700864A8B /* FWTPopoverArrow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FWTPopoverArrow.h; sourceTree = ""; }; 42 | A94900C41641948700864A8B /* FWTPopoverArrow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWTPopoverArrow.m; sourceTree = ""; }; 43 | A94900C51641948700864A8B /* FWTPopoverBackgroundHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FWTPopoverBackgroundHelper.h; sourceTree = ""; }; 44 | A94900C61641948700864A8B /* FWTPopoverBackgroundHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWTPopoverBackgroundHelper.m; sourceTree = ""; }; 45 | A94900C71641948700864A8B /* FWTPopoverView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FWTPopoverView.h; sourceTree = ""; }; 46 | A94900C81641948700864A8B /* FWTPopoverView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FWTPopoverView.m; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | A94900A71641942800864A8B /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | A94900C01641944D00864A8B /* UIKit.framework in Frameworks */, 55 | A94900BE1641944300864A8B /* CoreGraphics.framework in Frameworks */, 56 | A94900BC1641943C00864A8B /* QuartzCore.framework in Frameworks */, 57 | A94900AE1641942800864A8B /* Foundation.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | A949009F1641942800864A8B = { 65 | isa = PBXGroup; 66 | children = ( 67 | A94900AF1641942800864A8B /* FWTPopoverView */, 68 | A94900AC1641942800864A8B /* Frameworks */, 69 | A94900AB1641942800864A8B /* Products */, 70 | ); 71 | sourceTree = ""; 72 | }; 73 | A94900AB1641942800864A8B /* Products */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | A94900AA1641942800864A8B /* libFWTPopoverView.a */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | A94900AC1641942800864A8B /* Frameworks */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | A94900BF1641944D00864A8B /* UIKit.framework */, 85 | A94900BD1641944300864A8B /* CoreGraphics.framework */, 86 | A94900BB1641943C00864A8B /* QuartzCore.framework */, 87 | A94900AD1641942800864A8B /* Foundation.framework */, 88 | ); 89 | name = Frameworks; 90 | sourceTree = ""; 91 | }; 92 | A94900AF1641942800864A8B /* FWTPopoverView */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | A94900C71641948700864A8B /* FWTPopoverView.h */, 96 | A94900C81641948700864A8B /* FWTPopoverView.m */, 97 | A94900CD1641949D00864A8B /* Private */, 98 | A94900B01641942800864A8B /* Supporting Files */, 99 | ); 100 | path = FWTPopoverView; 101 | sourceTree = ""; 102 | }; 103 | A94900B01641942800864A8B /* Supporting Files */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | A94900B11641942800864A8B /* FWTPopoverView-Prefix.pch */, 107 | ); 108 | name = "Supporting Files"; 109 | sourceTree = ""; 110 | }; 111 | A94900CD1641949D00864A8B /* Private */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | A94900C51641948700864A8B /* FWTPopoverBackgroundHelper.h */, 115 | A94900C61641948700864A8B /* FWTPopoverBackgroundHelper.m */, 116 | A94900C11641948700864A8B /* FWTPopoverAnimationHelper.h */, 117 | A94900C21641948700864A8B /* FWTPopoverAnimationHelper.m */, 118 | A94900C31641948700864A8B /* FWTPopoverArrow.h */, 119 | A94900C41641948700864A8B /* FWTPopoverArrow.m */, 120 | ); 121 | name = Private; 122 | sourceTree = ""; 123 | }; 124 | /* End PBXGroup section */ 125 | 126 | /* Begin PBXNativeTarget section */ 127 | A94900A91641942800864A8B /* FWTPopoverView */ = { 128 | isa = PBXNativeTarget; 129 | buildConfigurationList = A94900B81641942800864A8B /* Build configuration list for PBXNativeTarget "FWTPopoverView" */; 130 | buildPhases = ( 131 | A94900A61641942800864A8B /* Sources */, 132 | A94900A71641942800864A8B /* Frameworks */, 133 | A94900A81641942800864A8B /* CopyFiles */, 134 | ); 135 | buildRules = ( 136 | ); 137 | dependencies = ( 138 | ); 139 | name = FWTPopoverView; 140 | productName = FWTPopoverView; 141 | productReference = A94900AA1641942800864A8B /* libFWTPopoverView.a */; 142 | productType = "com.apple.product-type.library.static"; 143 | }; 144 | /* End PBXNativeTarget section */ 145 | 146 | /* Begin PBXProject section */ 147 | A94900A11641942800864A8B /* Project object */ = { 148 | isa = PBXProject; 149 | attributes = { 150 | LastUpgradeCheck = 0450; 151 | ORGANIZATIONNAME = "Marco Meschini"; 152 | }; 153 | buildConfigurationList = A94900A41641942800864A8B /* Build configuration list for PBXProject "FWTPopoverView" */; 154 | compatibilityVersion = "Xcode 3.2"; 155 | developmentRegion = English; 156 | hasScannedForEncodings = 0; 157 | knownRegions = ( 158 | en, 159 | ); 160 | mainGroup = A949009F1641942800864A8B; 161 | productRefGroup = A94900AB1641942800864A8B /* Products */; 162 | projectDirPath = ""; 163 | projectRoot = ""; 164 | targets = ( 165 | A94900A91641942800864A8B /* FWTPopoverView */, 166 | ); 167 | }; 168 | /* End PBXProject section */ 169 | 170 | /* Begin PBXSourcesBuildPhase section */ 171 | A94900A61641942800864A8B /* Sources */ = { 172 | isa = PBXSourcesBuildPhase; 173 | buildActionMask = 2147483647; 174 | files = ( 175 | A94900C91641948700864A8B /* FWTPopoverAnimationHelper.m in Sources */, 176 | A94900CA1641948700864A8B /* FWTPopoverArrow.m in Sources */, 177 | A94900CB1641948700864A8B /* FWTPopoverBackgroundHelper.m in Sources */, 178 | A94900CC1641948700864A8B /* FWTPopoverView.m in Sources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXSourcesBuildPhase section */ 183 | 184 | /* Begin XCBuildConfiguration section */ 185 | A94900B61641942800864A8B /* Debug */ = { 186 | isa = XCBuildConfiguration; 187 | buildSettings = { 188 | ALWAYS_SEARCH_USER_PATHS = NO; 189 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 190 | CLANG_CXX_LIBRARY = "libc++"; 191 | CLANG_WARN_EMPTY_BODY = YES; 192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 193 | COPY_PHASE_STRIP = NO; 194 | GCC_C_LANGUAGE_STANDARD = gnu99; 195 | GCC_DYNAMIC_NO_PIC = NO; 196 | GCC_OPTIMIZATION_LEVEL = 0; 197 | GCC_PREPROCESSOR_DEFINITIONS = ( 198 | "DEBUG=1", 199 | "$(inherited)", 200 | ); 201 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 202 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 203 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 204 | GCC_WARN_UNUSED_VARIABLE = YES; 205 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 206 | SDKROOT = iphoneos; 207 | }; 208 | name = Debug; 209 | }; 210 | A94900B71641942800864A8B /* Release */ = { 211 | isa = XCBuildConfiguration; 212 | buildSettings = { 213 | ALWAYS_SEARCH_USER_PATHS = NO; 214 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 215 | CLANG_CXX_LIBRARY = "libc++"; 216 | CLANG_WARN_EMPTY_BODY = YES; 217 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 218 | COPY_PHASE_STRIP = YES; 219 | GCC_C_LANGUAGE_STANDARD = gnu99; 220 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 221 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 222 | GCC_WARN_UNUSED_VARIABLE = YES; 223 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 224 | SDKROOT = iphoneos; 225 | VALIDATE_PRODUCT = YES; 226 | }; 227 | name = Release; 228 | }; 229 | A94900B91641942800864A8B /* Debug */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | DSTROOT = /tmp/FWTPopoverView.dst; 233 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 234 | GCC_PREFIX_HEADER = "FWTPopoverView/FWTPopoverView-Prefix.pch"; 235 | OTHER_LDFLAGS = "-ObjC"; 236 | PRODUCT_NAME = "$(TARGET_NAME)"; 237 | SKIP_INSTALL = YES; 238 | }; 239 | name = Debug; 240 | }; 241 | A94900BA1641942800864A8B /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | DSTROOT = /tmp/FWTPopoverView.dst; 245 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 246 | GCC_PREFIX_HEADER = "FWTPopoverView/FWTPopoverView-Prefix.pch"; 247 | OTHER_LDFLAGS = "-ObjC"; 248 | PRODUCT_NAME = "$(TARGET_NAME)"; 249 | SKIP_INSTALL = YES; 250 | }; 251 | name = Release; 252 | }; 253 | /* End XCBuildConfiguration section */ 254 | 255 | /* Begin XCConfigurationList section */ 256 | A94900A41641942800864A8B /* Build configuration list for PBXProject "FWTPopoverView" */ = { 257 | isa = XCConfigurationList; 258 | buildConfigurations = ( 259 | A94900B61641942800864A8B /* Debug */, 260 | A94900B71641942800864A8B /* Release */, 261 | ); 262 | defaultConfigurationIsVisible = 0; 263 | defaultConfigurationName = Release; 264 | }; 265 | A94900B81641942800864A8B /* Build configuration list for PBXNativeTarget "FWTPopoverView" */ = { 266 | isa = XCConfigurationList; 267 | buildConfigurations = ( 268 | A94900B91641942800864A8B /* Debug */, 269 | A94900BA1641942800864A8B /* Release */, 270 | ); 271 | defaultConfigurationIsVisible = 0; 272 | defaultConfigurationName = Release; 273 | }; 274 | /* End XCConfigurationList section */ 275 | }; 276 | rootObject = A94900A11641942800864A8B /* Project object */; 277 | } 278 | -------------------------------------------------------------------------------- /FWTPopoverView/FWTPopoverView/FWTPopoverView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FWTPopoverHintView.m 3 | // FWTPopoverHintView 4 | // 5 | // Created by Marco Meschini on 7/12/12. 6 | // Copyright (c) 2012 Futureworkshops. All rights reserved. 7 | // 8 | 9 | #import "FWTPopoverView.h" 10 | #import 11 | 12 | #define FWT_PV_SUGGESTED_EDGE_INSETS UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f) 13 | #define FWT_PV_CONTENT_SIZE CGSizeMake(160.0f, 60.0f) 14 | #define FWT_PV_ADJUST_POSITION_IN_SUPERVIEW_ENABLED YES 15 | 16 | @interface FWTPopoverArrow () 17 | @property (nonatomic, readwrite, assign) FWTPopoverArrowDirection direction; 18 | @property (nonatomic, readwrite, assign) CGFloat offset; 19 | @end 20 | 21 | struct FWTPopoverViewFrameAndArrowAdjustment 22 | { 23 | CGRect frame; 24 | CGFloat dx; 25 | CGFloat dy; 26 | NSInteger direction; 27 | }; 28 | 29 | @interface FWTPopoverView () 30 | 31 | @property (nonatomic, retain) UIImageView *backgroundImageView; 32 | @property (nonatomic, readwrite, retain) UIView *contentView; 33 | @property (nonatomic, assign) UIEdgeInsets suggestedEdgeInsets, edgeInsets; 34 | 35 | @end 36 | 37 | @implementation FWTPopoverView 38 | @synthesize backgroundImageView = _backgroundImageView; 39 | @synthesize contentView = _contentView; 40 | @synthesize arrow = _arrow; 41 | @synthesize backgroundHelper = _backgroundHelper; 42 | @synthesize animationHelper = _animationHelper; 43 | 44 | - (void)dealloc 45 | { 46 | self.arrow = nil; 47 | self.backgroundHelper = nil; 48 | self.animationHelper = nil; 49 | self.contentView = nil; 50 | self.backgroundImageView = nil; 51 | [super dealloc]; 52 | } 53 | 54 | - (id)initWithFrame:(CGRect)frame 55 | { 56 | if ((self = [super initWithFrame:frame])) 57 | { 58 | // 59 | self.suggestedEdgeInsets = FWT_PV_SUGGESTED_EDGE_INSETS; 60 | self.contentSize = FWT_PV_CONTENT_SIZE; 61 | self.adjustPositionInSuperviewEnabled = FWT_PV_ADJUST_POSITION_IN_SUPERVIEW_ENABLED; 62 | } 63 | 64 | return self; 65 | } 66 | 67 | - (void)layoutSubviews 68 | { 69 | [super layoutSubviews]; 70 | 71 | // 72 | if (!self.backgroundImageView.superview) [self addSubview:self.backgroundImageView]; 73 | self.backgroundImageView.frame = self.bounds; 74 | 75 | // 76 | if (!self.contentView.superview) [self addSubview:self.contentView]; 77 | self.contentView.frame = UIEdgeInsetsInsetRect(self.bounds, self.edgeInsets); 78 | } 79 | 80 | #pragma mark - Getters 81 | - (UIImageView *)backgroundImageView 82 | { 83 | if (!self->_backgroundImageView) self->_backgroundImageView = [[UIImageView alloc] init]; 84 | return self->_backgroundImageView; 85 | } 86 | 87 | - (UIView *)contentView 88 | { 89 | if (!self->_contentView) self->_contentView = [[UIView alloc] init]; 90 | return self->_contentView; 91 | } 92 | 93 | - (FWTPopoverBackgroundHelper *)backgroundHelper 94 | { 95 | if (!self->_backgroundHelper) self->_backgroundHelper = [[FWTPopoverBackgroundHelper alloc] initWithAnnotationView:self]; 96 | return self->_backgroundHelper; 97 | } 98 | 99 | - (FWTPopoverArrow *)arrow 100 | { 101 | if (!self->_arrow) self->_arrow = [[FWTPopoverArrow alloc] init]; 102 | return self->_arrow; 103 | } 104 | 105 | - (FWTPopoverAnimationHelper *)animationHelper 106 | { 107 | if (!self->_animationHelper) self->_animationHelper = [[FWTPopoverAnimationHelper alloc] initWithAnnotationView:self]; 108 | return self->_animationHelper; 109 | } 110 | 111 | #pragma mark - Private 112 | - (CGFloat)_arrowOffsetForDeltaX:(CGFloat)dX deltaY:(CGFloat)dY direction:(NSInteger)direction 113 | { 114 | CGRect shapeBounds = UIEdgeInsetsInsetRect(self.bounds, self.edgeInsets); 115 | CGFloat cornerRadius = self.backgroundHelper.cornerRadius; 116 | CGSize availableHalfRectSize = CGSizeMake((shapeBounds.size.width-2*cornerRadius)*.5f, (shapeBounds.size.height-2*cornerRadius)*.5f); 117 | CGFloat maxArrowOffset = .0f; 118 | CGFloat arrowOffset = .0f; 119 | if (self.arrow.direction & FWTPopoverArrowDirectionUp || self.arrow.direction & FWTPopoverArrowDirectionDown) 120 | { 121 | arrowOffset = direction*dX; 122 | maxArrowOffset = availableHalfRectSize.width - self.arrow.size.width / 2.0f; 123 | } 124 | else if (self.arrow.direction & FWTPopoverArrowDirectionLeft || self.arrow.direction & FWTPopoverArrowDirectionRight) 125 | { 126 | arrowOffset = direction*dY; 127 | maxArrowOffset = availableHalfRectSize.height - self.arrow.size.width / 2.0f; 128 | } 129 | 130 | if (abs(arrowOffset) > maxArrowOffset) 131 | arrowOffset = (arrowOffset > 0) ? maxArrowOffset : -maxArrowOffset; 132 | 133 | return arrowOffset; 134 | } 135 | 136 | - (CGPoint)_midPointForRect:(CGRect)rect popoverSize:(CGSize)popoverSize arrowDirection:(FWTPopoverArrowDirection)arrowDirections 137 | { 138 | CGPoint midPoint = CGPointZero; 139 | midPoint.x = CGRectGetWidth(rect) == 1.0f ? rect.origin.x : CGRectGetMidX(rect); 140 | midPoint.y = CGRectGetHeight(rect) == 1.0f ? rect.origin.y : CGRectGetMidY(rect); 141 | 142 | if (self.arrow.direction & FWTPopoverArrowDirectionUp) 143 | midPoint.x -= (popoverSize.width * .5f + self.arrow.cornerOffset + self.arrow.offset); 144 | 145 | else if (self.arrow.direction & FWTPopoverArrowDirectionDown) 146 | { 147 | midPoint.x -= (popoverSize.width * .5f + self.arrow.cornerOffset + self.arrow.offset); 148 | midPoint.y -= popoverSize.height; 149 | } 150 | 151 | else if (self.arrow.direction & FWTPopoverArrowDirectionLeft) 152 | midPoint.y -= (popoverSize.height * .5f + self.arrow.cornerOffset + self.arrow.offset); 153 | 154 | else if (self.arrow.direction & FWTPopoverArrowDirectionRight) 155 | { 156 | midPoint.x -= popoverSize.width; 157 | midPoint.y -= (popoverSize.height * .5f + self.arrow.cornerOffset + self.arrow.offset); 158 | } 159 | 160 | else if (self.arrow.direction & FWTPopoverArrowDirectionNone) 161 | { 162 | midPoint.x -= popoverSize.width * .5f; 163 | midPoint.y -= popoverSize.height * .5f; 164 | } 165 | 166 | return midPoint; 167 | } 168 | 169 | - (struct FWTPopoverViewFrameAndArrowAdjustment)_adjustmentForFrame:(CGRect)frame inSuperview:(UIView *)view 170 | { 171 | struct FWTPopoverViewFrameAndArrowAdjustment toReturn; 172 | toReturn.frame = frame; 173 | toReturn.dx = .0f; 174 | toReturn.dy = .0f; 175 | toReturn.direction = 1; 176 | 177 | CGRect intersection = CGRectIntersection(view.bounds, toReturn.frame); 178 | CGFloat frameWidth = toReturn.frame.size.width; 179 | CGFloat frameHeight = toReturn.frame.size.height; 180 | if (intersection.size.width != frameWidth) 181 | { 182 | toReturn.dx = frameWidth-intersection.size.width; 183 | if (intersection.origin.x == 0) 184 | { 185 | toReturn.frame = CGRectOffset(toReturn.frame, toReturn.dx, .0f); 186 | toReturn.direction = -1; 187 | } 188 | else 189 | toReturn.frame = CGRectOffset(toReturn.frame, -toReturn.dx, .0f); 190 | } 191 | if (intersection.size.height != frameHeight) 192 | { 193 | toReturn.dy = frameHeight-intersection.size.height; 194 | if (intersection.origin.y == 0) 195 | { 196 | toReturn.frame = CGRectOffset(toReturn.frame, .0f, toReturn.dy); 197 | toReturn.direction = -1; 198 | } 199 | else 200 | toReturn.frame = CGRectOffset(toReturn.frame, .0f, -toReturn.dy); 201 | } 202 | 203 | return toReturn; 204 | } 205 | 206 | #pragma mark - Public 207 | - (void)presentFromRect:(CGRect)rect inView:(UIView *)view permittedArrowDirection:(FWTPopoverArrowDirection)arrowDirection animated:(BOOL)animated 208 | { 209 | // 210 | self.arrow.direction = arrowDirection; 211 | 212 | // 213 | self.edgeInsets = [self.arrow adjustedEdgeInsetsForEdgeInsets:self.suggestedEdgeInsets]; 214 | 215 | //TODO: is safe to do in this way?? 216 | CGSize currentSize = self.contentSize; 217 | currentSize.width += self.edgeInsets.left + self.edgeInsets.right; 218 | currentSize.height += self.edgeInsets.top + self.edgeInsets.bottom; 219 | 220 | // 221 | CGPoint newOrigin = [self _midPointForRect:rect popoverSize:currentSize arrowDirection:self.arrow.direction]; 222 | CGRect frame = CGRectZero; 223 | frame.origin = newOrigin; 224 | frame.size = currentSize; 225 | frame = CGRectIntegral(frame); 226 | self.frame = frame; 227 | if (self.adjustPositionInSuperviewEnabled) 228 | { 229 | struct FWTPopoverViewFrameAndArrowAdjustment adj = [self _adjustmentForFrame:frame inSuperview:view]; 230 | self.frame = adj.frame; 231 | self.arrow.offset = [self _arrowOffsetForDeltaX:adj.dx deltaY:adj.dy direction:adj.direction]; 232 | } 233 | 234 | // 235 | self.backgroundImageView.image = [self.backgroundHelper resizableBackgroundImageForSize:currentSize edgeInsets:self.edgeInsets]; 236 | 237 | // 238 | if (!animated) 239 | { 240 | [view addSubview:self]; 241 | 242 | if (self.didPresentBlock) self.didPresentBlock(self); 243 | } 244 | else 245 | { 246 | // 247 | [self.animationHelper safePerformBlock:self.animationHelper.prepareBlock]; 248 | 249 | // 250 | [view addSubview:self]; 251 | 252 | // 253 | if (animated) 254 | [UIView animateWithDuration:self.animationHelper.presentDuration 255 | delay:self.animationHelper.presentDelay 256 | options:self.animationHelper.presentOptions 257 | animations:self.animationHelper.presentAnimationsBlock 258 | completion:^(BOOL finished) { 259 | 260 | [self.animationHelper safePerformCompletionBlock:self.animationHelper.presentCompletionBlock finished:finished]; 261 | 262 | if (self.didPresentBlock) self.didPresentBlock(self); 263 | }]; 264 | } 265 | } 266 | 267 | - (void)adjustPositionToRect:(CGRect)rect 268 | { 269 | [self adjustPositionToRect:rect animated:NO]; 270 | } 271 | 272 | - (void)adjustPositionToRect:(CGRect)rect animated:(BOOL)animated 273 | { 274 | __block typeof(self) myself = self; 275 | void(^adjustPositionBlock)(void) = ^() { 276 | CGPoint newOrigin = [myself _midPointForRect:rect popoverSize:myself.bounds.size arrowDirection:myself.arrow.direction]; 277 | CGRect frame = myself.frame; 278 | frame.origin = newOrigin; 279 | 280 | if (myself.adjustPositionInSuperviewEnabled) 281 | frame = [myself _adjustmentForFrame:frame inSuperview:myself.superview].frame; 282 | 283 | myself.frame = frame; 284 | }; 285 | 286 | if (animated) 287 | [UIView animateWithDuration:self.animationHelper.adjustPositionDuration animations:adjustPositionBlock]; 288 | else 289 | adjustPositionBlock(); 290 | } 291 | 292 | - (void)dismissPopoverAnimated:(BOOL)animated 293 | { 294 | if (animated) 295 | [UIView animateWithDuration:self.animationHelper.dismissDuration 296 | delay:self.animationHelper.dismissDelay 297 | options:self.animationHelper.dismissOptions 298 | animations:self.animationHelper.dismissAnimationsBlock 299 | completion:^(BOOL finished) { 300 | 301 | [self.animationHelper safePerformCompletionBlock:self.animationHelper.dismissCompletionBlock finished:finished]; 302 | 303 | [self removeFromSuperview]; 304 | 305 | if (self.didDismissBlock) self.didDismissBlock(self); 306 | }]; 307 | else 308 | { 309 | [self removeFromSuperview]; 310 | 311 | if (self.didDismissBlock) self.didDismissBlock(self); 312 | } 313 | } 314 | 315 | - (CGRect)arrowRect 316 | { 317 | CGRect toReturn = self.frame; 318 | toReturn.size = self.arrow.size; 319 | 320 | if (self.arrow.direction & FWTPopoverArrowDirectionUp) 321 | { 322 | toReturn.origin.x += (CGRectGetWidth(self.frame)-self.arrow.size.width)*.5f + self.arrow.offset; 323 | toReturn.origin.y += self.edgeInsets.top-self.arrow.size.height; 324 | } 325 | else if (self.arrow.direction & FWTPopoverArrowDirectionDown) 326 | { 327 | toReturn.origin.x += (CGRectGetWidth(self.frame)-self.arrow.size.width)*.5f + self.arrow.offset; 328 | toReturn.origin.y += (CGRectGetHeight(self.frame)-self.edgeInsets.bottom); 329 | } 330 | else if (self.arrow.direction & FWTPopoverArrowDirectionLeft) 331 | { 332 | toReturn.origin.y += (CGRectGetHeight(self.frame)-self.arrow.size.width)*.5f + self.arrow.offset; 333 | toReturn.origin.x += self.suggestedEdgeInsets.left;//-self.arrow.size.width; 334 | toReturn.size = CGSizeMake(self.arrow.size.height, self.arrow.size.width); 335 | } 336 | else if (self.arrow.direction & FWTPopoverArrowDirectionRight) 337 | { 338 | toReturn.origin.y += (CGRectGetHeight(self.frame)-self.arrow.size.width)*.5f + self.arrow.offset; 339 | toReturn.origin.x += (CGRectGetWidth(self.frame)-self.edgeInsets.right); 340 | toReturn.size = CGSizeMake(self.arrow.size.height, self.arrow.size.width); 341 | } 342 | else if (self.arrow.direction & FWTPopoverArrowDirectionNone) 343 | { 344 | toReturn = CGRectZero; 345 | } 346 | 347 | return toReturn; 348 | } 349 | 350 | @end 351 | -------------------------------------------------------------------------------- /FWTPopoverView_Test/FWTPopoverView_Test.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A94900E21641963600864A8B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900E11641963600864A8B /* UIKit.framework */; }; 11 | A94900E41641963600864A8B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900E31641963600864A8B /* Foundation.framework */; }; 12 | A94900E61641963600864A8B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900E51641963600864A8B /* CoreGraphics.framework */; }; 13 | A94900EC1641963600864A8B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A94900EA1641963600864A8B /* InfoPlist.strings */; }; 14 | A94900EE1641963600864A8B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A94900ED1641963600864A8B /* main.m */; }; 15 | A94900F21641963600864A8B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A94900F11641963600864A8B /* AppDelegate.m */; }; 16 | A94900F41641963600864A8B /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = A94900F31641963600864A8B /* Default.png */; }; 17 | A94900F61641963600864A8B /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A94900F51641963600864A8B /* Default@2x.png */; }; 18 | A94900F81641963600864A8B /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A94900F71641963600864A8B /* Default-568h@2x.png */; }; 19 | A94900FF1641964E00864A8B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94900FE1641964E00864A8B /* QuartzCore.framework */; }; 20 | A94901011641965100864A8B /* libFWTPopoverView.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A94901001641965100864A8B /* libFWTPopoverView.a */; }; 21 | A9490104164196B000864A8B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9490103164196B000864A8B /* ViewController.m */; }; 22 | A99CC57B170354E20070FF13 /* button_back.png in Resources */ = {isa = PBXBuildFile; fileRef = A99CC579170354E20070FF13 /* button_back.png */; }; 23 | A99CC57C170354E20070FF13 /* button_back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A99CC57A170354E20070FF13 /* button_back@2x.png */; }; 24 | A99CC57F170357810070FF13 /* icon_project.png in Resources */ = {isa = PBXBuildFile; fileRef = A99CC57D170357810070FF13 /* icon_project.png */; }; 25 | A99CC580170357810070FF13 /* icon_project@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A99CC57E170357810070FF13 /* icon_project@2x.png */; }; 26 | A99CC5851703658E0070FF13 /* libRistrettoUI.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A99CC5841703658E0070FF13 /* libRistrettoUI.a */; }; 27 | A9D14A551704884C00F64866 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = A9D14A541704884C00F64866 /* icon.png */; }; 28 | A9D14A571704885000F64866 /* icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9D14A561704885000F64866 /* icon@2x.png */; }; 29 | A9D14A5A1704B83F00F64866 /* button_trash.png in Resources */ = {isa = PBXBuildFile; fileRef = A9D14A581704B83F00F64866 /* button_trash.png */; }; 30 | A9D14A5B1704B83F00F64866 /* button_trash@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = A9D14A591704B83F00F64866 /* button_trash@2x.png */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | A94900DD1641963600864A8B /* FWTPopoverView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FWTPopoverView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | A94900E11641963600864A8B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 36 | A94900E31641963600864A8B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 37 | A94900E51641963600864A8B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 38 | A94900E91641963600864A8B /* FWTPopoverView_Test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "FWTPopoverView_Test-Info.plist"; sourceTree = ""; }; 39 | A94900EB1641963600864A8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 40 | A94900ED1641963600864A8B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 41 | A94900EF1641963600864A8B /* FWTPopoverView_Test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FWTPopoverView_Test-Prefix.pch"; sourceTree = ""; }; 42 | A94900F01641963600864A8B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | A94900F11641963600864A8B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | A94900F31641963600864A8B /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 45 | A94900F51641963600864A8B /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 46 | A94900F71641963600864A8B /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 47 | A94900FE1641964E00864A8B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 48 | A94901001641965100864A8B /* libFWTPopoverView.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libFWTPopoverView.a; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | A9490102164196B000864A8B /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 50 | A9490103164196B000864A8B /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 51 | A99CC579170354E20070FF13 /* button_back.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = button_back.png; sourceTree = ""; }; 52 | A99CC57A170354E20070FF13 /* button_back@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "button_back@2x.png"; sourceTree = ""; }; 53 | A99CC57D170357810070FF13 /* icon_project.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_project.png; sourceTree = ""; }; 54 | A99CC57E170357810070FF13 /* icon_project@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon_project@2x.png"; sourceTree = ""; }; 55 | A99CC5841703658E0070FF13 /* libRistrettoUI.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRistrettoUI.a; path = "../../../../Library/Developer/Xcode/DerivedData/Build/Products/Debug-iphoneos/libRistrettoUI.a"; sourceTree = ""; }; 56 | A9D14A541704884C00F64866 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon.png; path = ../icon.png; sourceTree = ""; }; 57 | A9D14A561704885000F64866 /* icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "icon@2x.png"; path = "../icon@2x.png"; sourceTree = ""; }; 58 | A9D14A581704B83F00F64866 /* button_trash.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = button_trash.png; sourceTree = ""; }; 59 | A9D14A591704B83F00F64866 /* button_trash@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "button_trash@2x.png"; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | A94900DA1641963600864A8B /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | A99CC5851703658E0070FF13 /* libRistrettoUI.a in Frameworks */, 68 | A94901011641965100864A8B /* libFWTPopoverView.a in Frameworks */, 69 | A94900FF1641964E00864A8B /* QuartzCore.framework in Frameworks */, 70 | A94900E21641963600864A8B /* UIKit.framework in Frameworks */, 71 | A94900E41641963600864A8B /* Foundation.framework in Frameworks */, 72 | A94900E61641963600864A8B /* CoreGraphics.framework in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | A94900D21641963600864A8B = { 80 | isa = PBXGroup; 81 | children = ( 82 | A94900E71641963600864A8B /* FWTPopoverView_Test */, 83 | A94900E01641963600864A8B /* Frameworks */, 84 | A94900DE1641963600864A8B /* Products */, 85 | ); 86 | sourceTree = ""; 87 | }; 88 | A94900DE1641963600864A8B /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | A94900DD1641963600864A8B /* FWTPopoverView.app */, 92 | ); 93 | name = Products; 94 | sourceTree = ""; 95 | }; 96 | A94900E01641963600864A8B /* Frameworks */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | A99CC5841703658E0070FF13 /* libRistrettoUI.a */, 100 | A94901001641965100864A8B /* libFWTPopoverView.a */, 101 | A94900FE1641964E00864A8B /* QuartzCore.framework */, 102 | A94900E11641963600864A8B /* UIKit.framework */, 103 | A94900E31641963600864A8B /* Foundation.framework */, 104 | A94900E51641963600864A8B /* CoreGraphics.framework */, 105 | ); 106 | name = Frameworks; 107 | sourceTree = ""; 108 | }; 109 | A94900E71641963600864A8B /* FWTPopoverView_Test */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | A94900F01641963600864A8B /* AppDelegate.h */, 113 | A94900F11641963600864A8B /* AppDelegate.m */, 114 | A99CC5811703582C0070FF13 /* Sample */, 115 | A94900E81641963600864A8B /* Supporting Files */, 116 | ); 117 | path = FWTPopoverView_Test; 118 | sourceTree = ""; 119 | }; 120 | A94900E81641963600864A8B /* Supporting Files */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | A9D14A581704B83F00F64866 /* button_trash.png */, 124 | A9D14A591704B83F00F64866 /* button_trash@2x.png */, 125 | A9D14A561704885000F64866 /* icon@2x.png */, 126 | A9D14A541704884C00F64866 /* icon.png */, 127 | A94900E91641963600864A8B /* FWTPopoverView_Test-Info.plist */, 128 | A94900EA1641963600864A8B /* InfoPlist.strings */, 129 | A94900ED1641963600864A8B /* main.m */, 130 | A94900EF1641963600864A8B /* FWTPopoverView_Test-Prefix.pch */, 131 | A99CC57D170357810070FF13 /* icon_project.png */, 132 | A99CC57E170357810070FF13 /* icon_project@2x.png */, 133 | A99CC579170354E20070FF13 /* button_back.png */, 134 | A99CC57A170354E20070FF13 /* button_back@2x.png */, 135 | A94900F31641963600864A8B /* Default.png */, 136 | A94900F51641963600864A8B /* Default@2x.png */, 137 | A94900F71641963600864A8B /* Default-568h@2x.png */, 138 | ); 139 | name = "Supporting Files"; 140 | sourceTree = ""; 141 | }; 142 | A99CC5811703582C0070FF13 /* Sample */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | A9490102164196B000864A8B /* ViewController.h */, 146 | A9490103164196B000864A8B /* ViewController.m */, 147 | ); 148 | name = Sample; 149 | sourceTree = ""; 150 | }; 151 | /* End PBXGroup section */ 152 | 153 | /* Begin PBXNativeTarget section */ 154 | A94900DC1641963600864A8B /* FWTPopoverView_Test */ = { 155 | isa = PBXNativeTarget; 156 | buildConfigurationList = A94900FB1641963600864A8B /* Build configuration list for PBXNativeTarget "FWTPopoverView_Test" */; 157 | buildPhases = ( 158 | A94900D91641963600864A8B /* Sources */, 159 | A94900DA1641963600864A8B /* Frameworks */, 160 | A94900DB1641963600864A8B /* Resources */, 161 | ); 162 | buildRules = ( 163 | ); 164 | dependencies = ( 165 | ); 166 | name = FWTPopoverView_Test; 167 | productName = FWTPopoverView_Test; 168 | productReference = A94900DD1641963600864A8B /* FWTPopoverView.app */; 169 | productType = "com.apple.product-type.application"; 170 | }; 171 | /* End PBXNativeTarget section */ 172 | 173 | /* Begin PBXProject section */ 174 | A94900D41641963600864A8B /* Project object */ = { 175 | isa = PBXProject; 176 | attributes = { 177 | LastUpgradeCheck = 0450; 178 | ORGANIZATIONNAME = "Marco Meschini"; 179 | }; 180 | buildConfigurationList = A94900D71641963600864A8B /* Build configuration list for PBXProject "FWTPopoverView_Test" */; 181 | compatibilityVersion = "Xcode 3.2"; 182 | developmentRegion = English; 183 | hasScannedForEncodings = 0; 184 | knownRegions = ( 185 | en, 186 | ); 187 | mainGroup = A94900D21641963600864A8B; 188 | productRefGroup = A94900DE1641963600864A8B /* Products */; 189 | projectDirPath = ""; 190 | projectRoot = ""; 191 | targets = ( 192 | A94900DC1641963600864A8B /* FWTPopoverView_Test */, 193 | ); 194 | }; 195 | /* End PBXProject section */ 196 | 197 | /* Begin PBXResourcesBuildPhase section */ 198 | A94900DB1641963600864A8B /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | A94900EC1641963600864A8B /* InfoPlist.strings in Resources */, 203 | A94900F41641963600864A8B /* Default.png in Resources */, 204 | A94900F61641963600864A8B /* Default@2x.png in Resources */, 205 | A94900F81641963600864A8B /* Default-568h@2x.png in Resources */, 206 | A99CC57B170354E20070FF13 /* button_back.png in Resources */, 207 | A99CC57C170354E20070FF13 /* button_back@2x.png in Resources */, 208 | A99CC57F170357810070FF13 /* icon_project.png in Resources */, 209 | A99CC580170357810070FF13 /* icon_project@2x.png in Resources */, 210 | A9D14A551704884C00F64866 /* icon.png in Resources */, 211 | A9D14A571704885000F64866 /* icon@2x.png in Resources */, 212 | A9D14A5A1704B83F00F64866 /* button_trash.png in Resources */, 213 | A9D14A5B1704B83F00F64866 /* button_trash@2x.png in Resources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXResourcesBuildPhase section */ 218 | 219 | /* Begin PBXSourcesBuildPhase section */ 220 | A94900D91641963600864A8B /* Sources */ = { 221 | isa = PBXSourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | A94900EE1641963600864A8B /* main.m in Sources */, 225 | A94900F21641963600864A8B /* AppDelegate.m in Sources */, 226 | A9490104164196B000864A8B /* ViewController.m in Sources */, 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | /* End PBXSourcesBuildPhase section */ 231 | 232 | /* Begin PBXVariantGroup section */ 233 | A94900EA1641963600864A8B /* InfoPlist.strings */ = { 234 | isa = PBXVariantGroup; 235 | children = ( 236 | A94900EB1641963600864A8B /* en */, 237 | ); 238 | name = InfoPlist.strings; 239 | sourceTree = ""; 240 | }; 241 | /* End PBXVariantGroup section */ 242 | 243 | /* Begin XCBuildConfiguration section */ 244 | A94900F91641963600864A8B /* Debug */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | ALWAYS_SEARCH_USER_PATHS = NO; 248 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 249 | CLANG_CXX_LIBRARY = "libc++"; 250 | CLANG_WARN_EMPTY_BODY = YES; 251 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 252 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 253 | COPY_PHASE_STRIP = NO; 254 | GCC_C_LANGUAGE_STANDARD = gnu99; 255 | GCC_DYNAMIC_NO_PIC = NO; 256 | GCC_OPTIMIZATION_LEVEL = 0; 257 | GCC_PREPROCESSOR_DEFINITIONS = ( 258 | "DEBUG=1", 259 | "$(inherited)", 260 | ); 261 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 262 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 263 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 264 | GCC_WARN_UNUSED_VARIABLE = YES; 265 | HEADER_SEARCH_PATHS = ( 266 | "\"$(SRCROOT)/../FWTPopoverView/FWTPopoverView/\"/**", 267 | "\"$(SRCROOT)/../RistrettoUI/RistrettoUI/\"", 268 | ); 269 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 270 | OTHER_LDFLAGS = "-ObjC"; 271 | SDKROOT = iphoneos; 272 | TARGETED_DEVICE_FAMILY = "1,2"; 273 | }; 274 | name = Debug; 275 | }; 276 | A94900FA1641963600864A8B /* Release */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | ALWAYS_SEARCH_USER_PATHS = NO; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 284 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 285 | COPY_PHASE_STRIP = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 288 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 289 | GCC_WARN_UNUSED_VARIABLE = YES; 290 | HEADER_SEARCH_PATHS = ( 291 | "\"$(SRCROOT)/../FWTPopoverView/FWTPopoverView/\"/**", 292 | "\"$(SRCROOT)/../RistrettoUI/RistrettoUI/\"", 293 | ); 294 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 295 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 296 | OTHER_LDFLAGS = "-ObjC"; 297 | SDKROOT = iphoneos; 298 | TARGETED_DEVICE_FAMILY = "1,2"; 299 | VALIDATE_PRODUCT = YES; 300 | }; 301 | name = Release; 302 | }; 303 | A94900FC1641963600864A8B /* Debug */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 307 | GCC_PREFIX_HEADER = "FWTPopoverView_Test/FWTPopoverView_Test-Prefix.pch"; 308 | INFOPLIST_FILE = "FWTPopoverView_Test/FWTPopoverView_Test-Info.plist"; 309 | LIBRARY_SEARCH_PATHS = ( 310 | "$(inherited)", 311 | "\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/FWTPopoverView-btyyvkntlkicerfbutllchdqvznt/Build/Products/Debug-iphoneos\"", 312 | "\"$(SRCROOT)/../../../../Library/Developer/Xcode/DerivedData/Build/Products/Debug-iphoneos\"", 313 | ); 314 | ONLY_ACTIVE_ARCH = YES; 315 | PRODUCT_NAME = FWTPopoverView; 316 | WRAPPER_EXTENSION = app; 317 | }; 318 | name = Debug; 319 | }; 320 | A94900FD1641963600864A8B /* Release */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 324 | GCC_PREFIX_HEADER = "FWTPopoverView_Test/FWTPopoverView_Test-Prefix.pch"; 325 | INFOPLIST_FILE = "FWTPopoverView_Test/FWTPopoverView_Test-Info.plist"; 326 | LIBRARY_SEARCH_PATHS = ( 327 | "$(inherited)", 328 | "\"$(SRCROOT)/../../../Library/Developer/Xcode/DerivedData/FWTPopoverView-btyyvkntlkicerfbutllchdqvznt/Build/Products/Debug-iphoneos\"", 329 | "\"$(SRCROOT)/../../../../Library/Developer/Xcode/DerivedData/Build/Products/Debug-iphoneos\"", 330 | ); 331 | PRODUCT_NAME = FWTPopoverView; 332 | WRAPPER_EXTENSION = app; 333 | }; 334 | name = Release; 335 | }; 336 | /* End XCBuildConfiguration section */ 337 | 338 | /* Begin XCConfigurationList section */ 339 | A94900D71641963600864A8B /* Build configuration list for PBXProject "FWTPopoverView_Test" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | A94900F91641963600864A8B /* Debug */, 343 | A94900FA1641963600864A8B /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | A94900FB1641963600864A8B /* Build configuration list for PBXNativeTarget "FWTPopoverView_Test" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | A94900FC1641963600864A8B /* Debug */, 352 | A94900FD1641963600864A8B /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | /* End XCConfigurationList section */ 358 | }; 359 | rootObject = A94900D41641963600864A8B /* Project object */; 360 | } 361 | --------------------------------------------------------------------------------