Permalink
Browse files

For real this time, last commit

Fixed layouting code, cleaned up demo project and organized into
folders.  Added several more convenience methods, corrected padding
around contentViews.  Added the daysView as a demo of what the view can
do
  • Loading branch information...
1 parent 86ba852 commit af71bb0af69d8063473027b8b23720c8519d0cf3 Oliver Rickard committed Sep 14, 2012
View
1 .gitignore
@@ -0,0 +1 @@
+build/
View
535 popover.xcodeproj/project.pbxproj
@@ -0,0 +1,535 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ B1175C5A15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5915E3FBEE002FBFF1 /* UIKit.framework */; };
+ B1175C5C15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */; };
+ B1175C5E15E3FBEE002FBFF1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5D15E3FBEE002FBFF1 /* CoreGraphics.framework */; };
+ B1175C6415E3FBEE002FBFF1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1175C6215E3FBEE002FBFF1 /* InfoPlist.strings */; };
+ B1175C6615E3FBEE002FBFF1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C6515E3FBEE002FBFF1 /* main.m */; };
+ B1175C6A15E3FBEE002FBFF1 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C6915E3FBEE002FBFF1 /* AppDelegate.m */; };
+ B1175C6D15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1175C6B15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard */; };
+ B1175C7015E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B1175C6E15E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard */; };
+ B1175C7315E3FBEE002FBFF1 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C7215E3FBEE002FBFF1 /* ViewController.m */; };
+ B1175C7B15E3FBEE002FBFF1 /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C7A15E3FBEE002FBFF1 /* SenTestingKit.framework */; };
+ B1175C7C15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5915E3FBEE002FBFF1 /* UIKit.framework */; };
+ B1175C7D15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */; };
+ B1175C8515E3FBEE002FBFF1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1175C8315E3FBEE002FBFF1 /* InfoPlist.strings */; };
+ B1175C8815E3FBEE002FBFF1 /* popoverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C8715E3FBEE002FBFF1 /* popoverTests.m */; };
+ B1175C9215E3FC07002FBFF1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1175C9115E3FC07002FBFF1 /* QuartzCore.framework */; };
+ B1175C9515E3FC13002FBFF1 /* PopoverView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C9415E3FC13002FBFF1 /* PopoverView.m */; };
+ B1175C9615E3FC13002FBFF1 /* PopoverView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1175C9415E3FC13002FBFF1 /* PopoverView.m */; };
+ B14F47581603A267003EC4FF /* error.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47541603A267003EC4FF /* error.png */; };
+ B14F47591603A267003EC4FF /* error@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47551603A267003EC4FF /* error@2x.png */; };
+ B14F475A1603A267003EC4FF /* success.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47561603A267003EC4FF /* success.png */; };
+ B14F475B1603A267003EC4FF /* success@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B14F47571603A267003EC4FF /* success@2x.png */; };
+ B1ACBE981603859A006F8461 /* OCDaysView.m in Sources */ = {isa = PBXBuildFile; fileRef = B1ACBE971603859A006F8461 /* OCDaysView.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ B1175C7E15E3FBEE002FBFF1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = B1175C4C15E3FBEE002FBFF1 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B1175C5415E3FBEE002FBFF1;
+ remoteInfo = popover;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ B1175C5515E3FBEE002FBFF1 /* popover.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = popover.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ B1175C5915E3FBEE002FBFF1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ B1175C5D15E3FBEE002FBFF1 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ B1175C6115E3FBEE002FBFF1 /* popover-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "popover-Info.plist"; sourceTree = "<group>"; };
+ B1175C6315E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ B1175C6515E3FBEE002FBFF1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ B1175C6715E3FBEE002FBFF1 /* popover-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "popover-Prefix.pch"; sourceTree = "<group>"; };
+ B1175C6815E3FBEE002FBFF1 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ B1175C6915E3FBEE002FBFF1 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ B1175C6C15E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPhone.storyboard; sourceTree = "<group>"; };
+ B1175C6F15E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard_iPad.storyboard; sourceTree = "<group>"; };
+ B1175C7115E3FBEE002FBFF1 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ B1175C7215E3FBEE002FBFF1 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ B1175C7915E3FBEE002FBFF1 /* popoverTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = popoverTests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
+ B1175C7A15E3FBEE002FBFF1 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
+ B1175C8215E3FBEE002FBFF1 /* popoverTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "popoverTests-Info.plist"; sourceTree = "<group>"; };
+ B1175C8415E3FBEE002FBFF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ B1175C8615E3FBEE002FBFF1 /* popoverTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = popoverTests.h; sourceTree = "<group>"; };
+ B1175C8715E3FBEE002FBFF1 /* popoverTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = popoverTests.m; sourceTree = "<group>"; };
+ B1175C9115E3FC07002FBFF1 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ B1175C9315E3FC13002FBFF1 /* PopoverView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PopoverView.h; sourceTree = "<group>"; };
+ B1175C9415E3FC13002FBFF1 /* PopoverView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PopoverView.m; sourceTree = "<group>"; };
+ B14F47541603A267003EC4FF /* error.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = error.png; path = popover/Images/error.png; sourceTree = SOURCE_ROOT; };
+ B14F47551603A267003EC4FF /* error@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "error@2x.png"; path = "popover/Images/error@2x.png"; sourceTree = SOURCE_ROOT; };
+ B14F47561603A267003EC4FF /* success.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = success.png; path = popover/Images/success.png; sourceTree = SOURCE_ROOT; };
+ B14F47571603A267003EC4FF /* success@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "success@2x.png"; path = "popover/Images/success@2x.png"; sourceTree = SOURCE_ROOT; };
+ B1ACBE961603859A006F8461 /* OCDaysView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCDaysView.h; sourceTree = "<group>"; };
+ B1ACBE971603859A006F8461 /* OCDaysView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCDaysView.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ B1175C5215E3FBEE002FBFF1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1175C9215E3FC07002FBFF1 /* QuartzCore.framework in Frameworks */,
+ B1175C5A15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */,
+ B1175C5C15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */,
+ B1175C5E15E3FBEE002FBFF1 /* CoreGraphics.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B1175C7515E3FBEE002FBFF1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1175C7B15E3FBEE002FBFF1 /* SenTestingKit.framework in Frameworks */,
+ B1175C7C15E3FBEE002FBFF1 /* UIKit.framework in Frameworks */,
+ B1175C7D15E3FBEE002FBFF1 /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ B1175C4A15E3FBEE002FBFF1 = {
+ isa = PBXGroup;
+ children = (
+ B1175C9115E3FC07002FBFF1 /* QuartzCore.framework */,
+ B1175C5F15E3FBEE002FBFF1 /* popover */,
+ B1175C8015E3FBEE002FBFF1 /* popoverTests */,
+ B1175C5815E3FBEE002FBFF1 /* Frameworks */,
+ B1175C5615E3FBEE002FBFF1 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ B1175C5615E3FBEE002FBFF1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ B1175C5515E3FBEE002FBFF1 /* popover.app */,
+ B1175C7915E3FBEE002FBFF1 /* popoverTests.octest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ B1175C5815E3FBEE002FBFF1 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ B1175C5915E3FBEE002FBFF1 /* UIKit.framework */,
+ B1175C5B15E3FBEE002FBFF1 /* Foundation.framework */,
+ B1175C5D15E3FBEE002FBFF1 /* CoreGraphics.framework */,
+ B1175C7A15E3FBEE002FBFF1 /* SenTestingKit.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ B1175C5F15E3FBEE002FBFF1 /* popover */ = {
+ isa = PBXGroup;
+ children = (
+ B1ACBE941603858D006F8461 /* Demo Calendar View - Not Important */,
+ B1C7262515EE822B008C4D05 /* PopoverView */,
+ B1ACBE991603A040006F8461 /* Demo */,
+ B1175C6015E3FBEE002FBFF1 /* Supporting Files */,
+ );
+ path = popover;
+ sourceTree = "<group>";
+ };
+ B1175C6015E3FBEE002FBFF1 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ B1C7262415EE8222008C4D05 /* Images */,
+ B1175C6115E3FBEE002FBFF1 /* popover-Info.plist */,
+ B1175C6515E3FBEE002FBFF1 /* main.m */,
+ B1175C6715E3FBEE002FBFF1 /* popover-Prefix.pch */,
+ B1175C6215E3FBEE002FBFF1 /* InfoPlist.strings */,
+ );
+ name = "Supporting Files";
+ path = Demo;
+ sourceTree = "<group>";
+ };
+ B1175C8015E3FBEE002FBFF1 /* popoverTests */ = {
+ isa = PBXGroup;
+ children = (
+ B1175C8615E3FBEE002FBFF1 /* popoverTests.h */,
+ B1175C8715E3FBEE002FBFF1 /* popoverTests.m */,
+ B1175C8115E3FBEE002FBFF1 /* Supporting Files */,
+ );
+ path = popoverTests;
+ sourceTree = "<group>";
+ };
+ B1175C8115E3FBEE002FBFF1 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ B1175C8215E3FBEE002FBFF1 /* popoverTests-Info.plist */,
+ B1175C8315E3FBEE002FBFF1 /* InfoPlist.strings */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ B1ACBE941603858D006F8461 /* Demo Calendar View - Not Important */ = {
+ isa = PBXGroup;
+ children = (
+ B1ACBE961603859A006F8461 /* OCDaysView.h */,
+ B1ACBE971603859A006F8461 /* OCDaysView.m */,
+ );
+ name = "Demo Calendar View - Not Important";
+ path = "Demo/Calendar View";
+ sourceTree = "<group>";
+ };
+ B1ACBE991603A040006F8461 /* Demo */ = {
+ isa = PBXGroup;
+ children = (
+ B1175C6815E3FBEE002FBFF1 /* AppDelegate.h */,
+ B1175C6915E3FBEE002FBFF1 /* AppDelegate.m */,
+ B1175C6B15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard */,
+ B1175C6E15E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard */,
+ B1175C7115E3FBEE002FBFF1 /* ViewController.h */,
+ B1175C7215E3FBEE002FBFF1 /* ViewController.m */,
+ );
+ path = Demo;
+ sourceTree = "<group>";
+ };
+ B1C7262415EE8222008C4D05 /* Images */ = {
+ isa = PBXGroup;
+ children = (
+ B14F47541603A267003EC4FF /* error.png */,
+ B14F47551603A267003EC4FF /* error@2x.png */,
+ B14F47561603A267003EC4FF /* success.png */,
+ B14F47571603A267003EC4FF /* success@2x.png */,
+ );
+ path = Images;
+ sourceTree = "<group>";
+ };
+ B1C7262515EE822B008C4D05 /* PopoverView */ = {
+ isa = PBXGroup;
+ children = (
+ B1175C9315E3FC13002FBFF1 /* PopoverView.h */,
+ B1175C9415E3FC13002FBFF1 /* PopoverView.m */,
+ );
+ name = PopoverView;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ B1175C5415E3FBEE002FBFF1 /* popover */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B1175C8B15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popover" */;
+ buildPhases = (
+ B1175C5115E3FBEE002FBFF1 /* Sources */,
+ B1175C5215E3FBEE002FBFF1 /* Frameworks */,
+ B1175C5315E3FBEE002FBFF1 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = popover;
+ productName = popover;
+ productReference = B1175C5515E3FBEE002FBFF1 /* popover.app */;
+ productType = "com.apple.product-type.application";
+ };
+ B1175C7815E3FBEE002FBFF1 /* popoverTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B1175C8E15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popoverTests" */;
+ buildPhases = (
+ B1175C7415E3FBEE002FBFF1 /* Sources */,
+ B1175C7515E3FBEE002FBFF1 /* Frameworks */,
+ B1175C7615E3FBEE002FBFF1 /* Resources */,
+ B1175C7715E3FBEE002FBFF1 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ B1175C7F15E3FBEE002FBFF1 /* PBXTargetDependency */,
+ );
+ name = popoverTests;
+ productName = popoverTests;
+ productReference = B1175C7915E3FBEE002FBFF1 /* popoverTests.octest */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ B1175C4C15E3FBEE002FBFF1 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0440;
+ ORGANIZATIONNAME = "Oliver Rickard";
+ };
+ buildConfigurationList = B1175C4F15E3FBEE002FBFF1 /* Build configuration list for PBXProject "popover" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = B1175C4A15E3FBEE002FBFF1;
+ productRefGroup = B1175C5615E3FBEE002FBFF1 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ B1175C5415E3FBEE002FBFF1 /* popover */,
+ B1175C7815E3FBEE002FBFF1 /* popoverTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ B1175C5315E3FBEE002FBFF1 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1175C6415E3FBEE002FBFF1 /* InfoPlist.strings in Resources */,
+ B1175C6D15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard in Resources */,
+ B1175C7015E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard in Resources */,
+ B14F47581603A267003EC4FF /* error.png in Resources */,
+ B14F47591603A267003EC4FF /* error@2x.png in Resources */,
+ B14F475A1603A267003EC4FF /* success.png in Resources */,
+ B14F475B1603A267003EC4FF /* success@2x.png in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B1175C7615E3FBEE002FBFF1 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1175C8515E3FBEE002FBFF1 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ B1175C7715E3FBEE002FBFF1 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ B1175C5115E3FBEE002FBFF1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1175C6615E3FBEE002FBFF1 /* main.m in Sources */,
+ B1175C6A15E3FBEE002FBFF1 /* AppDelegate.m in Sources */,
+ B1175C7315E3FBEE002FBFF1 /* ViewController.m in Sources */,
+ B1175C9515E3FC13002FBFF1 /* PopoverView.m in Sources */,
+ B1ACBE981603859A006F8461 /* OCDaysView.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B1175C7415E3FBEE002FBFF1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B1175C8815E3FBEE002FBFF1 /* popoverTests.m in Sources */,
+ B1175C9615E3FC13002FBFF1 /* PopoverView.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ B1175C7F15E3FBEE002FBFF1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B1175C5415E3FBEE002FBFF1 /* popover */;
+ targetProxy = B1175C7E15E3FBEE002FBFF1 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ B1175C6215E3FBEE002FBFF1 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ B1175C6315E3FBEE002FBFF1 /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ B1175C6B15E3FBEE002FBFF1 /* MainStoryboard_iPhone.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ B1175C6C15E3FBEE002FBFF1 /* en */,
+ );
+ name = MainStoryboard_iPhone.storyboard;
+ sourceTree = "<group>";
+ };
+ B1175C6E15E3FBEE002FBFF1 /* MainStoryboard_iPad.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ B1175C6F15E3FBEE002FBFF1 /* en */,
+ );
+ name = MainStoryboard_iPad.storyboard;
+ sourceTree = "<group>";
+ };
+ B1175C8315E3FBEE002FBFF1 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ B1175C8415E3FBEE002FBFF1 /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ B1175C8915E3FBEE002FBFF1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ B1175C8A15E3FBEE002FBFF1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ B1175C8C15E3FBEE002FBFF1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_IDENTITY = "iPhone Developer: Oliver Rickard (M2X353B497)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Oliver Rickard (M2X353B497)";
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "popover/Demo/popover-Prefix.pch";
+ INFOPLIST_FILE = "popover/Demo/popover-Info.plist";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "C183E71C-4BA9-4B64-B7E5-BA551FF1F744";
+ "PROVISIONING_PROFILE[sdk=iphoneos*]" = "C183E71C-4BA9-4B64-B7E5-BA551FF1F744";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ B1175C8D15E3FBEE002FBFF1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "popover/Demo/popover-Prefix.pch";
+ INFOPLIST_FILE = "popover/Demo/popover-Info.plist";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+ B1175C8F15E3FBEE002FBFF1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/popover.app/popover";
+ FRAMEWORK_SEARCH_PATHS = (
+ "\"$(SDKROOT)/Developer/Library/Frameworks\"",
+ "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
+ );
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "popover/popover-Prefix.pch";
+ INFOPLIST_FILE = "popoverTests/popoverTests-Info.plist";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUNDLE_LOADER)";
+ WRAPPER_EXTENSION = octest;
+ };
+ name = Debug;
+ };
+ B1175C9015E3FBEE002FBFF1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/popover.app/popover";
+ FRAMEWORK_SEARCH_PATHS = (
+ "\"$(SDKROOT)/Developer/Library/Frameworks\"",
+ "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"",
+ );
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "popover/popover-Prefix.pch";
+ INFOPLIST_FILE = "popoverTests/popoverTests-Info.plist";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUNDLE_LOADER)";
+ WRAPPER_EXTENSION = octest;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ B1175C4F15E3FBEE002FBFF1 /* Build configuration list for PBXProject "popover" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B1175C8915E3FBEE002FBFF1 /* Debug */,
+ B1175C8A15E3FBEE002FBFF1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B1175C8B15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popover" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B1175C8C15E3FBEE002FBFF1 /* Debug */,
+ B1175C8D15E3FBEE002FBFF1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B1175C8E15E3FBEE002FBFF1 /* Build configuration list for PBXNativeTarget "popoverTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B1175C8F15E3FBEE002FBFF1 /* Debug */,
+ B1175C9015E3FBEE002FBFF1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = B1175C4C15E3FBEE002FBFF1 /* Project object */;
+}
View
7 popover.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:popover.xcodeproj">
+ </FileRef>
+</Workspace>
View
BIN ...eproj/project.xcworkspace/xcuserdata/ocrickard.xcuserdatad/UserInterfaceState.xcuserstate
Binary file not shown.
View
96 popover.xcodeproj/xcuserdata/ocrickard.xcuserdatad/xcschemes/popover.xcscheme
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0440"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "B1175C5415E3FBEE002FBFF1"
+ BuildableName = "popover.app"
+ BlueprintName = "popover"
+ ReferencedContainer = "container:popover.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Debug">
+ <Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "B1175C7815E3FBEE002FBFF1"
+ BuildableName = "popoverTests.octest"
+ BlueprintName = "popoverTests"
+ ReferencedContainer = "container:popover.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "B1175C5415E3FBEE002FBFF1"
+ BuildableName = "popover.app"
+ BlueprintName = "popover"
+ ReferencedContainer = "container:popover.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Debug"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "B1175C5415E3FBEE002FBFF1"
+ BuildableName = "popover.app"
+ BlueprintName = "popover"
+ ReferencedContainer = "container:popover.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "B1175C5415E3FBEE002FBFF1"
+ BuildableName = "popover.app"
+ BlueprintName = "popover"
+ ReferencedContainer = "container:popover.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
View
27 popover.xcodeproj/xcuserdata/ocrickard.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>SchemeUserState</key>
+ <dict>
+ <key>popover.xcscheme</key>
+ <dict>
+ <key>orderHint</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <key>SuppressBuildableAutocreation</key>
+ <dict>
+ <key>B1175C5415E3FBEE002FBFF1</key>
+ <dict>
+ <key>primary</key>
+ <true/>
+ </dict>
+ <key>B1175C7815E3FBEE002FBFF1</key>
+ <dict>
+ <key>primary</key>
+ <true/>
+ </dict>
+ </dict>
+</dict>
+</plist>
View
15 popover/Demo/AppDelegate.h
@@ -0,0 +1,15 @@
+//
+// AppDelegate.h
+// popover
+//
+// Created by Oliver Rickard on 21/08/2012.
+// Copyright (c) 2012 Oliver Rickard. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
View
52 popover/Demo/AppDelegate.m
@@ -0,0 +1,52 @@
+//
+// AppDelegate.m
+// popover
+//
+// Created by Oliver Rickard on 21/08/2012.
+// Copyright (c) 2012 Oliver Rickard. All rights reserved.
+//
+
+#import "AppDelegate.h"
+
+@implementation AppDelegate
+
+- (void)dealloc
+{
+ [_window release];
+ [super dealloc];
+}
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ // Override point for customization after application launch.
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ // 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.
+ // 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.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+ // 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.
+ // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application
+{
+ // 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.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ // 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.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+@end
View
36 popover/Demo/Calendar View/OCDaysView.h
@@ -0,0 +1,36 @@
+//
+// OCDaysView.h
+// OCCalendar
+//
+// Created by Oliver Rickard on 3/30/12.
+// Copyright (c) 2012 UC Berkeley. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface OCDaysView : UIView {
+ int startCellX;
+ int startCellY;
+ int endCellX;
+ int endCellY;
+
+ float xOffset;
+ float yOffset;
+
+ float hDiff;
+ float vDiff;
+
+ int currentMonth;
+ int currentYear;
+
+ BOOL didAddExtraRow;
+}
+
+- (void)setMonth:(int)month;
+- (void)setYear:(int)year;
+
+- (void)resetRows;
+
+- (BOOL)addExtraRow;
+
+@end
View
223 popover/Demo/Calendar View/OCDaysView.m
@@ -0,0 +1,223 @@
+//
+// OCDaysView.m
+// OCCalendar
+//
+// Created by Oliver Rickard on 3/30/12.
+// Copyright (c) 2012 UC Berkeley. All rights reserved.
+//
+
+#import "OCDaysView.h"
+#import <QuartzCore/QuartzCore.h>
+
+@implementation OCDaysView
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self) {
+ self.userInteractionEnabled = NO;
+
+ startCellX = 3;
+ startCellY = 0;
+ endCellX = 3;
+ endCellY = 0;
+
+ hDiff = floorf(frame.size.width / 7.f);
+ vDiff = floorf(frame.size.height / 4.f);
+
+ self.backgroundColor = [UIColor clearColor];
+ }
+ return self;
+}
+
+
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect
+{
+
+// CGSize shadow2Offset = CGSizeMake(1, 1);
+// CGFloat shadow2BlurRadius = 1;
+// CGColorRef shadow2 = [UIColor blackColor].CGColor;
+
+ NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+
+ int month = currentMonth;
+ int year = currentYear;
+
+ //Get the first day of the month
+ NSDateComponents *dateParts = [[NSDateComponents alloc] init];
+ [dateParts setMonth:month];
+ [dateParts setYear:year];
+ [dateParts setDay:1];
+ NSDate *dateOnFirst = [calendar dateFromComponents:dateParts];
+ [dateParts release];
+ NSDateComponents *weekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:dateOnFirst];
+ int weekdayOfFirst = [weekdayComponents weekday];
+
+ //NSLog(@"weekdayOfFirst:%d", weekdayOfFirst);
+
+ int numDaysInMonth = [calendar rangeOfUnit:NSDayCalendarUnit
+ inUnit:NSMonthCalendarUnit
+ forDate:dateOnFirst].length;
+
+ //NSLog(@"month:%d, numDaysInMonth:%d", currentMonth, numDaysInMonth);
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ didAddExtraRow = NO;
+
+
+
+ //Find number of days in previous month
+ NSDateComponents *prevDateParts = [[NSDateComponents alloc] init];
+ [prevDateParts setMonth:month-1];
+ [prevDateParts setYear:year];
+ [prevDateParts setDay:1];
+
+ NSDate *prevDateOnFirst = [calendar dateFromComponents:prevDateParts];
+
+ [prevDateParts release];
+
+ int numDaysInPrevMonth = [calendar rangeOfUnit:NSDayCalendarUnit
+ inUnit:NSMonthCalendarUnit
+ forDate:prevDateOnFirst].length;
+
+ NSDateComponents *today = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:[NSDate date]];
+
+ //Draw the text for each of those days.
+ for(int i = 0; i <= weekdayOfFirst-2; i++) {
+ int day = numDaysInPrevMonth - weekdayOfFirst + 2 + i;
+
+ NSString *str = [NSString stringWithFormat:@"%d", day];
+
+
+
+ CGContextSaveGState(context);
+// CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2);
+ CGRect dayHeader2Frame = CGRectMake((i)*hDiff, 0, 21, 14);
+ [[UIColor colorWithWhite:0.6f alpha:1.0f] setFill];
+ [str drawInRect: dayHeader2Frame withFont: [UIFont fontWithName: @"Helvetica" size: 12] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter];
+ CGContextRestoreGState(context);
+ }
+
+
+ BOOL endedOnSat = NO;
+ int finalRow = 0;
+ int day = 1;
+ for (int i = 0; i < 6; i++) {
+ for(int j = 0; j < 7; j++) {
+ int dayNumber = i * 7 + j;
+
+ if(dayNumber >= (weekdayOfFirst-1) && day <= numDaysInMonth) {
+ NSString *str = [NSString stringWithFormat:@"%d", day];
+
+ CGContextSaveGState(context);
+// CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2);
+ CGRect dayHeader2Frame = CGRectMake(j*hDiff, i*vDiff, 21, 14);
+ if([today day] == day && [today month] == month && [today year] == year) {
+ [[UIColor colorWithRed: 0.98 green: 0.24 blue: 0.09 alpha: 1] setFill];
+ } else {
+ [[UIColor colorWithWhite:0.2f alpha:1.f] setFill];
+ }
+ [str drawInRect: dayHeader2Frame withFont: [UIFont fontWithName: @"Helvetica" size: 12] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter];
+ CGContextRestoreGState(context);
+
+ finalRow = i;
+
+ if(day == numDaysInMonth && j == 6) {
+ endedOnSat = YES;
+ }
+
+ if(i == 5) {
+ didAddExtraRow = YES;
+ //NSLog(@"didAddExtraRow");
+ }
+
+ ++day;
+ }
+ }
+ }
+
+ //Find number of days in previous month
+ NSDateComponents *nextDateParts = [[NSDateComponents alloc] init];
+ [nextDateParts setMonth:month+1];
+ [nextDateParts setYear:year];
+ [nextDateParts setDay:1];
+
+ NSDate *nextDateOnFirst = [calendar dateFromComponents:nextDateParts];
+
+ [nextDateParts release];
+
+ NSDateComponents *nextWeekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:nextDateOnFirst];
+ int weekdayOfNextFirst = [nextWeekdayComponents weekday];
+
+ if(!endedOnSat) {
+ //Draw the text for each of those days.
+ for(int i = weekdayOfNextFirst - 1; i < 7; i++) {
+ int day = i - weekdayOfNextFirst + 2;
+
+ NSString *str = [NSString stringWithFormat:@"%d", day];
+
+ CGContextSaveGState(context);
+// CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2);
+ CGRect dayHeader2Frame = CGRectMake((i)*hDiff, finalRow * vDiff, 21, 14);
+ [[UIColor colorWithWhite:0.6f alpha:1.0f] setFill];
+ [str drawInRect: dayHeader2Frame withFont: [UIFont fontWithName: @"Helvetica" size: 12] lineBreakMode: UILineBreakModeWordWrap alignment: UITextAlignmentCenter];
+ CGContextRestoreGState(context);
+ }
+ }
+}
+
+- (void)setMonth:(int)month {
+ currentMonth = month;
+ [self setNeedsDisplay];
+}
+
+- (void)setYear:(int)year {
+ currentYear = year;
+ [self setNeedsDisplay];
+}
+
+- (void)resetRows {
+ NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+
+ int month = currentMonth;
+ int year = currentYear;
+
+ //Get the first day of the month
+ NSDateComponents *dateParts = [[NSDateComponents alloc] init];
+ [dateParts setMonth:month];
+ [dateParts setYear:year];
+ [dateParts setDay:1];
+ NSDate *dateOnFirst = [calendar dateFromComponents:dateParts];
+ [dateParts release];
+ NSDateComponents *weekdayComponents = [calendar components:NSWeekdayCalendarUnit fromDate:dateOnFirst];
+ int weekdayOfFirst = [weekdayComponents weekday];
+
+ int numDaysInMonth = [calendar rangeOfUnit:NSDayCalendarUnit
+ inUnit:NSMonthCalendarUnit
+ forDate:dateOnFirst].length;
+ didAddExtraRow = NO;
+
+ int day = 1;
+ for (int i = 0; i < 6; i++) {
+ for(int j = 0; j < 7; j++) {
+ int dayNumber = i * 7 + j;
+ if(dayNumber >= (weekdayOfFirst - 1) && day <= numDaysInMonth) {
+ if(i == 5) {
+ didAddExtraRow = YES;
+ //NSLog(@"didAddExtraRow");
+ }
+ ++day;
+ }
+ }
+ }
+}
+
+- (BOOL)addExtraRow {
+ return didAddExtraRow;
+}
+
+
+@end
View
14 popover/Demo/ViewController.h
@@ -0,0 +1,14 @@
+//
+// ViewController.h
+// popover
+//
+// Created by Oliver Rickard on 21/08/2012.
+// Copyright (c) 2012 Oliver Rickard. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PopoverView.h"
+
+@interface ViewController : UIViewController <PopoverViewDelegate>
+
+@end
View
110 popover/Demo/ViewController.m
@@ -0,0 +1,110 @@
+//
+// ViewController.m
+// popover
+//
+// Created by Oliver Rickard on 21/08/2012.
+// Copyright (c) 2012 Oliver Rickard. All rights reserved.
+//
+
+#import "ViewController.h"
+#import "PopoverView.h"
+#import "OCDaysView.h"
+#import <QuartzCore/QuartzCore.h> //This is just for the daysView where I call "daysView.layer" not necessary normally.
+
+#define kStringArray [NSArray arrayWithObjects:@"Definitely!", @"Kind of", @"Nope", nil]
+
+@interface ViewController ()
+
+@end
+
+@implementation ViewController
+
+
+
+#pragma mark - Setup Methods
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ // Do any additional setup after loading the view, typically from a nib.
+
+ UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
+ [self.view addGestureRecognizer:[tap autorelease]];
+
+ //Create a label centered on the screen
+ UILabel *tapAnywhereLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMidX(self.view.bounds) - 200.f*0.5f, CGRectGetMidY(self.view.bounds) - 30.f*0.5f, 200.f, 30.f)];
+ tapAnywhereLabel.text = @"Tap Anywhere";
+ tapAnywhereLabel.textAlignment = UITextAlignmentCenter;
+ [self.view addSubview:[tapAnywhereLabel autorelease]];
+}
+
+
+
+#pragma mark - User Interaction Methods
+
+#pragma mark EXAMPLE CODE IS HERE
+
+- (void)tapped:(UITapGestureRecognizer *)tap {
+ CGPoint point = [tap locationInView:self.view];
+
+ //Here are a couple of different options for how to display the Popover
+
+// [PopoverView showPopoverAtPoint:point inView:self.view 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
+
+// [PopoverView showPopoverAtPoint:point inView:self.view withTitle:@"This is a title" withText:@"This is text" delegate:self]; //Show text with title
+
+// [PopoverView showPopoverAtPoint:point inView:self.view withStringArray:kStringArray delegate:self]; //Show the string array defined at top of this file
+
+// [PopoverView showPopoverAtPoint:point inView:self.view withTitle:@"Was this helpful?" withStringArray:kStringArray delegate:self]; //Show string array defined at top of this file with title.
+
+ //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
+ OCDaysView *daysView = [[OCDaysView alloc] initWithFrame:CGRectMake(0, 0, 150, 100)];
+ [daysView setMonth:10];
+ [daysView setYear:2012];
+ daysView.backgroundColor = [UIColor colorWithWhite:0.95f alpha:1.f]; //Give it a background color
+ daysView.layer.borderColor = [UIColor colorWithWhite:0.9f alpha:1.f].CGColor; //Add a border
+ daysView.layer.borderWidth = 0.5f; //One retina pixel width
+ daysView.layer.cornerRadius = 4.f;
+ daysView.layer.masksToBounds = YES;
+
+// [PopoverView showPopoverAtPoint:point inView:self.view withContentView:[daysView autorelease] delegate:self]; //Show calendar with no title
+ [PopoverView showPopoverAtPoint:point inView:self.view withTitle:@"October 2012" withContentView:[daysView autorelease] delegate:self]; //Show calendar with title
+}
+
+
+
+#pragma mark - PopoverViewDelegate Methods
+
+- (void)popoverView:(PopoverView *)popoverView didSelectItemAtIndex:(NSInteger)index {
+ NSLog(@"%s item:%d", __PRETTY_FUNCTION__, index);
+
+ //Figure out which string was selected, store in "string"
+ NSString *string = [kStringArray objectAtIndex:index];
+
+ //Show a success image, with the string from the array
+ [popoverView showImage:[UIImage imageNamed:@"success"] withMessage:string];
+
+ //Dismiss the PopoverView after 0.5 seconds
+ [popoverView performSelector:@selector(dismiss) withObject:nil afterDelay:0.5f];
+}
+
+- (void)popoverViewDidDismiss:(PopoverView *)popoverView {
+ NSLog(@"%s", __PRETTY_FUNCTION__);
+}
+
+
+
+#pragma mark - UIViewController Methods
+
+- (void)viewDidUnload
+{
+ [super viewDidUnload];
+ // Release any retained subviews of the main view.
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ return UIInterfaceOrientationIsPortrait(interfaceOrientation);
+}
+
+@end
View
2 popover/Demo/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
View
27 popover/Demo/en.lproj/MainStoryboard_iPad.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1906" systemVersion="11A511" targetRuntime="iOS.CocoaTouch.iPad" nextObjectID="6" propertyAccessControl="none" initialViewController="2">
+ <dependencies>
+ <development defaultVersion="4200" identifier="xcode"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="902"/>
+ </dependencies>
+ <scenes>
+ <scene sceneID="4">
+ <objects>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="3" sceneMemberID="firstResponder"/>
+ <viewController id="2" customClass="ViewController" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="5">
+ <rect key="frame" x="0.0" y="20" width="768" height="1004"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ </objects>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackTranslucent"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination"/>
+ </simulatedMetricsContainer>
+</document>
View
27 popover/Demo/en.lproj/MainStoryboard_iPhone.storyboard
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1906" systemVersion="11A511" targetRuntime="iOS.CocoaTouch" nextObjectID="6" propertyAccessControl="none" initialViewController="2">
+ <dependencies>
+ <development defaultVersion="4200" identifier="xcode"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="902"/>
+ </dependencies>
+ <scenes>
+ <scene sceneID="5">
+ <objects>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="4" sceneMemberID="firstResponder"/>
+ <viewController id="2" customClass="ViewController" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="3">
+ <rect key="frame" x="0.0" y="20" width="320" height="460"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <subviews/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ </view>
+ </viewController>
+ </objects>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination"/>
+ </simulatedMetricsContainer>
+</document>
View
18 popover/Demo/main.m
@@ -0,0 +1,18 @@
+//
+// main.m
+// popover
+//
+// Created by Oliver Rickard on 21/08/2012.
+// Copyright (c) 2012 Oliver Rickard. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "AppDelegate.h"
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
View
47 popover/Demo/popover-Info.plist
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.runway20.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIMainStoryboardFile</key>
+ <string>MainStoryboard_iPhone</string>
+ <key>UIMainStoryboardFile~ipad</key>
+ <string>MainStoryboard_iPad</string>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
View
14 popover/Demo/popover-Prefix.pch
@@ -0,0 +1,14 @@
+//
+// Prefix header for all source files of the 'popover' target in the 'popover' project
+//
+
+#import <Availability.h>
+
+#ifndef __IPHONE_5_0
+#warning "This project uses features only available in iOS SDK 5.0 and later."
+#endif
+
+#ifdef __OBJC__
+ #import <UIKit/UIKit.h>
+ #import <Foundation/Foundation.h>
+#endif
View
BIN popover/Images/error.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN popover/Images/error@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN popover/Images/success.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN popover/Images/success@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
127 popover/PopoverView.h
@@ -0,0 +1,127 @@
+//
+// PopoverView.h
+// Embark
+//
+// Created by Oliver Rickard on 20/08/2012.
+//
+//
+
+#import <UIKit/UIKit.h>
+
+@class PopoverView;
+
+@protocol PopoverViewDelegate <NSObject>
+
+@optional
+
+//Delegate receives this call as soon as the item has been selected
+- (void)popoverView:(PopoverView *)popoverView didSelectItemAtIndex:(NSInteger)index;
+
+//Delegate receives this call once the popover has begun the dismissal animation
+- (void)popoverViewDidDismiss:(PopoverView *)popoverView;
+
+@end
+
+@interface PopoverView : UIView {
+ CGRect boxFrame;
+ CGSize contentSize;
+ CGPoint arrowPoint;
+
+ BOOL above;
+
+ id<PopoverViewDelegate> delegate;
+
+ NSArray *subviewsArray;
+
+ NSArray *dividerRects;
+
+ UIView *contentView;
+
+ UIView *titleView;
+
+ UIActivityIndicatorView *activityIndicator;
+
+ //Instance variable that can change at runtime
+ BOOL showDividerRects;
+}
+
+@property (nonatomic, retain) UIView *titleView;
+
+@property (nonatomic, retain) UIView *contentView;
+
+@property (nonatomic, retain) NSArray *subviewsArray;
+
+@property (nonatomic, assign) id<PopoverViewDelegate> delegate;
+
+#pragma mark - Class Static Showing Methods
+
+//These are the main static methods you can use to display the popover.
+//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.
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withText:(NSString *)text delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView delegate:(id<PopoverViewDelegate>)delegate;
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)cView delegate:(id<PopoverViewDelegate>)delegate;
+
+#pragma mark - Instance Showing Methods
+
+//Adds/animates in the popover to the top of the view stack with the arrow pointing at the "point"
+//within the specified view. The contentView will be added to the popover, and should have either
+//a clear color backgroundColor, or perhaps a rounded corner bg rect (radius 4.f if you're going to
+//round).
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)contentView;
+
+//Calls above method with a UILabel containing the text you deliver to this method.
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text;
+
+//Calls top method with an array of UIView objects. This method will stack these views vertically
+//with kBoxPadding padding between each view in the y-direction.
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray;
+
+//Does same as above, but adds a title label at top of the popover.
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray;
+
+//Calls the viewArray method with an array of UILabels created with the strings
+//in stringArray. All contents of stringArray must be NSStrings.
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray;
+
+//This method does same as above, but with a title label at the top of the popover.
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray;
+
+#pragma mark - Dismissal
+//Dismisses the view, and removes it from the view stack.
+- (void)dismiss;
+
+#pragma mark - Activity Indicator Methods
+
+//Shows the activity indicator, and changes the title (if the title is available, and is a UILabel).
+- (void)showActivityIndicatorWithMessage:(NSString *)msg;
+
+//Hides the activity indicator, and changes the title (if the title is available) to the msg
+- (void)hideActivityIndicatorWithMessage:(NSString *)msg;
+
+#pragma mark - Custom Image Showing
+
+//Animate in, and display the image provided here.
+- (void)showImage:(UIImage *)image withMessage:(NSString *)msg;
+
+#pragma mark - Error/Success Methods
+
+//Shows (and animates in) an error X in the contentView
+- (void)showError;
+
+//Shows (and animates in) a success checkmark in the contentView
+- (void)showSuccess;
+
+@end
View
944 popover/PopoverView.m
@@ -0,0 +1,944 @@
+//
+// PopoverView.m
+// Embark
+//
+// Created by Oliver Rickard on 20/08/2012.
+//
+//
+
+#import "PopoverView.h"
+#import <QuartzCore/QuartzCore.h>
+
+#pragma mark Constants - Configure look/feel
+
+// BOX GEOMETRY
+
+//Height/width of the actual arrow
+#define kArrowHeight 12.f
+
+//padding within the box for the contentView
+#define kBoxPadding 10.f
+
+//control point offset for rounding corners of the main popover box
+#define kCPOffset 1.8f
+
+//radius for the rounded corners of the main popover box
+#define kBoxRadius 4.f
+
+//Curvature value for the arrow. Set to 0.f to make it linear.
+#define kArrowCurvature 6.f
+
+//Minimum distance from the side of the arrow to the beginning of curvature for the box
+#define kArrowHorizontalPadding 5.f
+
+//Alpha value for the shadow
+#define kShadowAlpha 0.4f
+
+//Box gradient bg alpha
+#define kBoxAlpha 0.95f
+
+//Padding along top of screen to allow for any nav/status bars
+#define kTopMargin 50.f
+
+//margin along the left and right of the box
+#define kHorizontalMargin 10.f
+
+
+// DIVIDERS BETWEEN VIEWS
+
+//Bool that turns off/on the dividers
+#define kShowDividersBetweenViews YES
+
+//color for the divider fill
+#define kDividerColor [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:0.15f]
+
+
+// BACKGROUND GRADIENT
+
+//bottom color white in gradient bg
+#define kGradientBottomColor [UIColor colorWithWhite:0.980f alpha:kBoxAlpha]
+
+//top color white value in gradient bg
+#define kGradientTopColor [UIColor colorWithWhite:1.f alpha:kBoxAlpha]
+
+
+// TITLE GRADIENT
+
+//bottom color white value in title gradient bg
+#define kGradientTitleBottomColor [UIColor colorWithWhite:0.93f alpha:kBoxAlpha]
+
+//top color white value in title gradient bg
+#define kGradientTitleTopColor [UIColor colorWithWhite:1.f alpha:kBoxAlpha]
+
+
+// FONTS
+
+//normal text font
+#define kTextFont [UIFont fontWithName:@"HelveticaNeue" size:20.f]
+
+//normal text color
+#define kTextColor [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1]
+
+//normal text alignment
+#define kTextAlignment UITextAlignmentCenter
+
+//title font
+#define kTitleFont [UIFont fontWithName:@"HelveticaNeue" size:22.f]
+
+//title text color
+#define kTitleColor [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1]
+
+
+
+
+
+#pragma mark - Implementation
+
+@implementation PopoverView
+
+@synthesize subviewsArray;
+@synthesize contentView;
+@synthesize titleView;
+@synthesize delegate;
+
+#pragma mark - Static Methods
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withText:text];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withText:(NSString *)text delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withTitle:title withText:text];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withViewArray:viewArray];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withTitle:title withViewArray:viewArray];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withStringArray:stringArray];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withTitle:title withStringArray:stringArray];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withTitle:title withContentView:cView];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
++ (PopoverView *)showPopoverAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)cView delegate:(id<PopoverViewDelegate>)delegate {
+ PopoverView *popoverView = [[PopoverView alloc] initWithFrame:CGRectZero];
+ [popoverView showAtPoint:point inView:view withContentView:cView];
+ popoverView.delegate = delegate;
+ [popoverView release];
+ return popoverView;
+}
+
+#pragma mark - View Lifecycle
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+ if (self) {
+ // Initialization code
+
+ self.backgroundColor = [UIColor clearColor];
+
+ self.titleView = nil;
+ self.contentView = nil;
+
+ showDividerRects = kShowDividersBetweenViews;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ self.subviewsArray = nil;
+
+ self.contentView = nil;
+ self.titleView = nil;
+
+ [super dealloc];
+}
+
+
+
+#pragma mark - Display methods
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withText:(NSString *)text {
+ UIFont *font = kTextFont;
+
+ CGSize textSize = [text sizeWithFont:font constrainedToSize:CGSizeMake([[UIScreen mainScreen] bounds].size.width - kHorizontalMargin*4.f, 1000.f) lineBreakMode:UILineBreakModeWordWrap];
+
+ UILabel *textView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
+ textView.backgroundColor = [UIColor clearColor];
+ textView.userInteractionEnabled = NO;
+ [textView setNumberOfLines:0]; //This is so the label word wraps instead of cutting off the text
+ textView.font = font;
+ textView.textAlignment = kTextAlignment;
+ textView.textColor = [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1];
+ textView.text = text;
+
+ [self showAtPoint:point inView:view withViewArray:[NSArray arrayWithObject:textView]];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withText:(NSString *)text {
+ UIFont *font = kTextFont;
+ CGSize textSize = [text sizeWithFont:font constrainedToSize:CGSizeMake([[UIScreen mainScreen] bounds].size.width - kHorizontalMargin*4.f, 1000.f) lineBreakMode:UILineBreakModeWordWrap];
+
+ UILabel *textView = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
+ textView.backgroundColor = [UIColor clearColor];
+ textView.userInteractionEnabled = NO;
+ [textView setNumberOfLines:0]; //This is so the label word wraps instead of cutting off the text
+ textView.font = font;
+ textView.textAlignment = kTextAlignment;
+ textView.textColor = [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1];
+ textView.text = text;
+
+ [self showAtPoint:point inView:view withTitle:title withViewArray:[NSArray arrayWithObject:textView]];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray *)viewArray {
+ UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
+
+ float totalHeight = 0.f;
+ float totalWidth = 0.f;
+
+ int i = 0;
+
+ //Position each view the first time, and identify which view has the largest width that controls
+ //the sizing of the popover.
+ for(UIView *view in viewArray) {
+
+ //Only add padding below the view if it's not the last item
+ float padding = (i == viewArray.count-1) ? 0 : kBoxPadding;
+
+ totalHeight += view.frame.size.height + padding;
+
+ if(view.frame.size.width > totalWidth) {
+ totalWidth = view.frame.size.width;
+ }
+
+ [container addSubview:view];
+
+ i++;
+ }
+
+ //If dividers are enabled, then we allocate the divider rect array. This will hold NSValues
+ if(kShowDividersBetweenViews) {
+ dividerRects = [[NSMutableArray alloc] initWithCapacity:viewArray.count-1];
+ }
+
+ container.frame = CGRectMake(0, 0, totalWidth, totalHeight);
+
+ i = 0;
+
+ totalHeight = 0;
+
+ //Now we actually change the frame element for each subview, and center the views horizontally.
+ for(UIView *view in viewArray) {
+ if([view isKindOfClass:[UILabel class]]) {
+ //Now make sure all the labels are the full width
+ view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height);
+ }
+
+ //and if dividers are enabled, we record their position for the drawing methods
+ if(kShowDividersBetweenViews && i != viewArray.count-1) {
+ CGRect dividerRect = CGRectMake(view.frame.origin.x, view.frame.origin.y + view.frame.size.height + kBoxPadding*0.5f, view.frame.size.width, 0.5f);
+
+ [((NSMutableArray *)dividerRects) addObject:[NSValue valueWithCGRect:dividerRect]];
+ }
+
+ //Only add padding below the view if it's not the last item
+ float padding = (i == viewArray.count-1) ? 0.f : kBoxPadding;
+
+ totalHeight += view.frame.size.height + padding;
+
+ i++;
+ }
+
+ self.subviewsArray = viewArray;
+
+ [self showAtPoint:point inView:view withContentView:[container autorelease]];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withViewArray:(NSArray *)viewArray {
+ UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
+
+ //Create a label for the title text.
+ CGSize titleSize = [title sizeWithFont:kTitleFont];
+ UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.f, 0.f, titleSize.width, titleSize.height)];
+ titleLabel.backgroundColor = [UIColor clearColor];
+ titleLabel.font = kTitleFont;
+ titleLabel.textAlignment = UITextAlignmentCenter;
+ titleLabel.textColor = kTitleColor;
+ titleLabel.text = title;
+
+ //Make sure that the title's label will have non-zero height. If it has zero height, then we don't allocate any space
+ //for it in the positioning of the views.
+ float titleHeightOffset = (titleSize.height > 0.f ? kBoxPadding : 0.f);
+
+ float totalHeight = titleSize.height + titleHeightOffset + kBoxPadding;
+ float totalWidth = titleSize.width;
+
+ int i = 0;
+
+ //Position each view the first time, and identify which view has the largest width that controls
+ //the sizing of the popover.
+ for(UIView *view in viewArray) {
+
+ view.frame = CGRectMake(0, totalHeight, view.frame.size.width, view.frame.size.height);
+
+ //Only add padding below the view if it's not the last item.
+ float padding = (i == viewArray.count-1) ? 0.f : kBoxPadding;
+
+ totalHeight += view.frame.size.height + padding;
+
+ if(view.frame.size.width > totalWidth) {
+ totalWidth = view.frame.size.width;
+ }
+
+ [container addSubview:view];
+
+ i++;
+ }
+
+ //If dividers are enabled, then we allocate the divider rect array. This will hold NSValues
+ if(kShowDividersBetweenViews) {
+ dividerRects = [[NSMutableArray alloc] initWithCapacity:viewArray.count-1];
+ }
+
+ i = 0;
+
+ for(UIView *view in viewArray) {
+ if([view isKindOfClass:[UILabel class]]) {
+ //Now make sure all the labels are the full width
+ view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height);
+ }
+
+ //Center the views
+ view.frame = CGRectMake(CGRectGetMinX(boxFrame) + totalWidth*0.5f - view.frame.size.width*0.5f, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
+
+ //and if dividers are enabled, we record their position for the drawing methods
+ if(kShowDividersBetweenViews && i != viewArray.count-1) {
+ CGRect dividerRect = CGRectMake(view.frame.origin.x, view.frame.origin.y + view.frame.size.height + kBoxPadding*0.5f, view.frame.size.width, 0.5f);
+
+ [((NSMutableArray *)dividerRects) addObject:[NSValue valueWithCGRect:dividerRect]];
+ }
+
+ i++;
+ }
+
+ titleLabel.frame = CGRectMake(totalWidth*0.5f - titleSize.width*0.5f, 0, titleSize.width, titleSize.height);
+
+ //Store the titleView as an instance variable if it is larger than 0 height (not an empty string)
+ if(titleSize.height > 0) {
+ self.titleView = titleLabel;
+ }
+
+ [container addSubview:[titleLabel autorelease]];
+
+ container.frame = CGRectMake(0, 0, totalWidth, totalHeight);
+
+ self.subviewsArray = viewArray;
+
+ [self showAtPoint:point inView:view withContentView:[container autorelease]];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray {
+ NSMutableArray *labelArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count];
+
+ UIFont *font = kTextFont;
+
+ for(NSString *string in stringArray) {
+ CGSize textSize = [string sizeWithFont:font];
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
+ label.backgroundColor = [UIColor clearColor];
+ label.font = font;
+ label.textAlignment = kTextAlignment;
+ label.textColor = kTextColor;
+ label.text = string;
+ label.layer.cornerRadius = 4.f;
+
+ [labelArray addObject:[label autorelease]];
+ }
+
+ [self showAtPoint:point inView:view withViewArray:[labelArray autorelease]];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray {
+ NSMutableArray *labelArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count];
+
+ UIFont *font = kTextFont;
+
+ for(NSString *string in stringArray) {
+ CGSize textSize = [string sizeWithFont:font];
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
+ label.backgroundColor = [UIColor clearColor];
+ label.font = font;
+ label.textAlignment = kTextAlignment;
+ label.textColor = kTextColor;
+ label.text = string;
+ label.layer.cornerRadius = 4.f;
+
+ [labelArray addObject:[label autorelease]];
+ }
+
+ [self showAtPoint:point inView:view withTitle:title withViewArray:labelArray];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView {
+ [self showAtPoint:point inView:view withTitle:title withViewArray:[NSArray arrayWithObject:cView]];
+}
+
+- (void)showAtPoint:(CGPoint)point inView:(UIView *)view withContentView:(UIView *)cView {
+
+ //NSLog(@"point:%f,%f", point.x, point.y);
+
+ self.contentView = cView;
+
+ //Locate the view at the top fo the view stack.
+ UIWindow *window = [UIApplication sharedApplication].keyWindow;
+ if(!window) {
+ window = [[UIApplication sharedApplication].windows objectAtIndex:0];
+ }
+ UIView *topView = [[window subviews] objectAtIndex:0];
+
+ CGPoint topPoint = [topView convertPoint:point fromView:view];
+
+ arrowPoint = topPoint;
+
+ //NSLog(@"arrowPoint:%f,%f", arrowPoint.x, arrowPoint.y);
+
+ CGRect topViewBounds = topView.bounds;
+
+ float contentHeight = contentView.frame.size.height;
+ float contentWidth = contentView.frame.size.width;
+
+ float padding = kBoxPadding;
+
+ float boxHeight = contentHeight + 2.f*padding;
+ float boxWidth = contentWidth + 2.f*padding;
+
+ float xOrigin = 0.f;
+
+ //Make sure the arrow point is within the drawable bounds for the popover.
+ if(arrowPoint.x + kArrowHeight > topViewBounds.size.width - kHorizontalMargin - kBoxRadius - kArrowHorizontalPadding) {//Too far to the right
+ arrowPoint.x = topViewBounds.size.width - kHorizontalMargin - kBoxRadius - kArrowHorizontalPadding - kArrowHeight;
+ //NSLog(@"Correcting Arrow Point because it's too far to the right");
+ } else if(arrowPoint.x - kArrowHeight < kHorizontalMargin + kBoxRadius + kArrowHorizontalPadding) {//Too far to the left
+ arrowPoint.x = kHorizontalMargin + kArrowHeight + kBoxRadius + kArrowHorizontalPadding;
+ //NSLog(@"Correcting Arrow Point because it's too far to the left");
+ }
+
+ //NSLog(@"arrowPoint:%f,%f", arrowPoint.x, arrowPoint.y);
+
+ xOrigin = arrowPoint.x - boxWidth*0.5f;
+
+ //Check to see if the centered xOrigin value puts the box outside of the normal range.
+ if(xOrigin < CGRectGetMinX(topViewBounds) + kHorizontalMargin) {
+ xOrigin = CGRectGetMinX(topViewBounds) + kHorizontalMargin;
+ } else if(xOrigin + boxWidth > CGRectGetMaxX(topViewBounds) - kHorizontalMargin) {
+ //Check to see if the positioning puts the box out of the window towards the left
+ xOrigin = CGRectGetMaxX(topViewBounds) - kHorizontalMargin - boxWidth;
+ }
+
+ float arrowHeight = kArrowHeight;
+
+ float topPadding = kTopMargin;
+
+ above = YES;
+
+ if(topPoint.y - contentHeight - arrowHeight - topPadding < CGRectGetMinY(topViewBounds)) {
+ //Position below because it won't fit above.
+ above = NO;
+
+ boxFrame = CGRectMake(xOrigin, arrowPoint.y + arrowHeight, boxWidth, boxHeight);
+ } else {
+ //Position above.
+ above = YES;
+
+ boxFrame = CGRectMake(xOrigin, arrowPoint.y - arrowHeight - boxHeight, boxWidth, boxHeight);
+ }
+
+ //NSLog(@"boxFrame:(%f,%f,%f,%f)", boxFrame.origin.x, boxFrame.origin.y, boxFrame.size.width, boxFrame.size.height);
+
+ CGRect contentFrame = CGRectMake(boxFrame.origin.x + padding, boxFrame.origin.y + padding, contentWidth, contentHeight);
+ contentView.frame = contentFrame;
+ [self addSubview:contentView];
+
+ //We set the anchorPoint here so the popover will "grow" out of the arrowPoint specified by the user.
+ //You have to set the anchorPoint before setting the frame, because the anchorPoint property will
+ //implicitly set the frame for the view, which we do not want.
+ self.layer.anchorPoint = CGPointMake(arrowPoint.x / topViewBounds.size.width, arrowPoint.y / topViewBounds.size.height);
+ self.frame = topViewBounds;
+ [self setNeedsDisplay];
+
+ [topView addSubview:self];
+
+ //Add a tap gesture recognizer to the large invisible view (self), which will detect taps anywhere on the screen.
+ UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
+ [self addGestureRecognizer:tap];
+ [tap release];
+
+ self.userInteractionEnabled = YES;
+
+ //Make the view small and transparent before animation
+ self.alpha = 0.f;
+ self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
+
+ //animate into full size
+ //First stage animates to 1.05x normal size, then second stage animates back down to 1x size.
+ //This two-stage animation creates a little "pop" on open.
+ [UIView animateWithDuration:0.2f delay:0.f options:UIViewAnimationCurveEaseInOut animations:^{
+ self.alpha = 1.f;
+ self.transform = CGAffineTransformMakeScale(1.05f, 1.05f);
+ } completion:^(BOOL finished) {
+ [UIView animateWithDuration:0.08f delay:0.f options:UIViewAnimationOptionCurveEaseInOut animations:^{
+ self.transform = CGAffineTransformIdentity;
+ } completion:nil];
+ }];
+}
+
+
+
+#pragma mark - Activity Indicator
+
+//Animates in a progress indicator, and removes
+- (void)showActivityIndicatorWithMessage:(NSString *)msg {
+ if([titleView isKindOfClass:[UILabel class]]) {
+ ((UILabel *)titleView).text = msg;
+ }
+
+ if(subviewsArray && (subviewsArray.count > 0)) {
+ [UIView animateWithDuration:0.2f animations:^{
+ for(UIView *view in subviewsArray) {
+ view.alpha = 0.f;
+ }
+ }];
+
+ if(showDividerRects) {
+ showDividerRects = NO;
+ [self setNeedsDisplay];
+ }
+ }
+
+ if(activityIndicator) {
+ [activityIndicator release];
+ [activityIndicator removeFromSuperview];
+ activityIndicator = nil;
+ }
+
+ activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
+ activityIndicator.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - 10.f, CGRectGetMidY(contentView.bounds) - 10.f + 20.f, 20.f, 20.f);
+ [contentView addSubview:activityIndicator];
+
+ [activityIndicator startAnimating];
+}
+
+- (void)hideActivityIndicatorWithMessage:(NSString *)msg {
+ if([titleView isKindOfClass:[UILabel class]]) {
+ ((UILabel *)titleView).text = msg;
+ }
+
+ [activityIndicator stopAnimating];
+ [UIView animateWithDuration:0.1f animations:^{
+ activityIndicator.alpha = 0.f;
+ } completion:^(BOOL finished) {
+ [activityIndicator release];
+ [activityIndicator removeFromSuperview];
+ activityIndicator = nil;
+ }];
+}
+
+- (void)showImage:(UIImage *)image withMessage:(NSString *)msg {
+ UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
+ imageView.alpha = 0.f;
+ imageView.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - image.size.width*0.5f, CGRectGetMidY(contentView.bounds) - image.size.height*0.5f + 20.f, image.size.width, image.size.height);
+ imageView.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
+
+ [contentView addSubview:[imageView autorelease]];
+
+ if(subviewsArray && (subviewsArray.count > 0)) {
+ [UIView animateWithDuration:0.2f animations:^{
+ for(UIView *view in subviewsArray) {
+ view.alpha = 0.f;
+ }
+ }];
+
+ if(showDividerRects) {
+ showDividerRects = NO;
+ [self setNeedsDisplay];
+ }
+ }
+
+ if(msg) {
+ if([titleView isKindOfClass:[UILabel class]]) {
+ ((UILabel *)titleView).text = msg;
+ }
+ }
+
+ [UIView animateWithDuration:0.2f delay:0.2f options:UIViewAnimationCurveEaseOut animations:^{
+ imageView.alpha = 1.f;
+ imageView.transform = CGAffineTransformIdentity;
+ } completion:^(BOOL finished) {
+ //[imageView removeFromSuperview];
+ }];
+}
+
+- (void)showError {
+ UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"error"]];
+ imageView.alpha = 0.f;
+ imageView.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - 20.f, CGRectGetMidY(contentView.bounds) - 20.f + 20.f, 40.f, 40.f);
+ imageView.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
+
+ [contentView addSubview:[imageView autorelease]];
+
+ if(subviewsArray && (subviewsArray.count > 0)) {
+ [UIView animateWithDuration:0.1f animations:^{
+ for(UIView *view in subviewsArray) {
+ view.alpha = 0.f;
+ }
+ }];
+
+ if(showDividerRects) {
+ showDividerRects = NO;
+ [self setNeedsDisplay];
+ }
+ }
+
+ [UIView animateWithDuration:0.1f delay:0.1f options:UIViewAnimationCurveEaseOut animations:^{
+ imageView.alpha = 1.f;
+ imageView.transform = CGAffineTransformIdentity;
+ } completion:^(BOOL finished) {
+ //[imageView removeFromSuperview];
+ }];
+
+}
+
+- (void)showSuccess {
+ UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"success"]];
+ imageView.alpha = 0.f;
+ imageView.frame = CGRectMake(CGRectGetMidX(contentView.bounds) - 20.f, CGRectGetMidY(contentView.bounds) - 20.f + 20.f, 40.f, 40.f);
+ imageView.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
+
+ [contentView addSubview:[imageView autorelease]];
+
+ if(subviewsArray && (subviewsArray.count > 0)) {
+ [UIView animateWithDuration:0.1f animations:^{
+ for(UIView *view in subviewsArray) {
+ view.alpha = 0.f;
+ }
+ }];
+
+ if(showDividerRects) {
+ showDividerRects = NO;
+ [self setNeedsDisplay];
+ }
+ }
+
+ [UIView animateWithDuration:0.1f delay:0.1f options:UIViewAnimationCurveEaseOut animations:^{
+ imageView.alpha = 1.f;
+ imageView.transform = CGAffineTransformIdentity;
+ } completion:^(BOOL finished) {
+ //[imageView removeFromSuperview];
+ }];
+
+}
+
+
+
+#pragma mark - User Interaction
+
+- (void)tapped:(UITapGestureRecognizer *)tap {
+
+ CGPoint point = [tap locationInView:contentView];
+
+ //NSLog(@"point:(%f,%f)", point.x, point.y);
+
+ BOOL found = NO;
+
+ //NSLog(@"subviewsArray:%@", subviewsArray);
+
+ for(int i = 0; i < subviewsArray.count && !found; i++) {
+ UIView *view = [subviewsArray objectAtIndex:i];
+
+ //NSLog(@"Rect:(%f,%f,%f,%f)", view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height);
+
+ if(CGRectContainsPoint(view.frame, point)) {
+ //The tap was within this view, so we notify the delegate, and break the loop.
+
+ found = YES;
+
+ //NSLog(@"Tapped subview:%d", i);
+
+ if([view isKindOfClass:[UILabel class]]) {
+ UILabel *label = (UILabel *)view;
+ label.backgroundColor = [UIColor colorWithRed:0.329 green:0.341 blue:0.353 alpha:1];
+ label.textColor = [UIColor whiteColor];
+
+ // [self performSelector:@selector(dismiss) withObject:nil afterDelay:0.05f];
+ }
+
+ if(delegate && [delegate respondsToSelector:@selector(popoverView:didSelectItemAtIndex:)]) {
+ [delegate popoverView:self didSelectItemAtIndex:i];
+ }
+
+ break;
+ }
+ }
+
+ if(!found && CGRectContainsPoint(contentView.bounds, point)) {
+ found = YES;
+ //NSLog(@"popover box contains point, ignoring user input");
+ }
+
+ if(!found) {
+ [self dismiss];
+ }
+
+}
+
+- (void)dismiss {
+ [UIView animateWithDuration:0.3f animations:^{
+ self.alpha = 0.1f;
+ self.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
+ } completion:^(BOOL finished) {
+ [self removeFromSuperview];
+
+ if(self.delegate && [self.delegate respondsToSelector:@selector(popoverViewDidDismiss:)]) {
+ [delegate popoverViewDidDismiss:self];
+ }
+ }];
+}
+
+
+
+#pragma mark - Drawing Routines
+
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect
+{
+ // Drawing code
+
+ // Build the popover path
+ CGRect frame = boxFrame;
+
+ float xMin = CGRectGetMinX(frame);
+ float yMin = CGRectGetMinY(frame);
+
+ float xMax = CGRectGetMaxX(frame);
+ float yMax = CGRectGetMaxY(frame);
+
+ float radius = kBoxRadius; //Radius of the curvature.
+
+ float cpOffset = kCPOffset; //Control Point Offset. Modifies how "curved" the corners are.
+
+
+ /*
+ LT2 RT1
+ LT1⌜⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⎺⌝RT2
+ | |
+ | popover |
+ | |
+ LB2⌞_______________⌟RB1
+ LB1 RB2
+
+ Traverse rectangle in clockwise order, starting at LT1
+ L = Left
+ R = Right
+ T = Top
+ B = Bottom
+ 1,2 = order of traversal for any given corner
+
+ */
+
+ UIBezierPath *popoverPath = [UIBezierPath bezierPath];
+ [popoverPath moveToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMinY(frame) + radius)];//LT1
+ [popoverPath addCurveToPoint:CGPointMake(xMin + radius, yMin) controlPoint1:CGPointMake(xMin, yMin + radius - cpOffset) controlPoint2:CGPointMake(xMin + radius - cpOffset, yMin)];//LT2
+
+ //If the popover is positioned below (!above) the arrowPoint, then we know that the arrow must be on the top of the popover.
+ //In this case, the arrow is located between LT2 and RT1
+ if(!above) {
+ [popoverPath addLineToPoint:CGPointMake(arrowPoint.x - kArrowHeight, yMin)];//left side
+ [popoverPath addCurveToPoint:arrowPoint controlPoint1:CGPointMake(arrowPoint.x - kArrowHeight + kArrowCurvature, yMin) controlPoint2:arrowPoint];//actual arrow point
+ [popoverPath addCurveToPoint:CGPointMake(arrowPoint.x + kArrowHeight, yMin) controlPoint1:arrowPoint controlPoint2:CGPointMake(arrowPoint.x + kArrowHeight - kArrowCurvature, yMin)];//right side
+ }
+
+ [popoverPath addLineToPoint:CGPointMake(xMax - radius, yMin)];//RT1
+ [popoverPath addCurveToPoint:CGPointMake(xMax, yMin + radius) controlPoint1:CGPointMake(xMax - radius + cpOffset, yMin) controlPoint2:CGPointMake(xMax, yMin + radius - cpOffset)];//RT2
+ [popoverPath addLineToPoint:CGPointMake(xMax, yMax - radius)];//RB1
+ [popoverPath addCurveToPoint:CGPointMake(xMax - radius, yMax) controlPoint1:CGPointMake(xMax, yMax - radius + cpOffset) controlPoint2:CGPointMake(xMax - radius + cpOffset, yMax)];//RB2
+
+ //If the popover is positioned above the arrowPoint, then we know that the arrow must be on the bottom of the popover.
+ //In this case, the arrow is located somewhere between LB1 and RB2
+ if(above) {
+ [popoverPath addLineToPoint:CGPointMake(arrowPoint.x + kArrowHeight, yMax)];//right side
+ [popoverPath addCurveToPoint:arrowPoint controlPoint1:CGPointMake(arrowPoint.x + kArrowHeight - kArrowCurvature, yMax) controlPoint2:arrowPoint];//arrow point
+ [popoverPath addCurveToPoint:CGPointMake(arrowPoint.x - kArrowHeight, yMax) controlPoint1:arrowPoint controlPoint2:CGPointMake(arrowPoint.x - kArrowHeight + kArrowCurvature, yMax)];
+ }
+
+ [popoverPath addLineToPoint:CGPointMake(xMin + radius, yMax)];//LB1
+ [popoverPath addCurveToPoint:CGPointMake(xMin, yMax - radius) controlPoint1:CGPointMake(xMin + radius - cpOffset, yMax) controlPoint2:CGPointMake(xMin, yMax - radius + cpOffset)];//LB2
+ [popoverPath closePath];
+
+ //// General Declarations
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ //// Shadow Declarations
+ UIColor* shadow = [UIColor colorWithWhite:0.f alpha:kShadowAlpha];
+ CGSize shadowOffset = CGSizeMake(0, 1);
+ CGFloat shadowBlurRadius = 10;
+
+ //// Gradient Declarations
+ NSArray* gradientColors = [NSArray arrayWithObjects:
+ (id)kGradientTopColor.CGColor,
+ (id)kGradientBottomColor.CGColor, nil];
+ CGFloat gradientLocations[] = {0, 1};
+ CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)gradientColors, gradientLocations);
+
+
+ //These floats are the top and bottom offsets for the gradient drawing so the drawing includes the arrows.
+ float bottomOffset = (above ? kArrowHeight : 0.f);
+ float topOffset = (!above ? kArrowHeight : 0.f);
+
+ //Draw the actual gradient and shadow.
+ CGContextSaveGState(context);
+ CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor);
+ CGContextBeginTransparencyLayer(context, NULL);
+ [popoverPath addClip];
+ CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame) - topOffset), CGPointMake(CGRectGetMidX(frame), CGRectGetMaxY(frame) + bottomOffset), 0);
+ CGContextEndTransparencyLayer(context);
+ CGContextRestoreGState(context);
+
+ //// Cleanup
+ CGGradientRelease(gradient);
+ CGColorSpaceRelease(colorSpace);
+
+
+ //Draw the title background
+ {
+ //Calculate the height of the title bg
+ float titleBGHeight = -1;
+
+ //NSLog(@"titleView:%@", titleView);
+
+ if(titleView != nil) {
+ titleBGHeight = kBoxPadding*2.f + titleView.frame.size.height;
+ }
+
+
+ //Draw the title bg height, but only if we need to.
+ if(titleBGHeight > 0.f) {
+ CGPoint startingPoint = CGPointMake(xMin, yMin + titleBGHeight);
+ CGPoint endingPoint = CGPointMake(xMax, yMin + titleBGHeight);
+
+ UIBezierPath *titleBGPath = [UIBezierPath bezierPath];
+ [titleBGPath moveToPoint:startingPoint];
+ [titleBGPath addLineToPoint:CGPointMake(CGRectGetMinX(frame), CGRectGetMinY(frame) + radius)];//LT1
+ [titleBGPath addCurveToPoint:CGPointMake(xMin + radius, yMin) controlPoint1:CGPointMake(xMin, yMin + radius - cpOffset) controlPoint2:CGPointMake(xMin + radius - cpOffset, yMin)];//LT2
+
+ //If the popover is positioned below (!above) the arrowPoint, then we know that the arrow must be on the top of the popover.
+ //In this case, the arrow is located between LT2 and RT1
+ if(!above) {
+ [titleBGPath addLineToPoint:CGPointMake(arrowPoint.x - kArrowHeight, yMin)];//left side
+ [titleBGPath addCurveToPoint:arrowPoint controlPoint1:CGPointMake(arrowPoint.x - kArrowHeight + kArrowCurvature, yMin) controlPoint2:arrowPoint];//actual arrow point
+ [titleBGPath addCurveToPoint:CGPointMake(arrowPoint.x + kArrowHeight, yMin) controlPoint1:arrowPoint controlPoint2:CGPointMake(arrowPoint.x + kArrowHeight - kArrowCurvature, yMin)];//right side
+ }
+
+ [titleBGPath addLineToPoint:CGPointMake(xMax - radius, yMin)];//RT1
+ [titleBGPath addCurveToPoint:CGPointMake(xMax, yMin + radius) controlPoint1:CGPointMake(xMax - radius + cpOffset, yMin) controlPoint2:CGPointMake(xMax, yMin + radius - cpOffset)];//RT2
+ [titleBGPath addLineToPoint:endingPoint];
+ [titleBGPath addLineToPoint:startingPoint];
+ [titleBGPath closePath];
+
+ //// General Declarations
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ //// Gradient Declarations
+ NSArray* gradientColors = [NSArray arrayWithObjects:
+ (id)kGradientTitleTopColor.CGColor,
+ (id)kGradientTitleBottomColor.CGColor, nil];
+ CGFloat gradientLocations[] = {0, 1};
+ CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef)gradientColors, gradientLocations);
+
+
+ //These floats are the top and bottom offsets for the gradient drawing so the drawing includes the arrows.
+ float topOffset = (!above ? kArrowHeight : 0.f);
+
+ //Draw the actual gradient and shadow.
+ CGContextSaveGState(context);
+ CGContextBeginTransparencyLayer(context, NULL);
+ [titleBGPath addClip];
+ CGContextDrawLinearGradient(context, gradient, CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame) - topOffset), CGPointMake(CGRectGetMidX(frame), CGRectGetMinY(frame) + titleBGHeight), 0);
+ CGContextEndTransparencyLayer(context);
+ CGContextRestoreGState(context);
+
+ UIBezierPath *dividerLine = [UIBezierPath bezierPathWithRect:CGRectMake(startingPoint.x, startingPoint.y, (endingPoint.x - startingPoint.x), 0.5f)];
+ [[UIColor colorWithRed:0.741 green:0.741 blue:0.741 alpha:0.5f] setFill];
+ [dividerLine fill];
+
+ //// Cleanup
+ CGGradientRelease(gradient);
+ CGColorSpaceRelease(colorSpace);
+ }
+ }
+
+
+
+ //Draw the divider rects if we need to
+ {
+ if(kShowDividersBetweenViews && showDividerRects) {
+ if(dividerRects && dividerRects.count > 0) {
+ for(NSValue *value in dividerRects) {
+ CGRect rect = value.CGRectValue;
+ rect.origin.x += contentView.frame.origin.x;
+ rect.origin.y += contentView.frame.origin.y;
+
+ UIBezierPath *dividerPath = [UIBezierPath bezierPathWithRect:rect];
+ [kDividerColor setFill];
+ [dividerPath fill];
+ }
+ }
+ }
+ }
+}
+
+
+@end
View
2 popoverTests/en.lproj/InfoPlist.strings