├── .gitignore ├── PopoverView.podspec ├── PopoverView ├── PopoverView.h ├── PopoverView.m ├── PopoverViewCompatibility.h └── PopoverView_Configuration.h ├── README.markdown ├── popover.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── popover.xccheckout │ └── xcuserdata │ │ ├── baspellis.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── ocrickard.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── alan.xcuserdatad │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── baspellis.xcuserdatad │ └── xcschemes │ │ └── popover.xcscheme │ └── ocrickard.xcuserdatad │ └── xcschemes │ ├── popover.xcscheme │ └── xcschememanagement.plist ├── popover ├── Demo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Calendar View │ │ ├── OCDaysView.h │ │ └── OCDaysView.m │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ ├── MainStoryboard_iPad.storyboard │ │ └── MainStoryboard_iPhone.storyboard │ ├── main.m │ ├── popover-Info.plist │ └── popover-Prefix.pch └── Images │ ├── error.png │ ├── error@2x.png │ ├── success.png │ └── success@2x.png └── popoverTests ├── en.lproj └── InfoPlist.strings ├── popoverTests-Info.plist ├── popoverTests.h └── popoverTests.m /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | .DS_Store 4 | 5 | *.xcuserstate 6 | 7 | *.xcscheme 8 | -------------------------------------------------------------------------------- /PopoverView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "PopoverView" 4 | s.version = "0.0.2" 5 | s.summary = "A simple UIView popover control for iPhone/iPad written with CoreGraphics." 6 | s.homepage = "https://github.com/cocoa-factory/PopoverView" 7 | s.license = { 8 | :type => 'MIT', 9 | :text => <<-LICENSE 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | LICENSE 17 | } 18 | s.author = { "Raquel Galan" => "iprayforwaves@gmail.com" } 19 | s.author = 'runway20' 20 | s.source = { :git => "https://github.com/cocoa-factory/PopoverView.git", :tag => '0.0.2'} 21 | s.platform = :ios 22 | s.source_files = 'PopoverView/*.{h,m}' 23 | 24 | end -------------------------------------------------------------------------------- /PopoverView/PopoverView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PopoverView.h 3 | // Embark 4 | // 5 | // Created by Oliver Rickard on 20/08/2012. 6 | // 7 | // 8 | 9 | #import 10 | #import "PopoverViewCompatibility.h" 11 | 12 | 13 | /**************** Support both ARC and non-ARC ********************/ 14 | 15 | #ifndef SUPPORT_ARC 16 | #define SUPPORT_ARC 17 | 18 | #if __has_feature(objc_arc_weak) //objc_arc_weak 19 | #define WEAK weak 20 | #define __WEAK __weak 21 | #define STRONG strong 22 | 23 | #define AUTORELEASE self 24 | #define RELEASE self 25 | #define RETAIN self 26 | #define CFTYPECAST(exp) (__bridge exp) 27 | #define TYPECAST(exp) (__bridge_transfer exp) 28 | #define CFRELEASE(exp) CFRelease(exp) 29 | #define DEALLOC self 30 | 31 | #elif __has_feature(objc_arc) //objc_arc 32 | #define WEAK unsafe_unretained 33 | #define __WEAK __unsafe_unretained 34 | #define STRONG strong 35 | 36 | #define AUTORELEASE self 37 | #define RELEASE self 38 | #define RETAIN self 39 | #define CFTYPECAST(exp) (__bridge exp) 40 | #define TYPECAST(exp) (__bridge_transfer exp) 41 | #define CFRELEASE(exp) CFRelease(exp) 42 | #define DEALLOC self 43 | 44 | #else //none 45 | #define WEAK assign 46 | #define __WEAK 47 | #define STRONG retain 48 | 49 | #define AUTORELEASE autorelease 50 | #define RELEASE release 51 | #define RETAIN retain 52 | #define CFTYPECAST(exp) (exp) 53 | #define TYPECAST(exp) (exp) 54 | #define CFRELEASE(exp) CFRelease(exp) 55 | #define DEALLOC dealloc 56 | 57 | #endif 58 | #endif 59 | 60 | /******************************************************************/ 61 | 62 | 63 | @class PopoverView; 64 | 65 | @protocol PopoverViewDelegate 66 | 67 | @optional 68 | 69 | //Delegate receives this call as soon as the item has been selected 70 | - (void)popoverView:(PopoverView *)popoverView didSelectItemAtIndex:(NSInteger)index; 71 | 72 | //Delegate receives this call once the popover has begun the dismissal animation 73 | - (void)popoverViewDidDismiss:(PopoverView *)popoverView; 74 | 75 | @end 76 | 77 | @interface PopoverView : UIView { 78 | CGRect boxFrame; 79 | CGSize contentSize; 80 | CGPoint arrowPoint; 81 | 82 | BOOL above; 83 | 84 | __WEAK id delegate; 85 | 86 | UIView *parentView; 87 | 88 | UIView *topView; 89 | 90 | NSArray *subviewsArray; 91 | 92 | NSArray *dividerRects; 93 | 94 | UIView *contentView; 95 | 96 | UIView *titleView; 97 | 98 | UIActivityIndicatorView *activityIndicator; 99 | 100 | //Instance variable that can change at runtime 101 | BOOL showDividerRects; 102 | } 103 | 104 | @property (nonatomic, STRONG) UIView *titleView; 105 | 106 | @property (nonatomic, STRONG) UIView *contentView; 107 | 108 | @property (nonatomic, STRONG) NSArray *subviewsArray; 109 | 110 | @property (nonatomic, WEAK) id delegate; 111 | 112 | #pragma mark - Class Static Showing Methods 113 | 114 | //These are the main static methods you can use to display the popover. 115 | //Simply call [PopoverView show...] with your arguments, and the popover will be generated, added to the view stack, and notify you when it's done. 116 | 117 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text delegate:(id)delegate; 118 | 119 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withText:(NSString *)text delegate:(id)delegate; 120 | 121 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray delegate:(id)delegate; 122 | 123 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray delegate:(id)delegate; 124 | 125 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray delegate:(id)delegate; 126 | 127 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray delegate:(id)delegate; 128 | 129 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray delegate:(id)delegate; 130 | 131 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray delegate:(id)delegate; 132 | 133 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView delegate:(id)delegate; 134 | 135 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)cView delegate:(id)delegate; 136 | 137 | #pragma mark - Instance Showing Methods 138 | 139 | //Adds/animates in the popover to the top of the view stack with the arrow pointing at the "point" 140 | //within the specified view. The contentView will be added to the popover, and should have either 141 | //a clear color backgroundColor, or perhaps a rounded corner bg rect (radius 4.f if you're going to 142 | //round). 143 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)contentView; 144 | 145 | //Calls above method with a UILabel containing the text you deliver to this method. 146 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text; 147 | 148 | //Calls top method with an array of UIView objects. This method will stack these views vertically 149 | //with kBoxPadding padding between each view in the y-direction. 150 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray; 151 | 152 | //Does same as above, but adds a title label at top of the popover. 153 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray; 154 | 155 | //Calls the viewArray method with an array of UILabels created with the strings 156 | //in stringArray. All contents of stringArray must be NSStrings. 157 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray; 158 | 159 | //This method does same as above, but with a title label at the top of the popover. 160 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray; 161 | 162 | //Draws a vertical list of the NSString elements of stringArray with UIImages 163 | //from imageArray placed centered above them. 164 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray; 165 | 166 | //Does the same as above, but with a title 167 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray; 168 | 169 | //Lays out the PopoverView at a point once all of the views have already been setup elsewhere 170 | - (void)layoutAtPoint:(CGPoint)point inView:(UIView *)view; 171 | 172 | #pragma mark - Other Interaction 173 | //This method animates the rotation of the PopoverView to a new point 174 | - (void)animateRotationToNewPoint:(CGPoint)point inView:(UIView *)view withDuration:(NSTimeInterval)duration; 175 | 176 | #pragma mark - Dismissal 177 | //Dismisses the view, and removes it from the view stack. 178 | - (void)dismiss; 179 | - (void)dismiss:(BOOL)animated; 180 | 181 | #pragma mark - Activity Indicator Methods 182 | 183 | //Shows the activity indicator, and changes the title (if the title is available, and is a UILabel). 184 | - (void)showActivityIndicatorWithMessage:(NSString *)msg; 185 | 186 | //Hides the activity indicator, and changes the title (if the title is available) to the msg 187 | - (void)hideActivityIndicatorWithMessage:(NSString *)msg; 188 | 189 | #pragma mark - Custom Image Showing 190 | 191 | //Animate in, and display the image provided here. 192 | - (void)showImage:(UIImage *)image withMessage:(NSString *)msg; 193 | 194 | #pragma mark - Error/Success Methods 195 | 196 | //Shows (and animates in) an error X in the contentView 197 | - (void)showError; 198 | 199 | //Shows (and animates in) a success checkmark in the contentView 200 | - (void)showSuccess; 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /PopoverView/PopoverView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PopoverView.m 3 | // Embark 4 | // 5 | // Created by Oliver Rickard on 20/08/2012. 6 | // 7 | // 8 | 9 | #import "PopoverView.h" 10 | #import "PopoverView_Configuration.h" 11 | #import 12 | 13 | #pragma mark - Implementation 14 | 15 | @implementation PopoverView 16 | 17 | @synthesize subviewsArray; 18 | @synthesize contentView; 19 | @synthesize titleView; 20 | @synthesize delegate; 21 | 22 | #pragma mark - Static Methods 23 | 24 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text delegate:(id)delegate { 25 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 26 | [popoverView showAtPoint:point inView:view withText:text]; 27 | popoverView.delegate = delegate; 28 | [popoverView RELEASE]; 29 | return popoverView; 30 | } 31 | 32 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withText:(NSString *)text delegate:(id)delegate { 33 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 34 | [popoverView showAtPoint:point inView:view withTitle:title withText:text]; 35 | popoverView.delegate = delegate; 36 | [popoverView RELEASE]; 37 | return popoverView; 38 | } 39 | 40 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray delegate:(id)delegate { 41 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 42 | [popoverView showAtPoint:point inView:view withViewArray:viewArray]; 43 | popoverView.delegate = delegate; 44 | [popoverView RELEASE]; 45 | return popoverView; 46 | } 47 | 48 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray delegate:(id)delegate { 49 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 50 | [popoverView showAtPoint:point inView:view withTitle:title withViewArray:viewArray]; 51 | popoverView.delegate = delegate; 52 | [popoverView RELEASE]; 53 | return popoverView; 54 | } 55 | 56 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray delegate:(id)delegate { 57 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 58 | [popoverView showAtPoint:point inView:view withStringArray:stringArray]; 59 | popoverView.delegate = delegate; 60 | [popoverView RELEASE]; 61 | return popoverView; 62 | } 63 | 64 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray delegate:(id)delegate { 65 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 66 | [popoverView showAtPoint:point inView:view withTitle:title withStringArray:stringArray]; 67 | popoverView.delegate = delegate; 68 | [popoverView RELEASE]; 69 | return popoverView; 70 | } 71 | 72 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray delegate:(id)delegate { 73 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 74 | [popoverView showAtPoint:point inView:view withStringArray:stringArray withImageArray:imageArray]; 75 | popoverView.delegate = delegate; 76 | [popoverView RELEASE]; 77 | return popoverView; 78 | } 79 | 80 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray delegate:(id)delegate { 81 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 82 | [popoverView showAtPoint:point inView:view withTitle:title withStringArray:stringArray withImageArray:imageArray]; 83 | popoverView.delegate = delegate; 84 | [popoverView RELEASE]; 85 | return popoverView; 86 | } 87 | 88 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView delegate:(id)delegate { 89 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 90 | [popoverView showAtPoint:point inView:view withTitle:title withContentView:cView]; 91 | popoverView.delegate = delegate; 92 | [popoverView RELEASE]; 93 | return popoverView; 94 | } 95 | 96 | + (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)cView delegate:(id)delegate { 97 | PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero]; 98 | [popoverView showAtPoint:point inView:view withContentView:cView]; 99 | popoverView.delegate = delegate; 100 | [popoverView RELEASE]; 101 | return popoverView; 102 | } 103 | 104 | #pragma mark - View Lifecycle 105 | 106 | - (id)initWithFrame:(CGRect)frame 107 | { 108 | self = [super initWithFrame:frame]; 109 | if (self) { 110 | // Initialization code 111 | 112 | self.backgroundColor = [UIColor clearColor]; 113 | 114 | self.titleView = nil; 115 | self.contentView = nil; 116 | 117 | showDividerRects = kShowDividersBetweenViews; 118 | } 119 | return self; 120 | } 121 | 122 | - (void)dealloc 123 | { 124 | self.subviewsArray = nil; 125 | 126 | if (dividerRects) { 127 | [dividerRects RELEASE]; 128 | dividerRects = nil; 129 | } 130 | 131 | self.contentView = nil; 132 | self.titleView = nil; 133 | 134 | [super DEALLOC]; 135 | } 136 | 137 | 138 | 139 | #pragma mark - Display methods 140 | 141 | // get the screen size, adjusted for orientation and status bar display 142 | // see http://stackoverflow.com/questions/7905432/how-to-get-orientation-dependent-height-and-width-of-the-screen/7905540#7905540 143 | - (CGSize) screenSize 144 | { 145 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 146 | CGSize size = [UIScreen mainScreen].bounds.size; 147 | UIApplication *application = [UIApplication sharedApplication]; 148 | if (UIInterfaceOrientationIsLandscape(orientation)) 149 | { 150 | size = CGSizeMake(size.height, size.width); 151 | } 152 | if (application.statusBarHidden == NO) 153 | { 154 | size.height -= MIN(application.statusBarFrame.size.width, application.statusBarFrame.size.height); 155 | } 156 | return size; 157 | } 158 | 159 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text 160 | { 161 | UIFont *font = kTextFont; 162 | 163 | CGSize screenSize = [self screenSize]; 164 | CGSize textSize = [text sizeWithFont:font constrainedToSize:CGSizeMake(screenSize.width - kHorizontalMargin*4.f, 1000.f) lineBreakMode:UILineBreakModeWordWrap]; 165 | 166 | UILabel *textView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; 167 | textView.backgroundColor = [UIColor clearColor]; 168 | textView.userInteractionEnabled = NO; 169 | [textView setNumberOfLines:0]; //This is so the label word wraps instead of cutting off the text 170 | textView.font = font; 171 | textView.textAlignment = kTextAlignment; 172 | textView.textColor = kTextColor; 173 | textView.text = text; 174 | 175 | [self showAtPoint:point inView:view withViewArray:[NSArray arrayWithObject:[textView AUTORELEASE]]]; 176 | } 177 | 178 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withText:(NSString *)text 179 | { 180 | UIFont *font = kTextFont; 181 | 182 | CGSize screenSize = [self screenSize]; 183 | CGSize textSize = [text sizeWithFont:font constrainedToSize:CGSizeMake(screenSize.width - kHorizontalMargin*4.f, 1000.f) lineBreakMode:UILineBreakModeWordWrap]; 184 | 185 | UILabel *textView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; 186 | textView.backgroundColor = [UIColor clearColor]; 187 | textView.userInteractionEnabled = NO; 188 | [textView setNumberOfLines:0]; //This is so the label word wraps instead of cutting off the text 189 | textView.font = font; 190 | textView.textAlignment = kTextAlignment; 191 | textView.textColor = kTextColor; 192 | textView.text = text; 193 | 194 | [self showAtPoint:point inView:view withTitle:title withViewArray:[NSArray arrayWithObject:[textView AUTORELEASE]]]; 195 | } 196 | 197 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray 198 | { 199 | UIView *container = [[UIView alloc] initWithFrame:CGRectZero]; 200 | 201 | float totalHeight = 0.f; 202 | float totalWidth = 0.f; 203 | 204 | int i = 0; 205 | 206 | //Position each view the first time, and identify which view has the largest width that controls 207 | //the sizing of the popover. 208 | for (UIView *view in viewArray) { 209 | 210 | view.frame = CGRectMake(0, totalHeight, view.frame.size.width, view.frame.size.height); 211 | //Only add padding below the view if it's not the last item 212 | float padding = (i == viewArray.count-1) ? 0 : kBoxPadding; 213 | 214 | totalHeight += view.frame.size.height + padding; 215 | 216 | if (view.frame.size.width > totalWidth) { 217 | totalWidth = view.frame.size.width; 218 | } 219 | 220 | [container addSubview:view]; 221 | 222 | i++; 223 | } 224 | 225 | //If dividers are enabled, then we allocate the divider rect array. This will hold NSValues 226 | if (kShowDividersBetweenViews) { 227 | dividerRects = [[NSMutableArray alloc] initWithCapacity:viewArray.count-1]; 228 | } 229 | 230 | container.frame = CGRectMake(0, 0, totalWidth, totalHeight); 231 | 232 | i = 0; 233 | 234 | totalHeight = 0; 235 | 236 | //Now we actually change the frame element for each subview, and center the views horizontally. 237 | for (UIView *view in viewArray) { 238 | if ([view autoresizingMask] == UIViewAutoresizingFlexibleWidth) { 239 | //Now make sure all flexible views are the full width 240 | view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height); 241 | } else { 242 | //If the view is not flexible width, then we position it centered in the view 243 | //without stretching it. 244 | view.frame = CGRectMake(floorf(CGRectGetMinX(boxFrame) + totalWidth*0.5f - view.frame.size.width*0.5f), view.frame.origin.y, view.frame.size.width, view.frame.size.height); 245 | } 246 | 247 | //and if dividers are enabled, we record their position for the drawing methods 248 | if (kShowDividersBetweenViews && i != viewArray.count-1) { 249 | CGRect dividerRect = CGRectMake(view.frame.origin.x, floorf(view.frame.origin.y + view.frame.size.height + kBoxPadding*0.5f), view.frame.size.width, 0.5f); 250 | 251 | [((NSMutableArray *)dividerRects) addObject:[NSValue valueWithCGRect:dividerRect]]; 252 | } 253 | 254 | //Only add padding below the view if it's not the last item 255 | float padding = (i == viewArray.count-1) ? 0.f : kBoxPadding; 256 | 257 | totalHeight += view.frame.size.height + padding; 258 | 259 | i++; 260 | } 261 | 262 | self.subviewsArray = viewArray; 263 | 264 | [self showAtPoint:point inView:view withContentView:[container AUTORELEASE]]; 265 | } 266 | 267 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray 268 | { 269 | UIView *container = [[UIView alloc] initWithFrame:CGRectZero]; 270 | 271 | //Create a label for the title text. 272 | CGSize titleSize = [title sizeWithFont:kTitleFont]; 273 | UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.f, 0.f, titleSize.width, titleSize.height)]; 274 | titleLabel.backgroundColor = [UIColor clearColor]; 275 | titleLabel.font = kTitleFont; 276 | titleLabel.textAlignment = UITextAlignmentCenter; 277 | titleLabel.textColor = kTitleColor; 278 | titleLabel.text = title; 279 | 280 | //Make sure that the title's label will have non-zero height. If it has zero height, then we don't allocate any space 281 | //for it in the positioning of the views. 282 | float titleHeightOffset = (titleSize.height > 0.f ? kBoxPadding : 0.f); 283 | 284 | float totalHeight = titleSize.height + titleHeightOffset + kBoxPadding; 285 | float totalWidth = titleSize.width; 286 | 287 | int i = 0; 288 | 289 | //Position each view the first time, and identify which view has the largest width that controls 290 | //the sizing of the popover. 291 | for (UIView *view in viewArray) { 292 | 293 | view.frame = CGRectMake(0, totalHeight, view.frame.size.width, view.frame.size.height); 294 | 295 | //Only add padding below the view if it's not the last item. 296 | float padding = (i == viewArray.count-1) ? 0.f : kBoxPadding; 297 | 298 | totalHeight += view.frame.size.height + padding; 299 | 300 | if (view.frame.size.width > totalWidth) { 301 | totalWidth = view.frame.size.width; 302 | } 303 | 304 | [container addSubview:view]; 305 | 306 | i++; 307 | } 308 | 309 | //If dividers are enabled, then we allocate the divider rect array. This will hold NSValues 310 | if (kShowDividersBetweenViews) { 311 | dividerRects = [[NSMutableArray alloc] initWithCapacity:viewArray.count-1]; 312 | } 313 | 314 | i = 0; 315 | 316 | for (UIView *view in viewArray) { 317 | if ([view autoresizingMask] == UIViewAutoresizingFlexibleWidth) { 318 | //Now make sure all flexible views are the full width 319 | view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height); 320 | } else { 321 | //If the view is not flexible width, then we position it centered in the view 322 | //without stretching it. 323 | view.frame = CGRectMake(floorf(CGRectGetMinX(boxFrame) + totalWidth*0.5f - view.frame.size.width*0.5f), view.frame.origin.y, view.frame.size.width, view.frame.size.height); 324 | } 325 | 326 | //and if dividers are enabled, we record their position for the drawing methods 327 | if (kShowDividersBetweenViews && i != viewArray.count-1) { 328 | CGRect dividerRect = CGRectMake(view.frame.origin.x, floorf(view.frame.origin.y + view.frame.size.height + kBoxPadding*0.5f), view.frame.size.width, 0.5f); 329 | 330 | [((NSMutableArray *)dividerRects) addObject:[NSValue valueWithCGRect:dividerRect]]; 331 | } 332 | 333 | i++; 334 | } 335 | 336 | titleLabel.frame = CGRectMake(floorf(totalWidth*0.5f - titleSize.width*0.5f), 0, titleSize.width, titleSize.height); 337 | 338 | //Store the titleView as an instance variable if it is larger than 0 height (not an empty string) 339 | if (titleSize.height > 0) { 340 | self.titleView = titleLabel; 341 | } 342 | 343 | [container addSubview:[titleLabel AUTORELEASE]]; 344 | 345 | container.frame = CGRectMake(0, 0, totalWidth, totalHeight); 346 | 347 | self.subviewsArray = viewArray; 348 | 349 | [self showAtPoint:point inView:view withContentView:[container AUTORELEASE]]; 350 | } 351 | 352 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray 353 | { 354 | NSMutableArray *labelArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count]; 355 | 356 | UIFont *font = kTextFont; 357 | 358 | for (NSString *string in stringArray) { 359 | CGSize textSize = [string sizeWithFont:font]; 360 | UIButton *textButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; 361 | textButton.backgroundColor = [UIColor clearColor]; 362 | textButton.titleLabel.font = font; 363 | textButton.titleLabel.textAlignment = kTextAlignment; 364 | textButton.titleLabel.textColor = kTextColor; 365 | [textButton setTitle:string forState:UIControlStateNormal]; 366 | textButton.layer.cornerRadius = 4.f; 367 | [textButton setTitleColor:kTextColor forState:UIControlStateNormal]; 368 | [textButton setTitleColor:kTextHighlightColor forState:UIControlStateHighlighted]; 369 | [textButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside]; 370 | 371 | [labelArray addObject:[textButton AUTORELEASE]]; 372 | } 373 | 374 | [self showAtPoint:point inView:view withViewArray:[labelArray AUTORELEASE]]; 375 | } 376 | 377 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray 378 | { 379 | NSMutableArray *labelArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count]; 380 | 381 | UIFont *font = kTextFont; 382 | 383 | for (NSString *string in stringArray) { 384 | CGSize textSize = [string sizeWithFont:font]; 385 | UIButton *textButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; 386 | textButton.backgroundColor = [UIColor clearColor]; 387 | textButton.titleLabel.font = font; 388 | textButton.titleLabel.textAlignment = kTextAlignment; 389 | textButton.titleLabel.textColor = kTextColor; 390 | [textButton setTitle:string forState:UIControlStateNormal]; 391 | textButton.layer.cornerRadius = 4.f; 392 | [textButton setTitleColor:kTextColor forState:UIControlStateNormal]; 393 | [textButton setTitleColor:kTextHighlightColor forState:UIControlStateHighlighted]; 394 | [textButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside]; 395 | 396 | [labelArray addObject:[textButton AUTORELEASE]]; 397 | } 398 | 399 | [self showAtPoint:point inView:view withTitle:title withViewArray:[labelArray AUTORELEASE]]; 400 | } 401 | 402 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray 403 | { 404 | //Here we do something pretty similar to the stringArray method above. 405 | //We create an array of subviews that contains the strings and images centered above a label. 406 | 407 | NSAssert((stringArray.count == imageArray.count), @"stringArray.count should equal imageArray.count"); 408 | NSMutableArray* tempViewArray = [self makeTempViewsWithStrings:stringArray andImages:imageArray]; 409 | 410 | [self showAtPoint:point inView:view withViewArray:tempViewArray]; 411 | } 412 | 413 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray 414 | { 415 | NSAssert((stringArray.count == imageArray.count), @"stringArray.count should equal imageArray.count"); 416 | NSMutableArray* tempViewArray = [self makeTempViewsWithStrings:stringArray andImages:imageArray]; 417 | 418 | [self showAtPoint:point inView:view withTitle:title withViewArray:tempViewArray]; 419 | } 420 | 421 | - (NSMutableArray*) makeTempViewsWithStrings:(NSArray *)stringArray andImages:(NSArray *)imageArray 422 | { 423 | NSMutableArray *tempViewArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count]; 424 | 425 | UIFont *font = kTextFont; 426 | 427 | for (int i = 0; i < stringArray.count; i++) { 428 | NSString *string = [stringArray objectAtIndex:i]; 429 | 430 | //First we build a label for the text to set in. 431 | CGSize textSize = [string sizeWithFont:font]; 432 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; 433 | label.backgroundColor = [UIColor clearColor]; 434 | label.font = font; 435 | label.textAlignment = kTextAlignment; 436 | label.textColor = kTextColor; 437 | label.text = string; 438 | label.layer.cornerRadius = 4.f; 439 | 440 | //Now we grab the image at the same index in the imageArray, and create 441 | //a UIImageView for it. 442 | UIImage *image = [imageArray objectAtIndex:i]; 443 | UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; 444 | 445 | //Take the larger of the two widths as the width for the container 446 | float containerWidth = MAX(imageView.frame.size.width, label.frame.size.width); 447 | float containerHeight = label.frame.size.height + kImageTopPadding + kImageBottomPadding + imageView.frame.size.height; 448 | 449 | //This container will hold both the image and the label 450 | UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerWidth, containerHeight)]; 451 | 452 | //Now we do the frame manipulations to put the imageView on top of the label, both centered 453 | imageView.frame = CGRectMake(floorf(containerWidth*0.5f - imageView.frame.size.width*0.5f), kImageTopPadding, imageView.frame.size.width, imageView.frame.size.height); 454 | label.frame = CGRectMake(floorf(containerWidth*0.5f - label.frame.size.width*0.5f), imageView.frame.size.height + kImageBottomPadding + kImageTopPadding, label.frame.size.width, label.frame.size.height); 455 | 456 | [containerView addSubview:imageView]; 457 | [containerView addSubview:label]; 458 | 459 | [label RELEASE]; 460 | [imageView RELEASE]; 461 | 462 | [tempViewArray addObject:containerView]; 463 | [containerView RELEASE]; 464 | } 465 | 466 | return [tempViewArray AUTORELEASE]; 467 | } 468 | 469 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView 470 | { 471 | [self showAtPoint:point inView:view withTitle:title withViewArray:[NSArray arrayWithObject:cView]]; 472 | } 473 | 474 | - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)cView { 475 | 476 | //NSLog(@"point:%f,%f", point.x, point.y); 477 | 478 | self.contentView = cView; 479 | parentView = view; 480 | 481 | // get the top view 482 | // http://stackoverflow.com/questions/3843411/getting-reference-to-the-top-most-view-window-in-ios-application/8045804#8045804 483 | topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject]; 484 | 485 | [self setupLayout:point inView:view]; 486 | 487 | // Make the view small and transparent before animation 488 | self.alpha = 0.f; 489 | self.transform = CGAffineTransformMakeScale(0.1f, 0.1f); 490 | 491 | // animate into full size 492 | // First stage animates to 1.05x normal size, then second stage animates back down to 1x size. 493 | // This two-stage animation creates a little "pop" on open. 494 | [UIView animateWithDuration:0.2f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{ 495 | self.alpha = 1.f; 496 | self.transform = CGAffineTransformMakeScale(1.05f, 1.05f); 497 | } completion:^(BOOL finished) { 498 | [UIView animateWithDuration:0.08f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{ 499 | self.transform = CGAffineTransformIdentity; 500 | } completion:nil]; 501 | }]; 502 | } 503 | 504 | - (void)layoutAtPoint:(CGPoint)point inView:(UIView *)view 505 | { 506 | // make transparent 507 | self.alpha = 0.f; 508 | 509 | [self setupLayout:point inView:view]; 510 | 511 | // animate back to full opacity 512 | [UIView animateWithDuration:0.2f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{ 513 | self.alpha = 1.f; 514 | } completion:nil]; 515 | } 516 | 517 | -(void)setupLayout:(CGPoint)point inView:(UIView*)view 518 | { 519 | CGPoint topPoint = [topView convertPoint:point fromView:view]; 520 | 521 | arrowPoint = topPoint; 522 | 523 | //NSLog(@"arrowPoint:%f,%f", arrowPoint.x, arrowPoint.y); 524 | 525 | CGRect topViewBounds = topView.bounds; 526 | //NSLog(@"topViewBounds %@", NSStringFromCGRect(topViewBounds)); 527 | 528 | float contentHeight = contentView.frame.size.height; 529 | float contentWidth = contentView.frame.size.width; 530 | 531 | float padding = kBoxPadding; 532 | 533 | float boxHeight = contentHeight + 2.f*padding; 534 | float boxWidth = contentWidth + 2.f*padding; 535 | 536 | float xOrigin = 0.f; 537 | 538 | //Make sure the arrow point is within the drawable bounds for the popover. 539 | if (arrowPoint.x + kArrowHeight > topViewBounds.size.width - kHorizontalMargin - kBoxRadius - kArrowHorizontalPadding) {//Too far to the right 540 | arrowPoint.x = topViewBounds.size.width - kHorizontalMargin - kBoxRadius - kArrowHorizontalPadding - kArrowHeight; 541 | //NSLog(@"Correcting Arrow Point because it's too far to the right"); 542 | } else if (arrowPoint.x - kArrowHeight < kHorizontalMargin + kBoxRadius + kArrowHorizontalPadding) {//Too far to the left 543 | arrowPoint.x = kHorizontalMargin + kArrowHeight + kBoxRadius + kArrowHorizontalPadding; 544 | //NSLog(@"Correcting Arrow Point because it's too far to the left"); 545 | } 546 | 547 | //NSLog(@"arrowPoint:%f,%f", arrowPoint.x, arrowPoint.y); 548 | 549 | xOrigin = floorf(arrowPoint.x - boxWidth*0.5f); 550 | 551 | //Check to see if the centered xOrigin value puts the box outside of the normal range. 552 | if (xOrigin < CGRectGetMinX(topViewBounds) + kHorizontalMargin) { 553 | xOrigin = CGRectGetMinX(topViewBounds) + kHorizontalMargin; 554 | } else if (xOrigin + boxWidth > CGRectGetMaxX(topViewBounds) - kHorizontalMargin) { 555 | //Check to see if the positioning puts the box out of the window towards the left 556 | xOrigin = CGRectGetMaxX(topViewBounds) - kHorizontalMargin - boxWidth; 557 | } 558 | 559 | float arrowHeight = kArrowHeight; 560 | 561 | float topPadding = kTopMargin; 562 | 563 | above = YES; 564 | 565 | if (topPoint.y - contentHeight - arrowHeight - topPadding < CGRectGetMinY(topViewBounds)) { 566 | //Position below because it won't fit above. 567 | above = NO; 568 | 569 | boxFrame = CGRectMake(xOrigin, arrowPoint.y + arrowHeight, boxWidth, boxHeight); 570 | } else { 571 | //Position above. 572 | above = YES; 573 | 574 | boxFrame = CGRectMake(xOrigin, arrowPoint.y - arrowHeight - boxHeight, boxWidth, boxHeight); 575 | } 576 | 577 | //NSLog(@"boxFrame:(%f,%f,%f,%f)", boxFrame.origin.x, boxFrame.origin.y, boxFrame.size.width, boxFrame.size.height); 578 | 579 | CGRect contentFrame = CGRectMake(boxFrame.origin.x + padding, boxFrame.origin.y + padding, contentWidth, contentHeight); 580 | contentView.frame = contentFrame; 581 | 582 | //We set the anchorPoint here so the popover will "grow" out of the arrowPoint specified by the user. 583 | //You have to set the anchorPoint before setting the frame, because the anchorPoint property will 584 | //implicitly set the frame for the view, which we do not want. 585 | self.layer.anchorPoint = CGPointMake(arrowPoint.x / topViewBounds.size.width, arrowPoint.y / topViewBounds.size.height); 586 | self.frame = topViewBounds; 587 | [self setNeedsDisplay]; 588 | 589 | [self addSubview:contentView]; 590 | [topView addSubview:self]; 591 | 592 | //Add a tap gesture recognizer to the large invisible view (self), which will detect taps anywhere on the screen. 593 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; 594 | tap.cancelsTouchesInView = NO; // Allow touches through to a UITableView or other touchable view, as suggested by Dimajp. 595 | [self addGestureRecognizer:tap]; 596 | [tap RELEASE]; 597 | 598 | self.userInteractionEnabled = YES; 599 | } 600 | 601 | 602 | #pragma mark - Activity Indicator 603 | 604 | //Animates in a progress indicator, and removes 605 | - (void)showActivityIndicatorWithMessage:(NSString *)msg 606 | { 607 | if ([titleView isKindOfClass:[UILabel class]]) { 608 | ((UILabel *)titleView).text = msg; 609 | } 610 | 611 | if (subviewsArray && (subviewsArray.count > 0)) { 612 | [UIView animateWithDuration:0.2f animations:^{ 613 | for (UIView *view in subviewsArray) { 614 | view.alpha = 0.f; 615 | } 616 | }]; 617 | 618 | if (showDividerRects) { 619 | showDividerRects = NO; 620 | [self setNeedsDisplay]; 621 | } 622 | } 623 | 624 | if (activityIndicator) { 625 | [activityIndicator RELEASE]; 626 | [activityIndicator removeFromSuperview]; 627 | activityIndicator = nil; 628 | } 629 | 630 | activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 631 | activityIndicator.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - 10.f, CGRectGetMidY(contentView.bounds) - 10.f + 20.f, 20.f, 20.f); 632 | [contentView addSubview:activityIndicator]; 633 | 634 | [activityIndicator startAnimating]; 635 | } 636 | 637 | - (void)hideActivityIndicatorWithMessage:(NSString *)msg 638 | { 639 | if ([titleView isKindOfClass:[UILabel class]]) { 640 | ((UILabel *)titleView).text = msg; 641 | } 642 | 643 | [activityIndicator stopAnimating]; 644 | [UIView animateWithDuration:0.1f animations:^{ 645 | activityIndicator.alpha = 0.f; 646 | } completion:^(BOOL finished) { 647 | [activityIndicator RELEASE]; 648 | [activityIndicator removeFromSuperview]; 649 | activityIndicator = nil; 650 | }]; 651 | } 652 | 653 | - (void)showImage:(UIImage *)image withMessage:(NSString *)msg 654 | { 655 | UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; 656 | imageView.alpha = 0.f; 657 | imageView.frame = CGRectMake(floorf(CGRectGetMidX(contentView.bounds) - image.size.width*0.5f), floorf(CGRectGetMidY(contentView.bounds) - image.size.height*0.5f + ((self.titleView) ? 20 : 0.f)), image.size.width, image.size.height); 658 | imageView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); 659 | 660 | [contentView addSubview:[imageView AUTORELEASE]]; 661 | 662 | if (subviewsArray && (subviewsArray.count > 0)) { 663 | [UIView animateWithDuration:0.2f animations:^{ 664 | for (UIView *view in subviewsArray) { 665 | view.alpha = 0.f; 666 | } 667 | }]; 668 | 669 | if (showDividerRects) { 670 | showDividerRects = NO; 671 | [self setNeedsDisplay]; 672 | } 673 | } 674 | 675 | if (msg) { 676 | if ([titleView isKindOfClass:[UILabel class]]) { 677 | ((UILabel *)titleView).text = msg; 678 | } 679 | } 680 | 681 | [UIView animateWithDuration:0.2f delay:0.2f options:UIViewAnimationOptionCurveEaseOut animations:^{ 682 | imageView.alpha = 1.f; 683 | imageView.transform = CGAffineTransformIdentity; 684 | } completion:^(BOOL finished) { 685 | //[imageView removeFromSuperview]; 686 | }]; 687 | } 688 | 689 | - (void)showError 690 | { 691 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"error"]]; 692 | imageView.alpha = 0.f; 693 | imageView.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - 20.f, CGRectGetMidY(contentView.bounds) - 20.f + ((self.titleView) ? 20 : 0.f), 40.f, 40.f); 694 | imageView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); 695 | 696 | [contentView addSubview:[imageView AUTORELEASE]]; 697 | 698 | if (subviewsArray && (subviewsArray.count > 0)) { 699 | [UIView animateWithDuration:0.1f animations:^{ 700 | for (UIView *view in subviewsArray) { 701 | view.alpha = 0.f; 702 | } 703 | }]; 704 | 705 | if (showDividerRects) { 706 | showDividerRects = NO; 707 | [self setNeedsDisplay]; 708 | } 709 | } 710 | 711 | [UIView animateWithDuration:0.1f delay:0.1f options:UIViewAnimationOptionCurveEaseOut animations:^{ 712 | imageView.alpha = 1.f; 713 | imageView.transform = CGAffineTransformIdentity; 714 | } completion:^(BOOL finished) { 715 | //[imageView removeFromSuperview]; 716 | }]; 717 | 718 | } 719 | 720 | - (void)showSuccess 721 | { 722 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"success"]]; 723 | imageView.alpha = 0.f; 724 | imageView.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - 20.f, CGRectGetMidY(contentView.bounds) - 20.f + ((self.titleView) ? 20 : 0.f), 40.f, 40.f); 725 | imageView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); 726 | 727 | [contentView addSubview:[imageView AUTORELEASE]]; 728 | 729 | if (subviewsArray && (subviewsArray.count > 0)) { 730 | [UIView animateWithDuration:0.1f animations:^{ 731 | for (UIView *view in subviewsArray) { 732 | view.alpha = 0.f; 733 | } 734 | }]; 735 | 736 | if (showDividerRects) { 737 | showDividerRects = NO; 738 | [self setNeedsDisplay]; 739 | } 740 | } 741 | 742 | [UIView animateWithDuration:0.1f delay:0.1f options:UIViewAnimationOptionCurveEaseOut animations:^{ 743 | imageView.alpha = 1.f; 744 | imageView.transform = CGAffineTransformIdentity; 745 | } completion:^(BOOL finished) { 746 | //[imageView removeFromSuperview]; 747 | }]; 748 | 749 | } 750 | 751 | #pragma mark - User Interaction 752 | 753 | - (void)tapped:(UITapGestureRecognizer *)tap 754 | { 755 | CGPoint point = [tap locationInView:contentView]; 756 | 757 | //NSLog(@"point:(%f,%f)", point.x, point.y); 758 | 759 | BOOL found = NO; 760 | 761 | //NSLog(@"subviewsArray:%@", subviewsArray); 762 | 763 | for (int i = 0; i < subviewsArray.count && !found; i++) { 764 | UIView *view = [subviewsArray objectAtIndex:i]; 765 | 766 | //NSLog(@"Rect:(%f,%f,%f,%f)", view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height); 767 | 768 | if (CGRectContainsPoint(view.frame, point)) { 769 | //The tap was within this view, so we notify the delegate, and break the loop. 770 | 771 | found = YES; 772 | 773 | //NSLog(@"Tapped subview:%d", i); 774 | 775 | if ([view isKindOfClass:[UIButton class]]) { 776 | return; 777 | } 778 | 779 | if (delegate && [delegate respondsToSelector:@selector(popoverView:didSelectItemAtIndex:)]) { 780 | [delegate popoverView:self didSelectItemAtIndex:i]; 781 | } 782 | 783 | break; 784 | } 785 | } 786 | 787 | if (!found && CGRectContainsPoint(contentView.bounds, point)) { 788 | found = YES; 789 | //NSLog(@"popover box contains point, ignoring user input"); 790 | } 791 | 792 | if (!found) { 793 | [self dismiss:YES]; 794 | } 795 | 796 | } 797 | 798 | - (void)didTapButton:(UIButton *)sender 799 | { 800 | NSUInteger index = [subviewsArray indexOfObject:sender]; 801 | 802 | if (index == NSNotFound) { 803 | return; 804 | } 805 | 806 | if (delegate && [delegate respondsToSelector:@selector(popoverView:didSelectItemAtIndex:)]) { 807 | [delegate popoverView:self didSelectItemAtIndex:index]; 808 | } 809 | } 810 | 811 | - (void)dismiss 812 | { 813 | [self dismiss:YES]; 814 | } 815 | 816 | - (void)dismiss:(BOOL)animated 817 | { 818 | if (!animated) 819 | { 820 | [self dismissComplete]; 821 | } 822 | else 823 | { 824 | [UIView animateWithDuration:0.3f animations:^{ 825 | self.alpha = 0.1f; 826 | self.transform = CGAffineTransformMakeScale(0.1f, 0.1f); 827 | } completion:^(BOOL finished) { 828 | self.transform = CGAffineTransformIdentity; 829 | [self dismissComplete]; 830 | }]; 831 | } 832 | } 833 | 834 | - (void)dismissComplete 835 | { 836 | if (self.delegate && [self.delegate respondsToSelector:@selector(popoverViewDidDismiss:)]) { 837 | [delegate popoverViewDidDismiss:self]; 838 | } 839 | 840 | [self removeFromSuperview]; 841 | } 842 | 843 | - (void)animateRotationToNewPoint:(CGPoint)point inView:(UIView *)view withDuration:(NSTimeInterval)duration 844 | { 845 | [self layoutAtPoint:point inView:view]; 846 | } 847 | 848 | #pragma mark - Drawing Routines 849 | 850 | // Only override drawRect: if you perform custom drawing. 851 | // An empty implementation adversely affects performance during animation. 852 | - (void)drawRect:(CGRect)rect 853 | { 854 | // Drawing code 855 | 856 | // Build the popover path 857 | CGRect frame = boxFrame; 858 | 859 | float xMin = CGRectGetMinX(frame); 860 | float yMin = CGRectGetMinY(frame); 861 | 862 | float xMax = CGRectGetMaxX(frame); 863 | float yMax = CGRectGetMaxY(frame); 864 | 865 | float radius = kBoxRadius; //Radius of the curvature. 866 | 867 | float cpOffset = kCPOffset; //Control Point Offset. Modifies how "curved" the corners are. 868 | 869 | 870 | /* 871 | LT2 RT1 872 | LT1⌜⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⌝RT2 873 | | | 874 | | popover | 875 | | | 876 | LB2⌞_______________⌟RB1 877 | LB1 RB2 878 | 879 | Traverse rectangle in clockwise order, starting at LT1 880 | L = Left 881 | R = Right 882 | T = Top 883 | B = Bottom 884 | 1,2 = order of traversal for any given corner 885 | 886 | */ 887 | 888 | UIBezierPath *popoverPath = [UIBezierPath bezierPath]; 889 | [popoverPath moveToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMinY(frame) + radius)];//LT1 890 | [popoverPath addCurveToPoint:CGPointMake(xMin + radius, yMin) controlPoint1:CGPointMake(xMin, yMin + radius - cpOffset) controlPoint2:CGPointMake(xMin + radius - cpOffset, yMin)];//LT2 891 | 892 | //If the popover is positioned below (!above) the arrowPoint, then we know that the arrow must be on the top of the popover. 893 | //In this case, the arrow is located between LT2 and RT1 894 | if (!above) { 895 | [popoverPath addLineToPoint:CGPointMake(arrowPoint.x - kArrowHeight, yMin)];//left side 896 | [popoverPath addCurveToPoint:arrowPoint controlPoint1:CGPointMake(arrowPoint.x - kArrowHeight + kArrowCurvature, yMin) controlPoint2:arrowPoint];//actual arrow point 897 | [popoverPath addCurveToPoint:CGPointMake(arrowPoint.x + kArrowHeight, yMin) controlPoint1:arrowPoint controlPoint2:CGPointMake(arrowPoint.x + kArrowHeight - kArrowCurvature, yMin)];//right side 898 | } 899 | 900 | [popoverPath addLineToPoint:CGPointMake(xMax - radius, yMin)];//RT1 901 | [popoverPath addCurveToPoint:CGPointMake(xMax, yMin + radius) controlPoint1:CGPointMake(xMax - radius + cpOffset, yMin) controlPoint2:CGPointMake(xMax, yMin + radius - cpOffset)];//RT2 902 | [popoverPath addLineToPoint:CGPointMake(xMax, yMax - radius)];//RB1 903 | [popoverPath addCurveToPoint:CGPointMake(xMax - radius, yMax) controlPoint1:CGPointMake(xMax, yMax - radius + cpOffset) controlPoint2:CGPointMake(xMax - radius + cpOffset, yMax)];//RB2 904 | 905 | //If the popover is positioned above the arrowPoint, then we know that the arrow must be on the bottom of the popover. 906 | //In this case, the arrow is located somewhere between LB1 and RB2 907 | if (above) { 908 | [popoverPath addLineToPoint:CGPointMake(arrowPoint.x + kArrowHeight, yMax)];//right side 909 | [popoverPath addCurveToPoint:arrowPoint controlPoint1:CGPointMake(arrowPoint.x + kArrowHeight - kArrowCurvature, yMax) controlPoint2:arrowPoint];//arrow point 910 | [popoverPath addCurveToPoint:CGPointMake(arrowPoint.x - kArrowHeight, yMax) controlPoint1:arrowPoint controlPoint2:CGPointMake(arrowPoint.x - kArrowHeight + kArrowCurvature, yMax)]; 911 | } 912 | 913 | [popoverPath addLineToPoint:CGPointMake(xMin + radius, yMax)];//LB1 914 | [popoverPath addCurveToPoint:CGPointMake(xMin, yMax - radius) controlPoint1:CGPointMake(xMin + radius - cpOffset, yMax) controlPoint2:CGPointMake(xMin, yMax - radius + cpOffset)];//LB2 915 | [popoverPath closePath]; 916 | 917 | //// General Declarations 918 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 919 | CGContextRef context = UIGraphicsGetCurrentContext(); 920 | 921 | //// Shadow Declarations 922 | UIColor* shadow = [UIColor colorWithWhite:0.0f alpha:kShadowAlpha]; 923 | CGSize shadowOffset = CGSizeMake(0, 1); 924 | CGFloat shadowBlurRadius = kShadowBlur; 925 | 926 | //// Gradient Declarations 927 | NSArray* gradientColors = [NSArray arrayWithObjects: 928 | (id)kGradientTopColor.CGColor, 929 | (id)kGradientBottomColor.CGColor, nil]; 930 | CGFloat gradientLocations[] = {0, 1}; 931 | CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFTYPECAST(CFArrayRef)gradientColors), gradientLocations); 932 | 933 | 934 | //These floats are the top and bottom offsets for the gradient drawing so the drawing includes the arrows. 935 | float bottomOffset = (above ? kArrowHeight : 0.f); 936 | float topOffset = (!above ? kArrowHeight : 0.f); 937 | 938 | //Draw the actual gradient and shadow. 939 | CGContextSaveGState(context); 940 | CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor); 941 | CGContextBeginTransparencyLayer(context, NULL); 942 | [popoverPath addClip]; 943 | CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame) - topOffset), CGPointMake(CGRectGetMidX(frame), CGRectGetMaxY(frame) + bottomOffset), 0); 944 | CGContextEndTransparencyLayer(context); 945 | CGContextRestoreGState(context); 946 | 947 | //// Cleanup 948 | CGGradientRelease(gradient); 949 | CGColorSpaceRelease(colorSpace); 950 | 951 | 952 | //Draw the title background 953 | if (kDrawTitleGradient) { 954 | //Calculate the height of the title bg 955 | float titleBGHeight = -1; 956 | 957 | //NSLog(@"titleView:%@", titleView); 958 | 959 | if (titleView != nil) { 960 | titleBGHeight = kBoxPadding*2.f + titleView.frame.size.height; 961 | } 962 | 963 | 964 | //Draw the title bg height, but only if we need to. 965 | if (titleBGHeight > 0.f) { 966 | CGPoint startingPoint = CGPointMake(xMin, yMin + titleBGHeight); 967 | CGPoint endingPoint = CGPointMake(xMax, yMin + titleBGHeight); 968 | 969 | UIBezierPath *titleBGPath = [UIBezierPath bezierPath]; 970 | [titleBGPath moveToPoint:startingPoint]; 971 | [titleBGPath addLineToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMinY(frame) + radius)];//LT1 972 | [titleBGPath addCurveToPoint:CGPointMake(xMin + radius, yMin) controlPoint1:CGPointMake(xMin, yMin + radius - cpOffset) controlPoint2:CGPointMake(xMin + radius - cpOffset, yMin)];//LT2 973 | 974 | //If the popover is positioned below (!above) the arrowPoint, then we know that the arrow must be on the top of the popover. 975 | //In this case, the arrow is located between LT2 and RT1 976 | if (!above) { 977 | [titleBGPath addLineToPoint:CGPointMake(arrowPoint.x - kArrowHeight, yMin)];//left side 978 | [titleBGPath addCurveToPoint:arrowPoint controlPoint1:CGPointMake(arrowPoint.x - kArrowHeight + kArrowCurvature, yMin) controlPoint2:arrowPoint];//actual arrow point 979 | [titleBGPath addCurveToPoint:CGPointMake(arrowPoint.x + kArrowHeight, yMin) controlPoint1:arrowPoint controlPoint2:CGPointMake(arrowPoint.x + kArrowHeight - kArrowCurvature, yMin)];//right side 980 | } 981 | 982 | [titleBGPath addLineToPoint:CGPointMake(xMax - radius, yMin)];//RT1 983 | [titleBGPath addCurveToPoint:CGPointMake(xMax, yMin + radius) controlPoint1:CGPointMake(xMax - radius + cpOffset, yMin) controlPoint2:CGPointMake(xMax, yMin + radius - cpOffset)];//RT2 984 | [titleBGPath addLineToPoint:endingPoint]; 985 | [titleBGPath addLineToPoint:startingPoint]; 986 | [titleBGPath closePath]; 987 | 988 | //// General Declarations 989 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 990 | CGContextRef context = UIGraphicsGetCurrentContext(); 991 | 992 | //// Gradient Declarations 993 | NSArray* gradientColors = [NSArray arrayWithObjects: 994 | (id)kGradientTitleTopColor.CGColor, 995 | (id)kGradientTitleBottomColor.CGColor, nil]; 996 | CGFloat gradientLocations[] = {0, 1}; 997 | CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFTYPECAST(CFArrayRef)gradientColors), gradientLocations); 998 | 999 | 1000 | //These floats are the top and bottom offsets for the gradient drawing so the drawing includes the arrows. 1001 | float topOffset = (!above ? kArrowHeight : 0.f); 1002 | 1003 | //Draw the actual gradient and shadow. 1004 | CGContextSaveGState(context); 1005 | CGContextBeginTransparencyLayer(context, NULL); 1006 | [titleBGPath addClip]; 1007 | CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame) - topOffset), CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame) + titleBGHeight), 0); 1008 | CGContextEndTransparencyLayer(context); 1009 | CGContextRestoreGState(context); 1010 | 1011 | UIBezierPath *dividerLine = [UIBezierPath bezierPathWithRect:CGRectMake(startingPoint.x, startingPoint.y, (endingPoint.x - startingPoint.x), 0.5f)]; 1012 | [[UIColor colorWithRed:0.741 green:0.741 blue:0.741 alpha:0.5f] setFill]; 1013 | [dividerLine fill]; 1014 | 1015 | //// Cleanup 1016 | CGGradientRelease(gradient); 1017 | CGColorSpaceRelease(colorSpace); 1018 | } 1019 | } 1020 | 1021 | 1022 | 1023 | //Draw the divider rects if we need to 1024 | { 1025 | if (kShowDividersBetweenViews && showDividerRects) { 1026 | if (dividerRects && dividerRects.count > 0) { 1027 | for (NSValue *value in dividerRects) { 1028 | CGRect rect = value.CGRectValue; 1029 | rect.origin.x += contentView.frame.origin.x; 1030 | rect.origin.y += contentView.frame.origin.y; 1031 | 1032 | UIBezierPath *dividerPath = [UIBezierPath bezierPathWithRect:rect]; 1033 | [kDividerColor setFill]; 1034 | [dividerPath fill]; 1035 | } 1036 | } 1037 | } 1038 | } 1039 | 1040 | //Draw border if we need to 1041 | //The border is done last because it needs to be drawn on top of everything else 1042 | if (kDrawBorder) { 1043 | [kBorderColor setStroke]; 1044 | popoverPath.lineWidth = kBorderWidth; 1045 | [popoverPath stroke]; 1046 | } 1047 | 1048 | } 1049 | 1050 | @end 1051 | -------------------------------------------------------------------------------- /PopoverView/PopoverViewCompatibility.h: -------------------------------------------------------------------------------- 1 | // 2 | // PopoverViewCompatibility.h 3 | // popover 4 | // 5 | // Created by alanduncan on 7/22/13. 6 | // Copyright (c) 2013 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #ifndef popover_PopoverViewCompatibility_h 10 | #define popover_PopoverViewCompatibility_h 11 | 12 | #ifdef __IPHONE_6_0 13 | 14 | #define UITextAlignmentCenter NSTextAlignmentCenter 15 | #define UITextAlignmentLeft NSTextAlignmentLeft 16 | #define UITextAlignmentRight NSTextAlignmentRight 17 | #define UILineBreakModeTailTruncation NSLineBreakByTruncatingTail 18 | #define UILineBreakModeMiddleTruncation NSLineBreakByTruncatingMiddle 19 | #define UILineBreakModeWordWrap NSLineBreakByWordWrapping 20 | 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /PopoverView/PopoverView_Configuration.h: -------------------------------------------------------------------------------- 1 | // 2 | // PopoverView_Configuration.h 3 | // popover 4 | // 5 | // Created by Bas Pellis on 12/25/12. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #pragma mark Constants - Configure look/feel 10 | 11 | // BOX GEOMETRY 12 | 13 | //Height/width of the actual arrow 14 | #define kArrowHeight 12.f 15 | 16 | //padding within the box for the contentView 17 | #define kBoxPadding 10.f 18 | 19 | //control point offset for rounding corners of the main popover box 20 | #define kCPOffset 1.8f 21 | 22 | //radius for the rounded corners of the main popover box 23 | #define kBoxRadius 4.f 24 | 25 | //Curvature value for the arrow. Set to 0.f to make it linear. 26 | #define kArrowCurvature 6.f 27 | 28 | //Minimum distance from the side of the arrow to the beginning of curvature for the box 29 | #define kArrowHorizontalPadding 5.f 30 | 31 | //Alpha value for the shadow behind the PopoverView 32 | #define kShadowAlpha 0.4f 33 | 34 | //Blur for the shadow behind the PopoverView 35 | #define kShadowBlur 3.f; 36 | 37 | //Box gradient bg alpha 38 | #define kBoxAlpha 0.95f 39 | 40 | //Padding along top of screen to allow for any nav/status bars 41 | #define kTopMargin 50.f 42 | 43 | //margin along the left and right of the box 44 | #define kHorizontalMargin 10.f 45 | 46 | //padding along top of icons/images 47 | #define kImageTopPadding 3.f 48 | 49 | //padding along bottom of icons/images 50 | #define kImageBottomPadding 3.f 51 | 52 | 53 | // DIVIDERS BETWEEN VIEWS 54 | 55 | //Bool that turns off/on the dividers 56 | #define kShowDividersBetweenViews NO 57 | 58 | //color for the divider fill 59 | #define kDividerColor [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:0.15f] 60 | 61 | 62 | // BACKGROUND GRADIENT 63 | 64 | //bottom color white in gradient bg 65 | #define kGradientBottomColor [UIColor colorWithRed:0.98f green:0.98f blue:0.98f alpha:kBoxAlpha] 66 | 67 | //top color white value in gradient bg 68 | #define kGradientTopColor [UIColor colorWithRed:1.f green:1.f blue:1.f alpha:kBoxAlpha] 69 | 70 | 71 | // TITLE GRADIENT 72 | 73 | //bool that turns off/on title gradient 74 | #define kDrawTitleGradient YES 75 | 76 | //bottom color white value in title gradient bg 77 | #define kGradientTitleBottomColor [UIColor colorWithRed:0.93f green:0.93f blue:0.93f alpha:kBoxAlpha] 78 | 79 | //top color white value in title gradient bg 80 | #define kGradientTitleTopColor [UIColor colorWithRed:1.f green:1.f blue:1.f alpha:kBoxAlpha] 81 | 82 | 83 | // FONTS 84 | 85 | //normal text font 86 | #define kTextFont [UIFont fontWithName:@"HelveticaNeue" size:16.f] 87 | 88 | //normal text color 89 | #define kTextColor [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1] 90 | // highlighted text color 91 | #define kTextHighlightColor [UIColor colorWithRed:0.098 green:0.102 blue:0.106 alpha:1.000] 92 | 93 | //normal text alignment 94 | #define kTextAlignment UITextAlignmentCenter 95 | 96 | //title font 97 | #define kTitleFont [UIFont fontWithName:@"HelveticaNeue-Bold" size:16.f] 98 | 99 | //title text color 100 | #define kTitleColor [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1] 101 | 102 | 103 | // BORDER 104 | 105 | //bool that turns off/on the border 106 | #define kDrawBorder NO 107 | 108 | //border color 109 | #define kBorderColor [UIColor blackColor] 110 | 111 | //border width 112 | #define kBorderWidth 1.f -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | #PopoverView# 2 | 3 | PopoverView is a simple resolution-independent UIView written entirely in CoreGraphics and QuartzCore for display of modal content on both iPhone and iPad. It can display singular UIView contentViews, arrays of `UIViews`, display titles, or even allow selection from a list of strings. It is implemented via a very simple static interface that allows you to show the popover with just a single line. All animation, positioning, and memory allocations are handled by the component at runtime. We are releasing under the MIT License. 4 | 5 | For More Information, please see our full blog post: 6 | [PopoverView](http://www.getosito.com/blog/engineering/popoverview-a-flexible-modal-content-view-for-ios/) 7 | 8 | *** 9 | 10 | 11 | 12 | *** 13 | 14 | ##Demonstration## 15 | As a quick demonstration, I used a UIView from another one of my components called OCCalendar[^1]. To display this to the user on tap, I simply allocate and initialize the view, then I use a single line to display it to the user. The PopoverView handles positioning above/below the point of interest, handles all of the memory management, and manages the view stack so it gets displayed to the user at the correct location. 16 | 17 | ``` objc 18 | OCDaysView *daysView = [[OCDaysView alloc] initWithFrame:CGRectMake(0, 0, 150, 100)]; 19 | [daysView setMonth:10]; 20 | [daysView setYear:2012]; 21 | //[PopoverView showPopoverAtPoint:point inView:self.view withContentView:[daysView autorelease] delegate:self]; 22 | [PopoverView showPopoverAtPoint:point inView:self.view withTitle:@"October 2012" withContentView:[daysView autorelease] delegate:self]; 23 | ``` 24 | 25 | As you may note, I have two versions of the display code here. One of them displays the `daysView` as a single `contentView` with no title, and the other displays the same view with a "October 2012" title. 26 | 27 | 28 | 29 | *** 30 | 31 | ##Demo Project## 32 | The structure of the demo project is very simple. The PopoverView.h and .m files are in the "PopoverView" folder in the root directory. The demo project files are in the "popover/demo" subdirectory. 33 | 34 | *** 35 | 36 | ##License## 37 | 38 | (MIT Licensed) 39 | 40 | Copyright (c) 2012 Runway 20 Inc. 41 | 42 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 43 | 44 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47 | -------------------------------------------------------------------------------- /popover.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B1175C5A15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5915E3FBEE002FBFF1 /* UIKit.framework */; }; 11 | B1175C5C15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */; }; 12 | B1175C5E15E3FBEE002FBFF1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5D15E3FBEE002FBFF1 /* CoreGraphics.framework */; }; 13 | B1175C6415E3FBEE002FBFF1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1175C6215E3FBEE002FBFF1 /* InfoPlist.strings */; }; 14 | B1175C6615E3FBEE002FBFF1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C6515E3FBEE002FBFF1 /* main.m */; }; 15 | B1175C6A15E3FBEE002FBFF1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C6915E3FBEE002FBFF1 /* AppDelegate.m */; }; 16 | B1175C6D15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1175C6B15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard */; }; 17 | B1175C7015E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1175C6E15E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard */; }; 18 | B1175C7315E3FBEE002FBFF1 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C7215E3FBEE002FBFF1 /* ViewController.m */; }; 19 | B1175C7B15E3FBEE002FBFF1 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C7A15E3FBEE002FBFF1 /* SenTestingKit.framework */; }; 20 | B1175C7C15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5915E3FBEE002FBFF1 /* UIKit.framework */; }; 21 | B1175C7D15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */; }; 22 | B1175C8515E3FBEE002FBFF1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1175C8315E3FBEE002FBFF1 /* InfoPlist.strings */; }; 23 | B1175C8815E3FBEE002FBFF1 /* popoverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C8715E3FBEE002FBFF1 /* popoverTests.m */; }; 24 | B1175C9215E3FC07002FBFF1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C9115E3FC07002FBFF1 /* QuartzCore.framework */; }; 25 | B1175C9515E3FC13002FBFF1 /* PopoverView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C9415E3FC13002FBFF1 /* PopoverView.m */; }; 26 | B1175C9615E3FC13002FBFF1 /* PopoverView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C9415E3FC13002FBFF1 /* PopoverView.m */; }; 27 | B14F47581603A267003EC4FF /* error.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47541603A267003EC4FF /* error.png */; }; 28 | B14F47591603A267003EC4FF /* error@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47551603A267003EC4FF /* error@2x.png */; }; 29 | B14F475A1603A267003EC4FF /* success.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47561603A267003EC4FF /* success.png */; }; 30 | B14F475B1603A267003EC4FF /* success@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47571603A267003EC4FF /* success@2x.png */; }; 31 | B1ACBE981603859A006F8461 /* OCDaysView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1ACBE971603859A006F8461 /* OCDaysView.m */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | B1175C7E15E3FBEE002FBFF1 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = B1175C4C15E3FBEE002FBFF1 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = B1175C5415E3FBEE002FBFF1; 40 | remoteInfo = popover; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 0867719D1689B04F00ED150F /* PopoverView_Configuration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PopoverView_Configuration.h; sourceTree = ""; }; 46 | B1175C5515E3FBEE002FBFF1 /* popover.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = popover.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | B1175C5915E3FBEE002FBFF1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 49 | B1175C5D15E3FBEE002FBFF1 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 50 | B1175C6115E3FBEE002FBFF1 /* popover-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "popover-Info.plist"; sourceTree = ""; }; 51 | B1175C6315E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 52 | B1175C6515E3FBEE002FBFF1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | B1175C6715E3FBEE002FBFF1 /* popover-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "popover-Prefix.pch"; sourceTree = ""; }; 54 | B1175C6815E3FBEE002FBFF1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 55 | B1175C6915E3FBEE002FBFF1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 56 | B1175C6C15E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = ""; }; 57 | B1175C6F15E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = ""; }; 58 | B1175C7115E3FBEE002FBFF1 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 59 | B1175C7215E3FBEE002FBFF1 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 60 | B1175C7915E3FBEE002FBFF1 /* popoverTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = popoverTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | B1175C7A15E3FBEE002FBFF1 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 62 | B1175C8215E3FBEE002FBFF1 /* popoverTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "popoverTests-Info.plist"; sourceTree = ""; }; 63 | B1175C8415E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 64 | B1175C8615E3FBEE002FBFF1 /* popoverTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = popoverTests.h; sourceTree = ""; }; 65 | B1175C8715E3FBEE002FBFF1 /* popoverTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = popoverTests.m; sourceTree = ""; }; 66 | B1175C9115E3FC07002FBFF1 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 67 | B1175C9315E3FC13002FBFF1 /* PopoverView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopoverView.h; sourceTree = ""; }; 68 | B1175C9415E3FC13002FBFF1 /* PopoverView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PopoverView.m; sourceTree = ""; }; 69 | B14F47541603A267003EC4FF /* error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = error.png; path = popover/Images/error.png; sourceTree = SOURCE_ROOT; }; 70 | B14F47551603A267003EC4FF /* error@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "error@2x.png"; path = "popover/Images/error@2x.png"; sourceTree = SOURCE_ROOT; }; 71 | B14F47561603A267003EC4FF /* success.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = success.png; path = popover/Images/success.png; sourceTree = SOURCE_ROOT; }; 72 | B14F47571603A267003EC4FF /* success@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "success@2x.png"; path = "popover/Images/success@2x.png"; sourceTree = SOURCE_ROOT; }; 73 | B1ACBE961603859A006F8461 /* OCDaysView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCDaysView.h; sourceTree = ""; }; 74 | B1ACBE971603859A006F8461 /* OCDaysView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCDaysView.m; sourceTree = ""; }; 75 | E7F6CF2A179D542E00C944E3 /* PopoverViewCompatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopoverViewCompatibility.h; sourceTree = ""; }; 76 | E7F6CF2B179D573700C944E3 /* PopoverView.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = PopoverView.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; 77 | /* End PBXFileReference section */ 78 | 79 | /* Begin PBXFrameworksBuildPhase section */ 80 | B1175C5215E3FBEE002FBFF1 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | B1175C9215E3FC07002FBFF1 /* QuartzCore.framework in Frameworks */, 85 | B1175C5A15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */, 86 | B1175C5C15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */, 87 | B1175C5E15E3FBEE002FBFF1 /* CoreGraphics.framework in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | B1175C7515E3FBEE002FBFF1 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | B1175C7B15E3FBEE002FBFF1 /* SenTestingKit.framework in Frameworks */, 96 | B1175C7C15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */, 97 | B1175C7D15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | /* End PBXFrameworksBuildPhase section */ 102 | 103 | /* Begin PBXGroup section */ 104 | B1175C4A15E3FBEE002FBFF1 = { 105 | isa = PBXGroup; 106 | children = ( 107 | E7F6CF2B179D573700C944E3 /* PopoverView.podspec */, 108 | B1175C9115E3FC07002FBFF1 /* QuartzCore.framework */, 109 | B1175C5F15E3FBEE002FBFF1 /* popover */, 110 | B1175C8015E3FBEE002FBFF1 /* popoverTests */, 111 | B1175C5815E3FBEE002FBFF1 /* Frameworks */, 112 | B1175C5615E3FBEE002FBFF1 /* Products */, 113 | ); 114 | sourceTree = ""; 115 | }; 116 | B1175C5615E3FBEE002FBFF1 /* Products */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | B1175C5515E3FBEE002FBFF1 /* popover.app */, 120 | B1175C7915E3FBEE002FBFF1 /* popoverTests.octest */, 121 | ); 122 | name = Products; 123 | sourceTree = ""; 124 | }; 125 | B1175C5815E3FBEE002FBFF1 /* Frameworks */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | B1175C5915E3FBEE002FBFF1 /* UIKit.framework */, 129 | B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */, 130 | B1175C5D15E3FBEE002FBFF1 /* CoreGraphics.framework */, 131 | B1175C7A15E3FBEE002FBFF1 /* SenTestingKit.framework */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | B1175C5F15E3FBEE002FBFF1 /* popover */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | B1ACBE941603858D006F8461 /* Demo Calendar View - Not Important */, 140 | B1C7262515EE822B008C4D05 /* PopoverView */, 141 | B1ACBE991603A040006F8461 /* Demo */, 142 | B1175C6015E3FBEE002FBFF1 /* Supporting Files */, 143 | ); 144 | path = popover; 145 | sourceTree = ""; 146 | }; 147 | B1175C6015E3FBEE002FBFF1 /* Supporting Files */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | B1C7262415EE8222008C4D05 /* Images */, 151 | B1175C6115E3FBEE002FBFF1 /* popover-Info.plist */, 152 | B1175C6515E3FBEE002FBFF1 /* main.m */, 153 | B1175C6715E3FBEE002FBFF1 /* popover-Prefix.pch */, 154 | B1175C6215E3FBEE002FBFF1 /* InfoPlist.strings */, 155 | ); 156 | name = "Supporting Files"; 157 | path = Demo; 158 | sourceTree = ""; 159 | }; 160 | B1175C8015E3FBEE002FBFF1 /* popoverTests */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | B1175C8615E3FBEE002FBFF1 /* popoverTests.h */, 164 | B1175C8715E3FBEE002FBFF1 /* popoverTests.m */, 165 | B1175C8115E3FBEE002FBFF1 /* Supporting Files */, 166 | ); 167 | path = popoverTests; 168 | sourceTree = ""; 169 | }; 170 | B1175C8115E3FBEE002FBFF1 /* Supporting Files */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | B1175C8215E3FBEE002FBFF1 /* popoverTests-Info.plist */, 174 | B1175C8315E3FBEE002FBFF1 /* InfoPlist.strings */, 175 | ); 176 | name = "Supporting Files"; 177 | sourceTree = ""; 178 | }; 179 | B1ACBE941603858D006F8461 /* Demo Calendar View - Not Important */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | B1ACBE961603859A006F8461 /* OCDaysView.h */, 183 | B1ACBE971603859A006F8461 /* OCDaysView.m */, 184 | ); 185 | name = "Demo Calendar View - Not Important"; 186 | path = "Demo/Calendar View"; 187 | sourceTree = ""; 188 | }; 189 | B1ACBE991603A040006F8461 /* Demo */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | B1175C6815E3FBEE002FBFF1 /* AppDelegate.h */, 193 | B1175C6915E3FBEE002FBFF1 /* AppDelegate.m */, 194 | B1175C6B15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard */, 195 | B1175C6E15E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard */, 196 | B1175C7115E3FBEE002FBFF1 /* ViewController.h */, 197 | B1175C7215E3FBEE002FBFF1 /* ViewController.m */, 198 | ); 199 | path = Demo; 200 | sourceTree = ""; 201 | }; 202 | B1C7262415EE8222008C4D05 /* Images */ = { 203 | isa = PBXGroup; 204 | children = ( 205 | B14F47541603A267003EC4FF /* error.png */, 206 | B14F47551603A267003EC4FF /* error@2x.png */, 207 | B14F47561603A267003EC4FF /* success.png */, 208 | B14F47571603A267003EC4FF /* success@2x.png */, 209 | ); 210 | path = Images; 211 | sourceTree = ""; 212 | }; 213 | B1C7262515EE822B008C4D05 /* PopoverView */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | B1175C9315E3FC13002FBFF1 /* PopoverView.h */, 217 | 0867719D1689B04F00ED150F /* PopoverView_Configuration.h */, 218 | B1175C9415E3FC13002FBFF1 /* PopoverView.m */, 219 | E7F6CF2A179D542E00C944E3 /* PopoverViewCompatibility.h */, 220 | ); 221 | name = PopoverView; 222 | path = ../PopoverView; 223 | sourceTree = ""; 224 | }; 225 | /* End PBXGroup section */ 226 | 227 | /* Begin PBXNativeTarget section */ 228 | B1175C5415E3FBEE002FBFF1 /* popover */ = { 229 | isa = PBXNativeTarget; 230 | buildConfigurationList = B1175C8B15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popover" */; 231 | buildPhases = ( 232 | B1175C5115E3FBEE002FBFF1 /* Sources */, 233 | B1175C5215E3FBEE002FBFF1 /* Frameworks */, 234 | B1175C5315E3FBEE002FBFF1 /* Resources */, 235 | ); 236 | buildRules = ( 237 | ); 238 | dependencies = ( 239 | ); 240 | name = popover; 241 | productName = popover; 242 | productReference = B1175C5515E3FBEE002FBFF1 /* popover.app */; 243 | productType = "com.apple.product-type.application"; 244 | }; 245 | B1175C7815E3FBEE002FBFF1 /* popoverTests */ = { 246 | isa = PBXNativeTarget; 247 | buildConfigurationList = B1175C8E15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popoverTests" */; 248 | buildPhases = ( 249 | B1175C7415E3FBEE002FBFF1 /* Sources */, 250 | B1175C7515E3FBEE002FBFF1 /* Frameworks */, 251 | B1175C7615E3FBEE002FBFF1 /* Resources */, 252 | B1175C7715E3FBEE002FBFF1 /* ShellScript */, 253 | ); 254 | buildRules = ( 255 | ); 256 | dependencies = ( 257 | B1175C7F15E3FBEE002FBFF1 /* PBXTargetDependency */, 258 | ); 259 | name = popoverTests; 260 | productName = popoverTests; 261 | productReference = B1175C7915E3FBEE002FBFF1 /* popoverTests.octest */; 262 | productType = "com.apple.product-type.bundle"; 263 | }; 264 | /* End PBXNativeTarget section */ 265 | 266 | /* Begin PBXProject section */ 267 | B1175C4C15E3FBEE002FBFF1 /* Project object */ = { 268 | isa = PBXProject; 269 | attributes = { 270 | LastUpgradeCheck = 0440; 271 | ORGANIZATIONNAME = "Oliver Rickard"; 272 | }; 273 | buildConfigurationList = B1175C4F15E3FBEE002FBFF1 /* Build configuration list for PBXProject "popover" */; 274 | compatibilityVersion = "Xcode 3.2"; 275 | developmentRegion = English; 276 | hasScannedForEncodings = 0; 277 | knownRegions = ( 278 | en, 279 | ); 280 | mainGroup = B1175C4A15E3FBEE002FBFF1; 281 | productRefGroup = B1175C5615E3FBEE002FBFF1 /* Products */; 282 | projectDirPath = ""; 283 | projectRoot = ""; 284 | targets = ( 285 | B1175C5415E3FBEE002FBFF1 /* popover */, 286 | B1175C7815E3FBEE002FBFF1 /* popoverTests */, 287 | ); 288 | }; 289 | /* End PBXProject section */ 290 | 291 | /* Begin PBXResourcesBuildPhase section */ 292 | B1175C5315E3FBEE002FBFF1 /* Resources */ = { 293 | isa = PBXResourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | B1175C6415E3FBEE002FBFF1 /* InfoPlist.strings in Resources */, 297 | B1175C6D15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard in Resources */, 298 | B1175C7015E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard in Resources */, 299 | B14F47581603A267003EC4FF /* error.png in Resources */, 300 | B14F47591603A267003EC4FF /* error@2x.png in Resources */, 301 | B14F475A1603A267003EC4FF /* success.png in Resources */, 302 | B14F475B1603A267003EC4FF /* success@2x.png in Resources */, 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | }; 306 | B1175C7615E3FBEE002FBFF1 /* Resources */ = { 307 | isa = PBXResourcesBuildPhase; 308 | buildActionMask = 2147483647; 309 | files = ( 310 | B1175C8515E3FBEE002FBFF1 /* InfoPlist.strings in Resources */, 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | }; 314 | /* End PBXResourcesBuildPhase section */ 315 | 316 | /* Begin PBXShellScriptBuildPhase section */ 317 | B1175C7715E3FBEE002FBFF1 /* ShellScript */ = { 318 | isa = PBXShellScriptBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | ); 322 | inputPaths = ( 323 | ); 324 | outputPaths = ( 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | shellPath = /bin/sh; 328 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 329 | }; 330 | /* End PBXShellScriptBuildPhase section */ 331 | 332 | /* Begin PBXSourcesBuildPhase section */ 333 | B1175C5115E3FBEE002FBFF1 /* Sources */ = { 334 | isa = PBXSourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | B1175C6615E3FBEE002FBFF1 /* main.m in Sources */, 338 | B1175C6A15E3FBEE002FBFF1 /* AppDelegate.m in Sources */, 339 | B1175C7315E3FBEE002FBFF1 /* ViewController.m in Sources */, 340 | B1175C9515E3FC13002FBFF1 /* PopoverView.m in Sources */, 341 | B1ACBE981603859A006F8461 /* OCDaysView.m in Sources */, 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | B1175C7415E3FBEE002FBFF1 /* Sources */ = { 346 | isa = PBXSourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | B1175C8815E3FBEE002FBFF1 /* popoverTests.m in Sources */, 350 | B1175C9615E3FC13002FBFF1 /* PopoverView.m in Sources */, 351 | ); 352 | runOnlyForDeploymentPostprocessing = 0; 353 | }; 354 | /* End PBXSourcesBuildPhase section */ 355 | 356 | /* Begin PBXTargetDependency section */ 357 | B1175C7F15E3FBEE002FBFF1 /* PBXTargetDependency */ = { 358 | isa = PBXTargetDependency; 359 | target = B1175C5415E3FBEE002FBFF1 /* popover */; 360 | targetProxy = B1175C7E15E3FBEE002FBFF1 /* PBXContainerItemProxy */; 361 | }; 362 | /* End PBXTargetDependency section */ 363 | 364 | /* Begin PBXVariantGroup section */ 365 | B1175C6215E3FBEE002FBFF1 /* InfoPlist.strings */ = { 366 | isa = PBXVariantGroup; 367 | children = ( 368 | B1175C6315E3FBEE002FBFF1 /* en */, 369 | ); 370 | name = InfoPlist.strings; 371 | sourceTree = ""; 372 | }; 373 | B1175C6B15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard */ = { 374 | isa = PBXVariantGroup; 375 | children = ( 376 | B1175C6C15E3FBEE002FBFF1 /* en */, 377 | ); 378 | name = MainStoryboard_iPhone.storyboard; 379 | sourceTree = ""; 380 | }; 381 | B1175C6E15E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard */ = { 382 | isa = PBXVariantGroup; 383 | children = ( 384 | B1175C6F15E3FBEE002FBFF1 /* en */, 385 | ); 386 | name = MainStoryboard_iPad.storyboard; 387 | sourceTree = ""; 388 | }; 389 | B1175C8315E3FBEE002FBFF1 /* InfoPlist.strings */ = { 390 | isa = PBXVariantGroup; 391 | children = ( 392 | B1175C8415E3FBEE002FBFF1 /* en */, 393 | ); 394 | name = InfoPlist.strings; 395 | sourceTree = ""; 396 | }; 397 | /* End PBXVariantGroup section */ 398 | 399 | /* Begin XCBuildConfiguration section */ 400 | B1175C8915E3FBEE002FBFF1 /* Debug */ = { 401 | isa = XCBuildConfiguration; 402 | buildSettings = { 403 | ALWAYS_SEARCH_USER_PATHS = NO; 404 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 405 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 406 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 407 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 408 | COPY_PHASE_STRIP = NO; 409 | GCC_C_LANGUAGE_STANDARD = gnu99; 410 | GCC_DYNAMIC_NO_PIC = NO; 411 | GCC_OPTIMIZATION_LEVEL = 0; 412 | GCC_PREPROCESSOR_DEFINITIONS = ( 413 | "DEBUG=1", 414 | "$(inherited)", 415 | ); 416 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 417 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 418 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 419 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 420 | GCC_WARN_UNUSED_VARIABLE = YES; 421 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 422 | SDKROOT = iphoneos; 423 | TARGETED_DEVICE_FAMILY = "1,2"; 424 | }; 425 | name = Debug; 426 | }; 427 | B1175C8A15E3FBEE002FBFF1 /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ALWAYS_SEARCH_USER_PATHS = NO; 431 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 432 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 433 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 434 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 435 | COPY_PHASE_STRIP = YES; 436 | GCC_C_LANGUAGE_STANDARD = gnu99; 437 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 438 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 439 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 440 | GCC_WARN_UNUSED_VARIABLE = YES; 441 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 442 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 443 | SDKROOT = iphoneos; 444 | TARGETED_DEVICE_FAMILY = "1,2"; 445 | VALIDATE_PRODUCT = YES; 446 | }; 447 | name = Release; 448 | }; 449 | B1175C8C15E3FBEE002FBFF1 /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | buildSettings = { 452 | CODE_SIGN_IDENTITY = "iPhone Developer: Oliver Rickard (M2X353B497)"; 453 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Oliver Rickard (M2X353B497)"; 454 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 455 | GCC_PREFIX_HEADER = "popover/Demo/popover-Prefix.pch"; 456 | INFOPLIST_FILE = "popover/Demo/popover-Info.plist"; 457 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | PROVISIONING_PROFILE = "C183E71C-4BA9-4B64-B7E5-BA551FF1F744"; 460 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = "C183E71C-4BA9-4B64-B7E5-BA551FF1F744"; 461 | WRAPPER_EXTENSION = app; 462 | }; 463 | name = Debug; 464 | }; 465 | B1175C8D15E3FBEE002FBFF1 /* Release */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 469 | GCC_PREFIX_HEADER = "popover/Demo/popover-Prefix.pch"; 470 | INFOPLIST_FILE = "popover/Demo/popover-Info.plist"; 471 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 472 | PRODUCT_NAME = "$(TARGET_NAME)"; 473 | WRAPPER_EXTENSION = app; 474 | }; 475 | name = Release; 476 | }; 477 | B1175C8F15E3FBEE002FBFF1 /* Debug */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/popover.app/popover"; 481 | FRAMEWORK_SEARCH_PATHS = ( 482 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 483 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 484 | ); 485 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 486 | GCC_PREFIX_HEADER = "popover/popover-Prefix.pch"; 487 | INFOPLIST_FILE = "popoverTests/popoverTests-Info.plist"; 488 | PRODUCT_NAME = "$(TARGET_NAME)"; 489 | TEST_HOST = "$(BUNDLE_LOADER)"; 490 | WRAPPER_EXTENSION = octest; 491 | }; 492 | name = Debug; 493 | }; 494 | B1175C9015E3FBEE002FBFF1 /* Release */ = { 495 | isa = XCBuildConfiguration; 496 | buildSettings = { 497 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/popover.app/popover"; 498 | FRAMEWORK_SEARCH_PATHS = ( 499 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 500 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 501 | ); 502 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 503 | GCC_PREFIX_HEADER = "popover/popover-Prefix.pch"; 504 | INFOPLIST_FILE = "popoverTests/popoverTests-Info.plist"; 505 | PRODUCT_NAME = "$(TARGET_NAME)"; 506 | TEST_HOST = "$(BUNDLE_LOADER)"; 507 | WRAPPER_EXTENSION = octest; 508 | }; 509 | name = Release; 510 | }; 511 | /* End XCBuildConfiguration section */ 512 | 513 | /* Begin XCConfigurationList section */ 514 | B1175C4F15E3FBEE002FBFF1 /* Build configuration list for PBXProject "popover" */ = { 515 | isa = XCConfigurationList; 516 | buildConfigurations = ( 517 | B1175C8915E3FBEE002FBFF1 /* Debug */, 518 | B1175C8A15E3FBEE002FBFF1 /* Release */, 519 | ); 520 | defaultConfigurationIsVisible = 0; 521 | defaultConfigurationName = Release; 522 | }; 523 | B1175C8B15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popover" */ = { 524 | isa = XCConfigurationList; 525 | buildConfigurations = ( 526 | B1175C8C15E3FBEE002FBFF1 /* Debug */, 527 | B1175C8D15E3FBEE002FBFF1 /* Release */, 528 | ); 529 | defaultConfigurationIsVisible = 0; 530 | defaultConfigurationName = Release; 531 | }; 532 | B1175C8E15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popoverTests" */ = { 533 | isa = XCConfigurationList; 534 | buildConfigurations = ( 535 | B1175C8F15E3FBEE002FBFF1 /* Debug */, 536 | B1175C9015E3FBEE002FBFF1 /* Release */, 537 | ); 538 | defaultConfigurationIsVisible = 0; 539 | defaultConfigurationName = Release; 540 | }; 541 | /* End XCConfigurationList section */ 542 | }; 543 | rootObject = B1175C4C15E3FBEE002FBFF1 /* Project object */; 544 | } 545 | -------------------------------------------------------------------------------- /popover.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /popover.xcodeproj/project.xcworkspace/xcshareddata/popover.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectIdentifier 6 | 81D56861-47C8-4C91-BF6F-591384D37AD7 7 | IDESourceControlProjectName 8 | popover 9 | IDESourceControlProjectOriginsDictionary 10 | 11 | 20888322-FA45-47C8-B767-56F998A37116 12 | https://github.com/cocoa-factory/PopoverView.git 13 | 14 | IDESourceControlProjectPath 15 | popover.xcodeproj/project.xcworkspace 16 | IDESourceControlProjectRelativeInstallPathDictionary 17 | 18 | 20888322-FA45-47C8-B767-56F998A37116 19 | ../.. 20 | 21 | IDESourceControlProjectURL 22 | https://github.com/cocoa-factory/PopoverView.git 23 | IDESourceControlProjectVersion 24 | 110 25 | IDESourceControlProjectWCCIdentifier 26 | 20888322-FA45-47C8-B767-56F998A37116 27 | IDESourceControlProjectWCConfigurations 28 | 29 | 30 | IDESourceControlRepositoryExtensionIdentifierKey 31 | public.vcs.git 32 | IDESourceControlWCCIdentifierKey 33 | 20888322-FA45-47C8-B767-56F998A37116 34 | IDESourceControlWCCName 35 | PopoverView-CCF 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /popover.xcodeproj/project.xcworkspace/xcuserdata/baspellis.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runway20/PopoverView/b542c8660bd448923cfd05e677577238f91d91e4/popover.xcodeproj/project.xcworkspace/xcuserdata/baspellis.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /popover.xcodeproj/project.xcworkspace/xcuserdata/ocrickard.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runway20/PopoverView/b542c8660bd448923cfd05e677577238f91d91e4/popover.xcodeproj/project.xcworkspace/xcuserdata/ocrickard.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /popover.xcodeproj/xcuserdata/alan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | popover.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B1175C5415E3FBEE002FBFF1 16 | 17 | primary 18 | 19 | 20 | B1175C7815E3FBEE002FBFF1 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /popover.xcodeproj/xcuserdata/baspellis.xcuserdatad/xcschemes/popover.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /popover.xcodeproj/xcuserdata/ocrickard.xcuserdatad/xcschemes/popover.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /popover.xcodeproj/xcuserdata/ocrickard.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | popover.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B1175C5415E3FBEE002FBFF1 16 | 17 | primary 18 | 19 | 20 | B1175C7815E3FBEE002FBFF1 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /popover/Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // popover 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /popover/Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // popover 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (void)dealloc 14 | { 15 | [_window release]; 16 | [super dealloc]; 17 | } 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 20 | { 21 | // Override point for customization after application launch. 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application 26 | { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 29 | } 30 | 31 | - (void)applicationDidEnterBackground:(UIApplication *)application 32 | { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | - (void)applicationWillEnterForeground:(UIApplication *)application 38 | { 39 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | - (void)applicationDidBecomeActive:(UIApplication *)application 43 | { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | - (void)applicationWillTerminate:(UIApplication *)application 48 | { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /popover/Demo/Calendar View/OCDaysView.h: -------------------------------------------------------------------------------- 1 | // 2 | // OCDaysView.h 3 | // OCCalendar 4 | // 5 | // Created by Oliver Rickard on 3/30/12. 6 | // Copyright (c) 2012 UC Berkeley. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PopoverViewCompatibility.h" 11 | 12 | @interface OCDaysView : UIView { 13 | int startCellX; 14 | int startCellY; 15 | int endCellX; 16 | int endCellY; 17 | 18 | float xOffset; 19 | float yOffset; 20 | 21 | float hDiff; 22 | float vDiff; 23 | 24 | int currentMonth; 25 | int currentYear; 26 | 27 | BOOL didAddExtraRow; 28 | } 29 | 30 | - (void)setMonth:(int)month; 31 | - (void)setYear:(int)year; 32 | 33 | - (void)resetRows; 34 | 35 | - (BOOL)addExtraRow; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /popover/Demo/Calendar View/OCDaysView.m: -------------------------------------------------------------------------------- 1 | // 2 | // OCDaysView.m 3 | // OCCalendar 4 | // 5 | // Created by Oliver Rickard on 3/30/12. 6 | // Copyright (c) 2012 UC Berkeley. All rights reserved. 7 | // 8 | 9 | #import "OCDaysView.h" 10 | #import 11 | 12 | @implementation OCDaysView 13 | 14 | - (id)initWithFrame:(CGRect)frame 15 | { 16 | self = [super initWithFrame:frame]; 17 | if (self) { 18 | self.userInteractionEnabled = NO; 19 | 20 | startCellX = 3; 21 | startCellY = 0; 22 | endCellX = 3; 23 | endCellY = 0; 24 | 25 | hDiff = floorf(frame.size.width / 7.f); 26 | vDiff = floorf(frame.size.height / 4.f); 27 | 28 | self.backgroundColor = [UIColor clearColor]; 29 | } 30 | return self; 31 | } 32 | 33 | 34 | // Only override drawRect: if you perform custom drawing. 35 | // An empty implementation adversely affects performance during animation. 36 | - (void)drawRect:(CGRect)rect 37 | { 38 | 39 | // CGSize shadow2Offset = CGSizeMake(1, 1); 40 | // CGFloat shadow2BlurRadius = 1; 41 | // CGColorRef shadow2 = [UIColor blackColor].CGColor; 42 | 43 | NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 44 | 45 | int month = currentMonth; 46 | int year = currentYear; 47 | 48 | //Get the first day of the month 49 | NSDateComponents *dateParts = [[NSDateComponents alloc] init]; 50 | [dateParts setMonth:month]; 51 | [dateParts setYear:year]; 52 | [dateParts setDay:1]; 53 | NSDate *dateOnFirst = [calendar dateFromComponents:dateParts]; 54 | [dateParts release]; 55 | NSDateComponents *weekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:dateOnFirst]; 56 | int weekdayOfFirst = [weekdayComponents weekday]; 57 | 58 | //NSLog(@"weekdayOfFirst:%d", weekdayOfFirst); 59 | 60 | int numDaysInMonth = [calendar rangeOfUnit:NSDayCalendarUnit 61 | inUnit:NSMonthCalendarUnit 62 | forDate:dateOnFirst].length; 63 | 64 | //NSLog(@"month:%d, numDaysInMonth:%d", currentMonth, numDaysInMonth); 65 | 66 | CGContextRef context = UIGraphicsGetCurrentContext(); 67 | 68 | didAddExtraRow = NO; 69 | 70 | 71 | 72 | //Find number of days in previous month 73 | NSDateComponents *prevDateParts = [[NSDateComponents alloc] init]; 74 | [prevDateParts setMonth:month-1]; 75 | [prevDateParts setYear:year]; 76 | [prevDateParts setDay:1]; 77 | 78 | NSDate *prevDateOnFirst = [calendar dateFromComponents:prevDateParts]; 79 | 80 | [prevDateParts release]; 81 | 82 | int numDaysInPrevMonth = [calendar rangeOfUnit:NSDayCalendarUnit 83 | inUnit:NSMonthCalendarUnit 84 | forDate:prevDateOnFirst].length; 85 | 86 | NSDateComponents *today = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:[NSDate date]]; 87 | 88 | //Draw the text for each of those days. 89 | for(int i = 0; i <= weekdayOfFirst-2; i++) { 90 | int day = numDaysInPrevMonth - weekdayOfFirst + 2 + i; 91 | 92 | NSString *str = [NSString stringWithFormat:@"%d", day]; 93 | 94 | 95 | 96 | CGContextSaveGState(context); 97 | // CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2); 98 | CGRect dayHeader2Frame = CGRectMake((i)*hDiff, 0, 21, 14); 99 | [[UIColor colorWithWhite:0.6f alpha:1.0f] setFill]; 100 | [str drawInRect: dayHeader2Frame withFont: [UIFont fontWithName: @"Helvetica" size: 12] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter]; 101 | CGContextRestoreGState(context); 102 | } 103 | 104 | 105 | BOOL endedOnSat = NO; 106 | int finalRow = 0; 107 | int day = 1; 108 | for (int i = 0; i < 6; i++) { 109 | for(int j = 0; j < 7; j++) { 110 | int dayNumber = i * 7 + j; 111 | 112 | if(dayNumber >= (weekdayOfFirst-1) && day <= numDaysInMonth) { 113 | NSString *str = [NSString stringWithFormat:@"%d", day]; 114 | 115 | CGContextSaveGState(context); 116 | // CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2); 117 | CGRect dayHeader2Frame = CGRectMake(j*hDiff, i*vDiff, 21, 14); 118 | if([today day] == day && [today month] == month && [today year] == year) { 119 | [[UIColor colorWithRed: 0.98 green: 0.24 blue: 0.09 alpha: 1] setFill]; 120 | } else { 121 | [[UIColor colorWithWhite:0.2f alpha:1.f] setFill]; 122 | } 123 | [str drawInRect: dayHeader2Frame withFont: [UIFont fontWithName: @"Helvetica" size: 12] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter]; 124 | CGContextRestoreGState(context); 125 | 126 | finalRow = i; 127 | 128 | if(day == numDaysInMonth && j == 6) { 129 | endedOnSat = YES; 130 | } 131 | 132 | if(i == 5) { 133 | didAddExtraRow = YES; 134 | //NSLog(@"didAddExtraRow"); 135 | } 136 | 137 | ++day; 138 | } 139 | } 140 | } 141 | 142 | //Find number of days in previous month 143 | NSDateComponents *nextDateParts = [[NSDateComponents alloc] init]; 144 | [nextDateParts setMonth:month+1]; 145 | [nextDateParts setYear:year]; 146 | [nextDateParts setDay:1]; 147 | 148 | NSDate *nextDateOnFirst = [calendar dateFromComponents:nextDateParts]; 149 | 150 | [nextDateParts release]; 151 | 152 | NSDateComponents *nextWeekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:nextDateOnFirst]; 153 | int weekdayOfNextFirst = [nextWeekdayComponents weekday]; 154 | 155 | if(!endedOnSat) { 156 | //Draw the text for each of those days. 157 | for(int i = weekdayOfNextFirst - 1; i < 7; i++) { 158 | int day = i - weekdayOfNextFirst + 2; 159 | 160 | NSString *str = [NSString stringWithFormat:@"%d", day]; 161 | 162 | CGContextSaveGState(context); 163 | // CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2); 164 | CGRect dayHeader2Frame = CGRectMake((i)*hDiff, finalRow * vDiff, 21, 14); 165 | [[UIColor colorWithWhite:0.6f alpha:1.0f] setFill]; 166 | [str drawInRect: dayHeader2Frame withFont: [UIFont fontWithName: @"Helvetica" size: 12] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter]; 167 | CGContextRestoreGState(context); 168 | } 169 | } 170 | } 171 | 172 | - (void)setMonth:(int)month { 173 | currentMonth = month; 174 | [self setNeedsDisplay]; 175 | } 176 | 177 | - (void)setYear:(int)year { 178 | currentYear = year; 179 | [self setNeedsDisplay]; 180 | } 181 | 182 | - (void)resetRows { 183 | NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 184 | 185 | int month = currentMonth; 186 | int year = currentYear; 187 | 188 | //Get the first day of the month 189 | NSDateComponents *dateParts = [[NSDateComponents alloc] init]; 190 | [dateParts setMonth:month]; 191 | [dateParts setYear:year]; 192 | [dateParts setDay:1]; 193 | NSDate *dateOnFirst = [calendar dateFromComponents:dateParts]; 194 | [dateParts release]; 195 | NSDateComponents *weekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:dateOnFirst]; 196 | int weekdayOfFirst = [weekdayComponents weekday]; 197 | 198 | int numDaysInMonth = [calendar rangeOfUnit:NSDayCalendarUnit 199 | inUnit:NSMonthCalendarUnit 200 | forDate:dateOnFirst].length; 201 | didAddExtraRow = NO; 202 | 203 | int day = 1; 204 | for (int i = 0; i < 6; i++) { 205 | for(int j = 0; j < 7; j++) { 206 | int dayNumber = i * 7 + j; 207 | if(dayNumber >= (weekdayOfFirst - 1) && day <= numDaysInMonth) { 208 | if(i == 5) { 209 | didAddExtraRow = YES; 210 | //NSLog(@"didAddExtraRow"); 211 | } 212 | ++day; 213 | } 214 | } 215 | } 216 | } 217 | 218 | - (BOOL)addExtraRow { 219 | return didAddExtraRow; 220 | } 221 | 222 | 223 | @end 224 | -------------------------------------------------------------------------------- /popover/Demo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // popover 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PopoverView.h" 11 | 12 | @interface ViewController : UIViewController 13 | { 14 | PopoverView *pv; 15 | 16 | UILabel *tapAnywhereLabel; 17 | CGPoint point; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /popover/Demo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // popover 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "PopoverView.h" 11 | #import "OCDaysView.h" 12 | #import //This is just for the daysView where I call "daysView.layer" not necessary normally. 13 | 14 | #define kStringArray [NSArray arrayWithObjects:@"YES", @"NO", nil] 15 | #define kImageArray [NSArray arrayWithObjects:[UIImage imageNamed:@"success"], [UIImage imageNamed:@"error"], nil] 16 | 17 | @interface ViewController () 18 | 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | #pragma mark - Setup Methods 24 | 25 | - (void)viewDidLoad 26 | { 27 | [super viewDidLoad]; 28 | // Do any additional setup after loading the view, typically from a nib. 29 | 30 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; 31 | [self.view addGestureRecognizer:[tap autorelease]]; 32 | 33 | // Create a label centered on the screen 34 | tapAnywhereLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 30)]; 35 | tapAnywhereLabel.center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)); 36 | tapAnywhereLabel.text = @"Tap Anywhere"; 37 | tapAnywhereLabel.textAlignment = UITextAlignmentCenter; 38 | [self.view addSubview:[tapAnywhereLabel autorelease]]; 39 | } 40 | 41 | #pragma mark - User Interaction Methods 42 | 43 | #pragma mark EXAMPLE CODE IS HERE 44 | 45 | - (void)tapped:(UITapGestureRecognizer *)tap 46 | { 47 | point = [tap locationInView:self.view]; 48 | //NSLog(@"tapped at %@", NSStringFromCGPoint(point)); 49 | 50 | // Here are a couple of different options for how to display the Popover 51 | 52 | // pv = [PopoverView showPopoverAtPoint:point 53 | // inView:self.view 54 | // withText:@"This is a very long popover box. As you can see, it goes to multiple lines in size." delegate:self]; // Show text wrapping popover with long string 55 | 56 | // pv = [PopoverView showPopoverAtPoint:point 57 | // inView:self.view 58 | // withTitle:@"This is a title" 59 | // withText:@"This is text" 60 | // delegate:self]; // Show text with title 61 | 62 | // pv = [PopoverView showPopoverAtPoint:point 63 | // inView:self.view 64 | // withStringArray:kStringArray 65 | // delegate:self]; // Show the string array defined at top of this file 66 | 67 | pv = [PopoverView showPopoverAtPoint:point 68 | inView:self.view 69 | withTitle:@"Was this helpful?" 70 | withStringArray:kStringArray 71 | delegate:self]; // Show string array defined at top of this file with title. 72 | 73 | // pv = [PopoverView showPopoverAtPoint:point 74 | // inView:self.view 75 | // withStringArray:kStringArray 76 | // withImageArray:kImageArray 77 | // delegate:self]; 78 | 79 | // pv = [PopoverView showPopoverAtPoint:point 80 | // inView:self.view 81 | // withTitle:@"DEBUG" 82 | // withStringArray:kStringArray 83 | // withImageArray:kImageArray 84 | // delegate:self]; 85 | 86 | // // Here's a little bit more advanced sample. I create a custom view, and hand it off to the PopoverView to display for me. I round the corners 87 | // OCDaysView *daysView = [[OCDaysView alloc] initWithFrame:CGRectMake(0, 0, 150, 100)]; 88 | // [daysView setMonth:10]; 89 | // [daysView setYear:2012]; 90 | // daysView.backgroundColor = [UIColor colorWithWhite:0.95f alpha:1.f]; //Give it a background color 91 | // daysView.layer.borderColor = [UIColor colorWithWhite:0.9f alpha:1.f].CGColor; //Add a border 92 | // daysView.layer.borderWidth = 0.5f; //One retina pixel width 93 | // daysView.layer.cornerRadius = 4.f; 94 | // daysView.layer.masksToBounds = YES; 95 | // 96 | // pv = [PopoverView showPopoverAtPoint:point 97 | // inView:self.view 98 | // withContentView:[daysView autorelease] 99 | // delegate:self]; // Show calendar with no title 100 | // pv = [PopoverView showPopoverAtPoint:point 101 | // inView:self.view 102 | // withTitle:@"October 2012" 103 | // withContentView:[daysView autorelease] 104 | // delegate:self]; // Show calendar with title 105 | 106 | // UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 107 | // tableView.delegate = self; 108 | // tableView.dataSource = self; 109 | // pv = [PopoverView showPopoverAtPoint:point 110 | // inView:self.view 111 | // withContentView:tableView 112 | // delegate:self]; 113 | [pv retain]; 114 | } 115 | 116 | #pragma mark - DEMO - UITableView Delegate Methods 117 | 118 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 119 | { 120 | return 10; 121 | } 122 | 123 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 124 | { 125 | return 25; 126 | } 127 | 128 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 129 | { 130 | UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; 131 | cell.textLabel.text = @"text"; 132 | cell.textLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12.f]; 133 | 134 | return [cell autorelease]; 135 | } 136 | 137 | #pragma mark - PopoverViewDelegate Methods 138 | 139 | - (void)popoverView:(PopoverView *)popoverView didSelectItemAtIndex:(NSInteger)index 140 | { 141 | NSLog(@"%s item:%d", __PRETTY_FUNCTION__, index); 142 | 143 | // Figure out which string was selected, store in "string" 144 | NSString *string = [kStringArray objectAtIndex:index]; 145 | 146 | // Show a success image, with the string from the array 147 | [popoverView showImage:[UIImage imageNamed:@"success"] withMessage:string]; 148 | 149 | // alternatively, you can use 150 | // [popoverView showSuccess]; 151 | // or 152 | // [popoverView showError]; 153 | 154 | // Dismiss the PopoverView after 0.5 seconds 155 | [popoverView performSelector:@selector(dismiss) withObject:nil afterDelay:0.5f]; 156 | } 157 | 158 | - (void)popoverViewDidDismiss:(PopoverView *)popoverView 159 | { 160 | NSLog(@"%s", __PRETTY_FUNCTION__); 161 | [pv release], pv = nil; 162 | } 163 | 164 | #pragma mark - UIViewController Methods 165 | 166 | - (void)viewDidUnload 167 | { 168 | [super viewDidUnload]; 169 | [pv release], pv = nil; 170 | } 171 | 172 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 173 | { 174 | return UIInterfaceOrientationIsLandscape(interfaceOrientation); 175 | // or, depending on the app setup, one of 176 | // return UIInterfaceOrientationIsPortrait(interfaceOrientation); 177 | // return YES; 178 | } 179 | 180 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 181 | { 182 | // get new center coords 183 | CGPoint center = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)); 184 | 185 | // move label's center 186 | tapAnywhereLabel.center = center; 187 | 188 | if (pv) { 189 | // popover is visible, so we need to either reposition or dismiss it (dismising is probably best to avoid confusion) 190 | bool dismiss = YES; 191 | if (dismiss) { 192 | [pv dismiss:NO]; 193 | } 194 | else { 195 | // move popover 196 | [pv animateRotationToNewPoint:center 197 | inView:self.view 198 | withDuration:duration]; 199 | } 200 | } 201 | } 202 | 203 | @end 204 | -------------------------------------------------------------------------------- /popover/Demo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /popover/Demo/en.lproj/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /popover/Demo/en.lproj/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /popover/Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // popover 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. 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 | -------------------------------------------------------------------------------- /popover/Demo/popover-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.runway20.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard_iPhone 29 | UIMainStoryboardFile~ipad 30 | MainStoryboard_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationLandscapeLeft 38 | UIInterfaceOrientationLandscapeRight 39 | 40 | UISupportedInterfaceOrientations~ipad 41 | 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /popover/Demo/popover-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'popover' target in the 'popover' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /popover/Images/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runway20/PopoverView/b542c8660bd448923cfd05e677577238f91d91e4/popover/Images/error.png -------------------------------------------------------------------------------- /popover/Images/error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runway20/PopoverView/b542c8660bd448923cfd05e677577238f91d91e4/popover/Images/error@2x.png -------------------------------------------------------------------------------- /popover/Images/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runway20/PopoverView/b542c8660bd448923cfd05e677577238f91d91e4/popover/Images/success.png -------------------------------------------------------------------------------- /popover/Images/success@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runway20/PopoverView/b542c8660bd448923cfd05e677577238f91d91e4/popover/Images/success@2x.png -------------------------------------------------------------------------------- /popoverTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /popoverTests/popoverTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.runway20.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /popoverTests/popoverTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // popoverTests.h 3 | // popoverTests 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface popoverTests : SenTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /popoverTests/popoverTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // popoverTests.m 3 | // popoverTests 4 | // 5 | // Created by Oliver Rickard on 21/08/2012. 6 | // Copyright (c) 2012 Oliver Rickard. All rights reserved. 7 | // 8 | 9 | #import "popoverTests.h" 10 | 11 | @implementation popoverTests 12 | 13 | - (void)setUp 14 | { 15 | [super setUp]; 16 | 17 | // Set-up code here. 18 | } 19 | 20 | - (void)tearDown 21 | { 22 | // Tear-down code here. 23 | 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample 28 | { 29 | STFail(@"Unit tests are not implemented yet in popoverTests"); 30 | } 31 | 32 | @end 33 | --------------------------------------------------------------------------------