Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial code commit.

  • Loading branch information...
commit 9dcaeba7e73cf05cdb9dbe27fb243a22055be328 1 parent 7c658b5
@devindoty devindoty authored
Showing with 33,498 additions and 0 deletions.
  1. BIN  .DS_Store
  2. +346 −0 EGOTextView_Demo.xcodeproj/project.pbxproj
  3. +7 −0 EGOTextView_Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  4. +29,687 −0 EGOTextView_Demo.xcodeproj/project.xcworkspace/xcuserdata/devin.xcuserdatad/UserInterfaceState.xcuserstate
  5. +10 −0 EGOTextView_Demo.xcodeproj/project.xcworkspace/xcuserdata/devin.xcuserdatad/WorkspaceSettings.xcsettings
  6. +23 −0 EGOTextView_Demo.xcodeproj/xcuserdata/devin.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist
  7. +72 −0 EGOTextView_Demo.xcodeproj/xcuserdata/devin.xcuserdatad/xcschemes/EGOTextView_Demo.xcscheme
  8. +22 −0 EGOTextView_Demo.xcodeproj/xcuserdata/devin.xcuserdatad/xcschemes/xcschememanagement.plist
  9. BIN  EGOTextView_Demo/.DS_Store
  10. +64 −0 EGOTextView_Demo/EGOTextView/EGOTextView.h
  11. +2,319 −0 EGOTextView_Demo/EGOTextView/EGOTextView.m
  12. BIN  EGOTextView_Demo/EGOTextView/Resources/drag-dot@2x.png
  13. BIN  EGOTextView_Demo/EGOTextView/Resources/loupe-hi@2x.png
  14. BIN  EGOTextView_Demo/EGOTextView/Resources/loupe-lo@2x.png
  15. BIN  EGOTextView_Demo/EGOTextView/Resources/loupe-mask@2x.png
  16. BIN  EGOTextView_Demo/EGOTextView/Resources/magnifier-ranged-hi@2x.png
  17. BIN  EGOTextView_Demo/EGOTextView/Resources/magnifier-ranged-lo-stemless@2x.png
  18. BIN  EGOTextView_Demo/EGOTextView/Resources/magnifier-ranged-lo@2x.png
  19. BIN  EGOTextView_Demo/EGOTextView/Resources/magnifier-ranged-mask@2x.png
  20. +38 −0 EGOTextView_Demo/EGOTextView_Demo-Info.plist
  21. +14 −0 EGOTextView_Demo/EGOTextView_Demo-Prefix.pch
  22. +21 −0 EGOTextView_Demo/EGOTextView_DemoAppDelegate.h
  23. +77 −0 EGOTextView_Demo/EGOTextView_DemoAppDelegate.m
  24. +22 −0 EGOTextView_Demo/EGOTextView_DemoViewController.h
  25. +157 −0 EGOTextView_Demo/EGOTextView_DemoViewController.m
  26. +156 −0 EGOTextView_Demo/en.lproj/EGOTextView_DemoViewController.xib
  27. +2 −0  EGOTextView_Demo/en.lproj/InfoPlist.strings
  28. +444 −0 EGOTextView_Demo/en.lproj/MainWindow.xib
  29. +17 −0 EGOTextView_Demo/main.m
View
BIN  .DS_Store
Binary file not shown
View
346 EGOTextView_Demo.xcodeproj/project.pbxproj
@@ -0,0 +1,346 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 03644E9213611C720015EC74 /* magnifier-ranged-hi@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03644E8E13611C720015EC74 /* magnifier-ranged-hi@2x.png */; };
+ 03644E9313611C720015EC74 /* magnifier-ranged-lo-stemless@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03644E8F13611C720015EC74 /* magnifier-ranged-lo-stemless@2x.png */; };
+ 03644E9413611C720015EC74 /* magnifier-ranged-lo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03644E9013611C720015EC74 /* magnifier-ranged-lo@2x.png */; };
+ 03644E9513611C720015EC74 /* magnifier-ranged-mask@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03644E9113611C720015EC74 /* magnifier-ranged-mask@2x.png */; };
+ 03C94662135E90E000EF024B /* drag-dot@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03C94661135E90E000EF024B /* drag-dot@2x.png */; };
+ 03CDA265135DF850003B567F /* loupe-hi@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CDA262135DF850003B567F /* loupe-hi@2x.png */; };
+ 03CDA266135DF850003B567F /* loupe-lo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CDA263135DF850003B567F /* loupe-lo@2x.png */; };
+ 03CDA267135DF850003B567F /* loupe-mask@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 03CDA264135DF850003B567F /* loupe-mask@2x.png */; };
+ 03FF5ECC135CA49D00268656 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03FF5ECB135CA49D00268656 /* UIKit.framework */; };
+ 03FF5ECE135CA49D00268656 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03FF5ECD135CA49D00268656 /* Foundation.framework */; };
+ 03FF5ED0135CA49D00268656 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03FF5ECF135CA49D00268656 /* CoreGraphics.framework */; };
+ 03FF5ED6135CA49D00268656 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 03FF5ED4135CA49D00268656 /* InfoPlist.strings */; };
+ 03FF5ED9135CA49D00268656 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FF5ED8135CA49D00268656 /* main.m */; };
+ 03FF5EDC135CA49D00268656 /* EGOTextView_DemoAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FF5EDB135CA49D00268656 /* EGOTextView_DemoAppDelegate.m */; };
+ 03FF5EDF135CA49E00268656 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 03FF5EDD135CA49E00268656 /* MainWindow.xib */; };
+ 03FF5EE2135CA49E00268656 /* EGOTextView_DemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FF5EE1135CA49E00268656 /* EGOTextView_DemoViewController.m */; };
+ 03FF5EE5135CA49E00268656 /* EGOTextView_DemoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 03FF5EE3135CA49E00268656 /* EGOTextView_DemoViewController.xib */; };
+ 03FF5EEE135CA4DA00268656 /* EGOTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 03FF5EED135CA4DA00268656 /* EGOTextView.m */; };
+ 03FF5EFB135CA6AC00268656 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03FF5EFA135CA6AC00268656 /* QuartzCore.framework */; };
+ 03FF5EFD135CA6B200268656 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03FF5EFC135CA6B200268656 /* CoreText.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 03644E8E13611C720015EC74 /* magnifier-ranged-hi@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "magnifier-ranged-hi@2x.png"; sourceTree = "<group>"; };
+ 03644E8F13611C720015EC74 /* magnifier-ranged-lo-stemless@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "magnifier-ranged-lo-stemless@2x.png"; sourceTree = "<group>"; };
+ 03644E9013611C720015EC74 /* magnifier-ranged-lo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "magnifier-ranged-lo@2x.png"; sourceTree = "<group>"; };
+ 03644E9113611C720015EC74 /* magnifier-ranged-mask@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "magnifier-ranged-mask@2x.png"; sourceTree = "<group>"; };
+ 03C94661135E90E000EF024B /* drag-dot@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "drag-dot@2x.png"; sourceTree = "<group>"; };
+ 03CDA262135DF850003B567F /* loupe-hi@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "loupe-hi@2x.png"; sourceTree = "<group>"; };
+ 03CDA263135DF850003B567F /* loupe-lo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "loupe-lo@2x.png"; sourceTree = "<group>"; };
+ 03CDA264135DF850003B567F /* loupe-mask@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "loupe-mask@2x.png"; sourceTree = "<group>"; };
+ 03FF5EC7135CA49D00268656 /* EGOTextView_Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EGOTextView_Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 03FF5ECB135CA49D00268656 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 03FF5ECD135CA49D00268656 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 03FF5ECF135CA49D00268656 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 03FF5ED3135CA49D00268656 /* EGOTextView_Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "EGOTextView_Demo-Info.plist"; sourceTree = "<group>"; };
+ 03FF5ED5135CA49D00268656 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+ 03FF5ED7135CA49D00268656 /* EGOTextView_Demo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "EGOTextView_Demo-Prefix.pch"; sourceTree = "<group>"; };
+ 03FF5ED8135CA49D00268656 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 03FF5EDA135CA49D00268656 /* EGOTextView_DemoAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EGOTextView_DemoAppDelegate.h; sourceTree = "<group>"; };
+ 03FF5EDB135CA49D00268656 /* EGOTextView_DemoAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EGOTextView_DemoAppDelegate.m; sourceTree = "<group>"; };
+ 03FF5EDE135CA49E00268656 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = "<group>"; };
+ 03FF5EE0135CA49E00268656 /* EGOTextView_DemoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EGOTextView_DemoViewController.h; sourceTree = "<group>"; };
+ 03FF5EE1135CA49E00268656 /* EGOTextView_DemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EGOTextView_DemoViewController.m; sourceTree = "<group>"; };
+ 03FF5EE4135CA49E00268656 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/EGOTextView_DemoViewController.xib; sourceTree = "<group>"; };
+ 03FF5EEC135CA4DA00268656 /* EGOTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EGOTextView.h; sourceTree = "<group>"; };
+ 03FF5EED135CA4DA00268656 /* EGOTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EGOTextView.m; sourceTree = "<group>"; };
+ 03FF5EFA135CA6AC00268656 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ 03FF5EFC135CA6B200268656 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 03FF5EC4135CA49D00268656 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 03FF5EFD135CA6B200268656 /* CoreText.framework in Frameworks */,
+ 03FF5EFB135CA6AC00268656 /* QuartzCore.framework in Frameworks */,
+ 03FF5ECC135CA49D00268656 /* UIKit.framework in Frameworks */,
+ 03FF5ECE135CA49D00268656 /* Foundation.framework in Frameworks */,
+ 03FF5ED0135CA49D00268656 /* CoreGraphics.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 03CDA261135DF850003B567F /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 03644E8E13611C720015EC74 /* magnifier-ranged-hi@2x.png */,
+ 03644E8F13611C720015EC74 /* magnifier-ranged-lo-stemless@2x.png */,
+ 03644E9013611C720015EC74 /* magnifier-ranged-lo@2x.png */,
+ 03644E9113611C720015EC74 /* magnifier-ranged-mask@2x.png */,
+ 03C94661135E90E000EF024B /* drag-dot@2x.png */,
+ 03CDA262135DF850003B567F /* loupe-hi@2x.png */,
+ 03CDA263135DF850003B567F /* loupe-lo@2x.png */,
+ 03CDA264135DF850003B567F /* loupe-mask@2x.png */,
+ );
+ path = Resources;
+ sourceTree = "<group>";
+ };
+ 03FF5EBC135CA49D00268656 = {
+ isa = PBXGroup;
+ children = (
+ 03FF5ED1135CA49D00268656 /* EGOTextView_Demo */,
+ 03FF5ECA135CA49D00268656 /* Frameworks */,
+ 03FF5EC8135CA49D00268656 /* Products */,
+ 03FF5EFC135CA6B200268656 /* CoreText.framework */,
+ 03FF5EFA135CA6AC00268656 /* QuartzCore.framework */,
+ );
+ sourceTree = "<group>";
+ };
+ 03FF5EC8135CA49D00268656 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 03FF5EC7135CA49D00268656 /* EGOTextView_Demo.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 03FF5ECA135CA49D00268656 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 03FF5ECB135CA49D00268656 /* UIKit.framework */,
+ 03FF5ECD135CA49D00268656 /* Foundation.framework */,
+ 03FF5ECF135CA49D00268656 /* CoreGraphics.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 03FF5ED1135CA49D00268656 /* EGOTextView_Demo */ = {
+ isa = PBXGroup;
+ children = (
+ 03FF5EEB135CA4AC00268656 /* EGOTextView */,
+ 03FF5EDA135CA49D00268656 /* EGOTextView_DemoAppDelegate.h */,
+ 03FF5EDB135CA49D00268656 /* EGOTextView_DemoAppDelegate.m */,
+ 03FF5EDD135CA49E00268656 /* MainWindow.xib */,
+ 03FF5EE0135CA49E00268656 /* EGOTextView_DemoViewController.h */,
+ 03FF5EE1135CA49E00268656 /* EGOTextView_DemoViewController.m */,
+ 03FF5EE3135CA49E00268656 /* EGOTextView_DemoViewController.xib */,
+ 03FF5ED2135CA49D00268656 /* Supporting Files */,
+ );
+ path = EGOTextView_Demo;
+ sourceTree = "<group>";
+ };
+ 03FF5ED2135CA49D00268656 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 03FF5ED3135CA49D00268656 /* EGOTextView_Demo-Info.plist */,
+ 03FF5ED4135CA49D00268656 /* InfoPlist.strings */,
+ 03FF5ED7135CA49D00268656 /* EGOTextView_Demo-Prefix.pch */,
+ 03FF5ED8135CA49D00268656 /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ 03FF5EEB135CA4AC00268656 /* EGOTextView */ = {
+ isa = PBXGroup;
+ children = (
+ 03CDA261135DF850003B567F /* Resources */,
+ 03FF5EEC135CA4DA00268656 /* EGOTextView.h */,
+ 03FF5EED135CA4DA00268656 /* EGOTextView.m */,
+ );
+ path = EGOTextView;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 03FF5EC6135CA49D00268656 /* EGOTextView_Demo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 03FF5EE8135CA49E00268656 /* Build configuration list for PBXNativeTarget "EGOTextView_Demo" */;
+ buildPhases = (
+ 03FF5EC3135CA49D00268656 /* Sources */,
+ 03FF5EC4135CA49D00268656 /* Frameworks */,
+ 03FF5EC5135CA49D00268656 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = EGOTextView_Demo;
+ productName = EGOTextView_Demo;
+ productReference = 03FF5EC7135CA49D00268656 /* EGOTextView_Demo.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 03FF5EBE135CA49D00268656 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 03FF5EC1135CA49D00268656 /* Build configuration list for PBXProject "EGOTextView_Demo" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 03FF5EBC135CA49D00268656;
+ productRefGroup = 03FF5EC8135CA49D00268656 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 03FF5EC6135CA49D00268656 /* EGOTextView_Demo */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 03FF5EC5135CA49D00268656 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 03FF5ED6135CA49D00268656 /* InfoPlist.strings in Resources */,
+ 03FF5EDF135CA49E00268656 /* MainWindow.xib in Resources */,
+ 03FF5EE5135CA49E00268656 /* EGOTextView_DemoViewController.xib in Resources */,
+ 03CDA265135DF850003B567F /* loupe-hi@2x.png in Resources */,
+ 03CDA266135DF850003B567F /* loupe-lo@2x.png in Resources */,
+ 03CDA267135DF850003B567F /* loupe-mask@2x.png in Resources */,
+ 03C94662135E90E000EF024B /* drag-dot@2x.png in Resources */,
+ 03644E9213611C720015EC74 /* magnifier-ranged-hi@2x.png in Resources */,
+ 03644E9313611C720015EC74 /* magnifier-ranged-lo-stemless@2x.png in Resources */,
+ 03644E9413611C720015EC74 /* magnifier-ranged-lo@2x.png in Resources */,
+ 03644E9513611C720015EC74 /* magnifier-ranged-mask@2x.png in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 03FF5EC3135CA49D00268656 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 03FF5ED9135CA49D00268656 /* main.m in Sources */,
+ 03FF5EDC135CA49D00268656 /* EGOTextView_DemoAppDelegate.m in Sources */,
+ 03FF5EE2135CA49E00268656 /* EGOTextView_DemoViewController.m in Sources */,
+ 03FF5EEE135CA4DA00268656 /* EGOTextView.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 03FF5ED4135CA49D00268656 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 03FF5ED5135CA49D00268656 /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "<group>";
+ };
+ 03FF5EDD135CA49E00268656 /* MainWindow.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 03FF5EDE135CA49E00268656 /* en */,
+ );
+ name = MainWindow.xib;
+ sourceTree = "<group>";
+ };
+ 03FF5EE3135CA49E00268656 /* EGOTextView_DemoViewController.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 03FF5EE4135CA49E00268656 /* en */,
+ );
+ name = EGOTextView_DemoViewController.xib;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 03FF5EE6135CA49E00268656 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvmgcc42;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 4.2;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 03FF5EE7135CA49E00268656 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = com.apple.compilers.llvmgcc42;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 4.2;
+ OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+ SDKROOT = iphoneos;
+ };
+ name = Release;
+ };
+ 03FF5EE9135CA49E00268656 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "EGOTextView_Demo/EGOTextView_Demo-Prefix.pch";
+ INFOPLIST_FILE = "EGOTextView_Demo/EGOTextView_Demo-Info.plist";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ 03FF5EEA135CA49E00268656 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "EGOTextView_Demo/EGOTextView_Demo-Prefix.pch";
+ INFOPLIST_FILE = "EGOTextView_Demo/EGOTextView_Demo-Info.plist";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ VALIDATE_PRODUCT = YES;
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 03FF5EC1135CA49D00268656 /* Build configuration list for PBXProject "EGOTextView_Demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 03FF5EE6135CA49E00268656 /* Debug */,
+ 03FF5EE7135CA49E00268656 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 03FF5EE8135CA49E00268656 /* Build configuration list for PBXNativeTarget "EGOTextView_Demo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 03FF5EE9135CA49E00268656 /* Debug */,
+ 03FF5EEA135CA49E00268656 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 03FF5EBE135CA49D00268656 /* Project object */;
+}
View
7 EGOTextView_Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:EGOTextView_Demo.xcodeproj">
+ </FileRef>
+</Workspace>
View
29,687 ...xcodeproj/project.xcworkspace/xcuserdata/devin.xcuserdatad/UserInterfaceState.xcuserstate
29,687 additions, 0 deletions not shown
View
10 ...o.xcodeproj/project.xcworkspace/xcuserdata/devin.xcuserdatad/WorkspaceSettings.xcsettings
@@ -0,0 +1,10 @@
+<?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>IDEWorkspaceUserSettings_HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
+ <true/>
+ <key>IDEWorkspaceUserSettings_SnapshotAutomaticallyBeforeSignificantChanges</key>
+ <false/>
+</dict>
+</plist>
View
23 EGOTextView_Demo.xcodeproj/xcuserdata/devin.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Bucket
+ type = "1"
+ version = "1.0">
+ <SymbolicBreakpoints>
+ <SymbolicBreakpoint
+ shouldBeEnabled = "Yes"
+ ignoreCount = "0"
+ continueAfterRunningActions = "No"
+ symbolName = "malloc_error_break"
+ moduleName = "libSystem.B.dylib">
+ </SymbolicBreakpoint>
+ </SymbolicBreakpoints>
+ <ExceptionBreakpoints>
+ <ExceptionBreakpoint
+ shouldBeEnabled = "No"
+ ignoreCount = "0"
+ continueAfterRunningActions = "No"
+ scope = "0"
+ stopOnStyle = "0">
+ </ExceptionBreakpoint>
+ </ExceptionBreakpoints>
+</Bucket>
View
72 EGOTextView_Demo.xcodeproj/xcuserdata/devin.xcuserdatad/xcschemes/EGOTextView_Demo.xcscheme
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "03FF5EC6135CA49D00268656"
+ BuildableName = "EGOTextView_Demo.app"
+ BlueprintName = "EGOTextView_Demo"
+ ReferencedContainer = "container:EGOTextView_Demo.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Debug">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Debug">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "03FF5EC6135CA49D00268656"
+ BuildableName = "EGOTextView_Demo.app"
+ BlueprintName = "EGOTextView_Demo"
+ ReferencedContainer = "container:EGOTextView_Demo.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "03FF5EC6135CA49D00268656"
+ BuildableName = "EGOTextView_Demo.app"
+ BlueprintName = "EGOTextView_Demo"
+ ReferencedContainer = "container:EGOTextView_Demo.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
View
22 EGOTextView_Demo.xcodeproj/xcuserdata/devin.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,22 @@
+<?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>EGOTextView_Demo.xcscheme</key>
+ <dict>
+ <key>orderHint</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <key>SuppressBuildableAutocreation</key>
+ <dict>
+ <key>03FF5EC6135CA49D00268656</key>
+ <dict>
+ <key>primary</key>
+ <true/>
+ </dict>
+ </dict>
+</dict>
+</plist>
View
BIN  EGOTextView_Demo/.DS_Store
Binary file not shown
View
64 EGOTextView_Demo/EGOTextView/EGOTextView.h
@@ -0,0 +1,64 @@
+//
+// EGOTextView.h
+// EGOTextView_Demo
+//
+// Created by Devin Doty on 4/18/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <CoreText/CoreText.h>
+
+@class EGOTextView;
+@protocol EGOTextViewDelegate <NSObject, UIScrollViewDelegate>
+@optional
+
+- (BOOL)textViewShouldBeginEditing:(EGOTextView *)textView;
+- (BOOL)textViewShouldEndEditing:(EGOTextView *)textView;
+
+- (void)textViewDidBeginEditing:(EGOTextView *)textView;
+- (void)textViewDidEndEditing:(EGOTextView *)textView;
+
+- (BOOL)textView:(EGOTextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
+- (void)textViewDidChange:(EGOTextView *)textView;
+
+- (void)textViewDidChangeSelection:(EGOTextView *)textView;
+
+@end
+
+@class EGOCaretView, EGOContentView, EGOTextWindow, EGOMagnifyView, EGOSelectionView;
+@interface EGOTextView : UIScrollView <UITextInputTraits, UITextInput> {
+@private
+ NSAttributedString *_attributedString;
+ UIFont *_font;
+ BOOL _editing;
+ BOOL _editable;
+ BOOL _spellCheck;
+
+ NSRange _markedRange;
+ NSRange _selectedRange;
+ NSRange _correctionRange;
+
+ CTFramesetterRef _framesetter;
+ CTFrameRef _frame;
+ UILongPressGestureRecognizer *_longPress;
+
+ EGOContentView *_textContentView;
+ EGOTextWindow *_textWindow;
+ EGOCaretView *_caretView;
+ EGOSelectionView *_selectionView;
+
+}
+
+@property(nonatomic,assign) id <EGOTextViewDelegate> delegate;
+@property(nonatomic,copy) NSAttributedString *attributedString;
+@property(nonatomic,retain) UIFont *font; // ignored when attributedString is not nil
+@property(nonatomic,getter=isEditing) BOOL editing; //default NO
+@property(nonatomic,getter=isEditable) BOOL editable; //default YES
+@property(nonatomic) NSRange selectedRange;
+@property(nonatomic) NSRange markedRange;
+
+- (BOOL)hasText;
+- (void)setText:(NSString*)text; // creates an attributed string with default attributes
+
+@end
View
2,319 EGOTextView_Demo/EGOTextView/EGOTextView.m
@@ -0,0 +1,2319 @@
+//
+// EGOTextView.m
+// EGOTextView_Demo
+//
+// Created by Devin Doty on 4/18/11.
+// Copyright 2011 __MyCompanyName__. All rights reserved.
+//
+
+#import "EGOTextView.h"
+#import <UIKit/UITextChecker.h>
+#import <QuartzCore/QuartzCore.h>
+#include <objc/runtime.h>
+
+typedef enum {
+ EGOWindowLoupe = 0,
+ EGOWindowMagnify,
+} EGOWindowType;
+
+typedef enum {
+ EGOSelectionTypeLeft=0,
+ EGOSelectionTypeRight,
+} EGOSelectionType;
+
+#pragma mark EGOContentView definition
+
+@interface EGOContentView : UIView {
+@private
+ id _delegate;
+}
+@property(nonatomic,assign) id delegate;
+@end
+
+#pragma mark EGOCaretView definition
+
+@interface EGOCaretView : UIView {
+ NSTimer *_blinkTimer;
+}
+
+- (void)delayBlink;
+- (void)show;
+@end
+
+
+#pragma mark EGOLoupeView definition
+
+@interface EGOLoupeView : UIView {
+@private
+ UIImage *_contentImage;
+}
+- (void)setContentImage:(UIImage*)image;
+@end
+
+
+#pragma mark MagnifyView definition
+
+@interface EGOMagnifyView : UIView {
+@private
+ UIImage *_contentImage;
+}
+- (void)setContentImage:(UIImage*)image;
+@end
+
+
+#pragma mark EGOTextWindow definition
+
+@interface EGOTextWindow : UIWindow {
+@private
+ UIView *_view;
+ EGOWindowType _type;
+ EGOSelectionType _selectionType;
+ BOOL _showing;
+
+}
+@property(nonatomic,assign) EGOWindowType type;
+@property(nonatomic,assign) EGOSelectionType selectionType;
+@property(nonatomic,readonly,getter=isShowing) BOOL showing;
+- (void)setType:(EGOWindowType)type;
+- (void)renderWithContentView:(UIView*)view fromRect:(CGRect)rect;
+- (void)showFromView:(UIView*)view rect:(CGRect)rect;
+- (void)hide:(BOOL)animated;
+@end
+
+
+#pragma mark EGOSelectionView definition
+
+@interface EGOSelectionView : UIView {
+@private
+ UIView *_leftDot;
+ UIView *_rightDot;
+ UIView *_leftCaret;
+ UIView *_rightCaret;
+}
+- (void)setBeginCaret:(CGRect)begin endCaret:(CGRect)rect;
+@end
+
+#pragma mark UITextPosition definition
+
+@interface IndexedPosition : UITextPosition {
+ NSUInteger _index;
+ id <UITextInputDelegate> _inputDelegate;
+}
+
+@property (nonatomic) NSUInteger index;
++ (IndexedPosition *)positionWithIndex:(NSUInteger)index;
+
+@end
+
+#pragma mark UITextRange definition
+
+@interface IndexedRange : UITextRange {
+ NSRange _range;
+}
+
+@property (nonatomic) NSRange range;
++ (IndexedRange *)rangeWithNSRange:(NSRange)range;
+@end
+
+#pragma mark EGOTextView private
+
+@interface EGOTextView (Private)
+
+ NSMutableAttributedString *_mutableAttributedString;
+ NSDictionary *_markedTextStyle;
+ id <UITextInputDelegate> _inputDelegate;
+ UITextInputStringTokenizer *_tokenizer;
+ UITextChecker *_textChecker;
+
+
+@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
+@property(nonatomic) UITextAutocorrectionType autocorrectionType;
+@property(nonatomic) UIKeyboardType keyboardType;
+@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
+@property(nonatomic) UIReturnKeyType returnKeyType;
+@property(nonatomic) BOOL enablesReturnKeyAutomatically;
+
+- (CGRect)caretRectForIndex:(int)index;
+- (CGRect)firstRectForNSRange:(NSRange)range;
+- (NSInteger)closestIndexToPoint:(CGPoint)point;
+- (NSInteger)closestWhiteSpaceIndexToPoint:(CGPoint)point;
+- (NSRange)characterRangeAtPoint_:(CGPoint)point;
+- (void)checkSpelling;
+- (void)textChanged;
+- (void)removeCorrectionAttributesForRange:(NSRange)range;
+- (void)insertCorrectionAttributesForRange:(NSRange)range;
+
++ (UIColor *)selectionColor;
++ (UIColor *)spellingSelectionColor;
++ (UIColor *)caretColor;
+@end
+
+@interface EGOTextView ()
+@property(nonatomic,retain) NSDictionary *defaultAttributes;
+@property(nonatomic,retain) NSDictionary *correctionAttributes;
+@property(nonatomic,retain) NSMutableDictionary *menuItemActions;
+@property(nonatomic) NSRange correctionRange;
+@end
+
+
+@implementation EGOTextView
+
+@synthesize delegate;
+@synthesize attributedString=_attributedString;
+@synthesize font=_font;
+@synthesize editing=_editing;
+@synthesize editable=_editable;
+@synthesize markedRange=_markedRange;
+@synthesize selectedRange=_selectedRange;
+@synthesize correctionRange=_correctionRange;
+@synthesize defaultAttributes=_defaultAttributes;
+@synthesize correctionAttributes=_correctionAttributes;
+@synthesize markedTextStyle=_markedTextStyle;
+@synthesize inputDelegate=_inputDelegate;
+@synthesize menuItemActions;
+
+@synthesize autocapitalizationType;
+@synthesize autocorrectionType;
+@synthesize keyboardType;
+@synthesize keyboardAppearance;
+@synthesize returnKeyType;
+@synthesize enablesReturnKeyAutomatically;
+
+- (id)initWithFrame:(CGRect)frame {
+ if ((self = [super initWithFrame:frame])) {
+
+ [self setText:@""];
+ self.alwaysBounceVertical = YES;
+ self.editable = YES;
+ self.font = [UIFont systemFontOfSize:17];
+ self.backgroundColor = [UIColor whiteColor];
+ self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+
+ EGOContentView *contentView = [[EGOContentView alloc] initWithFrame:CGRectInset(self.bounds, 8.0f, 8.0f)];
+ contentView.autoresizingMask = 0;
+ contentView.delegate = self;
+ [self addSubview:contentView];
+ _textContentView = [contentView retain];
+ [contentView release];
+
+ UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
+ [self addGestureRecognizer:gesture];
+ [gesture release];
+ _longPress = gesture;
+
+ }
+ return self;
+}
+
+- (id)init {
+ if ((self = [self initWithFrame:CGRectZero])) {}
+ return self;
+}
+
+- (void)clearPreviousLayoutInformation {
+
+ if (_framesetter != NULL) {
+ CFRelease(_framesetter);
+ _framesetter = NULL;
+ }
+
+ if (_frame != NULL) {
+ CFRelease(_frame);
+ _frame = NULL;
+ }
+}
+
+- (void)setFont:(UIFont *)font {
+
+ UIFont *oldFont = _font;
+ _font = [font retain];
+ [oldFont release];
+
+ CTFontRef ctFont = CTFontCreateWithName((CFStringRef) self.font.fontName, self.font.pointSize, NULL);
+ NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:(id)ctFont, (NSString *)kCTFontAttributeName, (id)[UIColor blackColor].CGColor, kCTForegroundColorAttributeName, nil];
+ self.defaultAttributes = dictionary;
+ [dictionary release];
+ CFRelease(ctFont);
+
+ [self textChanged];
+
+}
+
+- (CGFloat)boundingWidthForHeight:(CGFloat)height {
+
+ CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(_framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(CGFLOAT_MAX, height), NULL);
+ return suggestedSize.width;
+
+}
+
+- (CGFloat)boundingHeightForWidth:(CGFloat)width {
+
+ CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(_framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(width, CGFLOAT_MAX), NULL);
+ return suggestedSize.height;
+
+}
+
+- (void)textChanged {
+
+ if ([[UIMenuController sharedMenuController] isMenuVisible]) {
+ [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
+ }
+
+ CTFramesetterRef framesetter = _framesetter;
+ _framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self.attributedString);
+ if (framesetter!=NULL) {
+ CFRelease(framesetter);
+ }
+
+ CGRect rect = _textContentView.frame;
+ CGFloat height = [self boundingHeightForWidth:rect.size.width];
+ rect.size.height = height+self.font.lineHeight;
+ _textContentView.frame = rect;
+ self.contentSize = CGSizeMake(self.frame.size.width, rect.size.height+(self.font.lineHeight*2));
+
+ UIBezierPath *path = [UIBezierPath bezierPathWithRect:_textContentView.bounds];
+
+ CTFrameRef frameRef = _frame;
+ _frame = CTFramesetterCreateFrame(_framesetter, CFRangeMake(0, 0), [path CGPath], NULL);
+ if (frameRef!=NULL) {
+ CFRelease(frameRef);
+ }
+
+ [_textContentView setNeedsDisplay];
+
+}
+
+- (NSString *)text {
+ return _attributedString.string;
+}
+
+- (void)setAttributedString:(NSAttributedString*)string {
+
+ NSAttributedString *aString = _attributedString;
+ _attributedString = [string copy];
+ [aString release], aString = nil;
+
+ [self textChanged];
+
+ if (([self.delegate respondsToSelector:@selector(textViewDidChange:)])) {
+ [self.delegate textViewDidChange:self];
+ }
+
+}
+
+- (void)setText:(NSString *)_text {
+
+ NSAttributedString *string = [[NSAttributedString alloc] initWithString:_text attributes:self.defaultAttributes];
+ [self setAttributedString:string];
+ [string release];
+
+}
+
+
+#pragma mark -
+#pragma mark Layout Methods
+
+- (NSRange)rangeIntersection:(NSRange)first withSecond:(NSRange)second {
+
+ NSRange result = NSMakeRange(NSNotFound, 0);
+
+ if (first.location > second.location) {
+ NSRange tmp = first;
+ first = second;
+ second = tmp;
+ }
+
+ if (second.location < first.location + first.length) {
+ result.location = second.location;
+ NSUInteger end = MIN(first.location + first.length, second.location + second.length);
+ result.length = end - result.location;
+ }
+
+ return result;
+}
+
+- (void)drawPathFromRects:(NSArray*)array {
+
+ if (array==nil || [array count] == 0) return;
+
+ CGMutablePathRef _path = CGPathCreateMutable();
+
+ CGRect firstRect = CGRectFromString([array lastObject]);
+ CGRect lastRect = CGRectFromString([array objectAtIndex:0]);
+ if ([array count]>1) {
+ lastRect.size.width = _textContentView.bounds.size.width-lastRect.origin.x;
+ }
+ CGPathAddRect(_path, NULL, firstRect);
+ CGPathAddRect(_path, NULL, lastRect);
+
+ if ([array count] > 1) {
+
+ CGRect fillRect = CGRectZero;
+
+ CGFloat originX = ([array count]==2) ? MIN(CGRectGetMinX(firstRect), CGRectGetMinX(lastRect)) : 0.0f;
+ CGFloat originY = firstRect.origin.y + firstRect.size.height;
+ CGFloat width = ([array count]==2) ? originX+MIN(CGRectGetMaxX(firstRect), CGRectGetMaxX(lastRect)) : _textContentView.bounds.size.width;
+ CGFloat height = MAX(0.0f, lastRect.origin.y-originY);
+
+ fillRect = CGRectMake(originX, originY, width, height);
+ CGPathAddRect(_path, NULL, fillRect);
+
+ }
+
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+ CGContextAddPath(ctx, _path);
+ CGContextFillPath(ctx);
+ CGPathRelease(_path);
+
+}
+
+- (void)drawBoundingRangeAsSelection:(NSRange)selectionRange {
+
+ if (!self.editing || selectionRange.length == 0 || selectionRange.location == NSNotFound) {
+ return;
+ }
+
+ NSMutableArray *pathRects = [[NSMutableArray alloc] init];
+ NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+ CGPoint *origins = (CGPoint*)malloc([lines count] * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, [lines count]), origins);
+ NSInteger count = [lines count];
+
+ for (int i = 0; i < count; i++) {
+
+ CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
+ CFRange lineRange = CTLineGetStringRange(line);
+ NSRange range = NSMakeRange(lineRange.location==kCFNotFound ? NSNotFound : lineRange.location, lineRange.length);
+ NSRange intersection = [self rangeIntersection:range withSecond:selectionRange];
+
+ if (intersection.location != NSNotFound && intersection.length > 0) {
+
+ CGFloat xStart = CTLineGetOffsetForStringIndex(line, intersection.location, NULL);
+ CGFloat xEnd = CTLineGetOffsetForStringIndex(line, intersection.location + intersection.length, NULL);
+
+ CGPoint origin = origins[i];
+ CGFloat ascent, descent;
+ CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
+
+ CGRect selectionRect = CGRectMake(xStart, origin.y - descent, xEnd - xStart, ascent + descent);
+
+ if (range.length==1) {
+ selectionRect.size.width = _textContentView.bounds.size.width;
+ }
+
+ [pathRects addObject:NSStringFromCGRect(selectionRect)];
+
+ }
+ }
+
+ [self drawPathFromRects:pathRects];
+ [pathRects release];
+ free(origins);
+
+}
+
+- (void)drawContentInRect:(CGRect)rect {
+
+ [[EGOTextView selectionColor] setFill];
+ [self drawBoundingRangeAsSelection:self.selectedRange];
+ [[EGOTextView spellingSelectionColor] setFill];
+ [self drawBoundingRangeAsSelection:self.correctionRange];
+
+ CGPathRef framePath = CTFrameGetPath(_frame);
+ CGRect frameRect = CGPathGetBoundingBox(framePath);
+
+ NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+ NSInteger count = [lines count];
+
+ CGPoint *origins = (CGPoint*)malloc(count * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins);
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+ for (int i = 0; i < count; i++) {
+ CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex((CFArrayRef)lines, i);
+ CGContextSetTextPosition(ctx, frameRect.origin.x + origins[i].x, frameRect.origin.y + origins[i].y);
+ CTLineDraw(line, ctx);
+ }
+ free(origins);
+
+}
+
+- (NSInteger)closestWhiteSpaceIndexToPoint:(CGPoint)point {
+
+ point = [self convertPoint:point toView:_textContentView];
+ __block NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+ NSInteger count = [lines count];
+ CGPoint *origins = (CGPoint*)malloc(count * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins);
+ __block NSRange returnRange = NSMakeRange(_attributedString.length, 0);
+
+ for (int i = 0; i < lines.count; i++) {
+ if (point.y > origins[i].y) {
+
+ CTLineRef line = (CTLineRef)[lines objectAtIndex:i];
+ CFIndex index = CTLineGetStringIndexForPosition(line, point);
+
+ char character = [_attributedString.string characterAtIndex:MAX(0, index-1)];
+ if (character == '\n' || character == ' ') {
+ returnRange = NSMakeRange(index, 0);
+ break;
+ }
+
+ CFRange cfRange = CTLineGetStringRange(line);
+ NSRange range = NSMakeRange(cfRange.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length);
+
+ if (index==_attributedString.length) {
+ break;
+ } else if (index==range.location){
+ returnRange = NSMakeRange(index, 0);
+ break;
+ }
+
+ [_attributedString.string enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *subString, NSRange subStringRange, NSRange enclosingRange, BOOL *stop){
+
+ if ((index - enclosingRange.location <= enclosingRange.length)) {
+
+ if (subStringRange.length == 1) {
+
+ returnRange = subStringRange;
+
+ } else if (index < roundf((subStringRange.length/2))) {
+
+ returnRange = NSMakeRange(subStringRange.location, 0);
+
+ } else {
+
+ returnRange = NSMakeRange(subStringRange.location+subStringRange.length, 0);
+
+ }
+
+ *stop = YES;
+
+ }
+
+ }];
+
+ break;
+ }
+ }
+
+ free(origins);
+ return returnRange.location;
+
+}
+
+- (NSInteger)closestIndexToPoint:(CGPoint)point {
+
+ point = [self convertPoint:point toView:_textContentView];
+ NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+ NSInteger count = [lines count];
+ CGPoint *origins = (CGPoint*)malloc(count * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins);
+
+ for (int i = 0; i < lines.count; i++) {
+ if (point.y > origins[i].y) {
+ CTLineRef line = (CTLineRef)[lines objectAtIndex:i];
+ free(origins);
+ return CTLineGetStringIndexForPosition(line, point);
+ }
+ }
+
+ free(origins);
+ return [_attributedString length];
+
+}
+
+- (NSRange)characterRangeAtPoint_:(CGPoint)point {
+
+ __block NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+
+ CGPoint *origins = (CGPoint*)malloc([lines count] * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, [lines count]), origins);
+ __block NSRange returnRange = NSMakeRange(NSNotFound, 0);
+
+ for (int i = 0; i < lines.count; i++) {
+ if (point.y > origins[i].y) {
+
+ CTLineRef line = (CTLineRef)[lines objectAtIndex:i];
+ NSInteger index = CTLineGetStringIndexForPosition(line, point);
+
+ CFRange cfRange = CTLineGetStringRange(line);
+ NSRange range = NSMakeRange(cfRange.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length);
+
+ [_attributedString.string enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *subString, NSRange subStringRange, NSRange enclosingRange, BOOL *stop){
+
+ if (index - subStringRange.location <= subStringRange.length) {
+ returnRange = subStringRange;
+ *stop = YES;
+ }
+
+ }];
+ break;
+ }
+ }
+
+ free(origins);
+ return returnRange;
+
+}
+
+
+- (NSRange)characterRangeAtIndex:(NSInteger)index {
+
+ __block NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+ NSInteger count = [lines count];
+ __block NSRange returnRange = NSMakeRange(NSNotFound, 0);
+
+ for (int i=count-1; i >= 0; i--) {
+
+ __block CTLineRef line = (CTLineRef)[lines objectAtIndex:i];
+ CFRange cfRange = CTLineGetStringRange(line);
+ NSRange range = NSMakeRange(cfRange.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length == kCFNotFound ? 0 : cfRange.length);
+
+ if ((index - range.location <= range.length)) {
+
+ [_attributedString.string enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *subString, NSRange subStringRange, NSRange enclosingRange, BOOL *stop){
+
+ if (index - subStringRange.location <= subStringRange.length) {
+ returnRange = subStringRange;
+ *stop = YES;
+ }
+
+ }];
+
+ break;
+ }
+ }
+
+ return returnRange;
+
+}
+
+- (CGRect)caretRectForIndex:(NSInteger)index {
+
+ if(_attributedString==nil) return CGRectZero;
+
+ NSArray *lines = (NSArray*)CTFrameGetLines(_frame);
+
+ if (_attributedString.length == 0) {
+ CGPoint origin = CGPointMake(CGRectGetMinX(_textContentView.bounds), CGRectGetMaxY(_textContentView.bounds) - self.font.leading);
+ return CGRectMake(origin.x, origin.y - fabs(self.font.descender), 3, MAX(self.font.ascender + fabs(self.font.descender), self.font.lineHeight));
+ }
+
+ /*
+ if (_selectedRange.length > 0 && [_attributedString.string characterAtIndex:index-1] == '\n') {
+
+ CTLineRef line = (CTLineRef)[lines lastObject];
+ CFRange range = CTLineGetStringRange(line);
+ CGFloat xPos = CTLineGetOffsetForStringIndex(line, range.location, NULL);
+ CGFloat ascent, descent;
+ CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
+
+ CGPoint origin;
+ CGPoint *origins = (CGPoint*)malloc(1 * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake([lines count]-1, 0), origins);
+ origin = origins[0];
+ free(origins);
+
+ origin.y -= self.font.leading;
+ return CGRectMake(_textContentView.bounds.size.width - 3.0f, floorf(origin.y - descent), 3, MAX(floorf(ascent + descent), self.font.lineHeight));
+
+ }*/
+
+ if (index == _attributedString.length && [_attributedString.string characterAtIndex:(index - 1)] == '\n' ) {
+
+ CTLineRef line = (CTLineRef) [lines lastObject];
+ CFRange range = CTLineGetStringRange(line);
+ CGFloat xPos = CTLineGetOffsetForStringIndex(line, range.location, NULL);
+ CGFloat ascent, descent;
+ CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
+
+ CGPoint origin;
+ CGPoint *origins = (CGPoint*)malloc(1 * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake([lines count]-1, 0), origins);
+ origin = origins[0];
+ free(origins);
+
+ origin.y -= self.font.leading;
+ return CGRectMake(xPos, floorf(origin.y - descent), 3, MAX(floorf(ascent + descent), self.font.lineHeight));
+
+ }
+
+ index = MAX(index, 0);
+ index = MIN(_attributedString.string.length, index);
+
+ NSInteger count = [lines count];
+ CGPoint *origins = (CGPoint*)malloc(count * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins);
+ CGRect returnRect = CGRectZero;
+
+ for (int i=count-1; i >= 0; i--) {
+
+ CTLineRef line = (CTLineRef)[lines objectAtIndex:i];
+ CFRange range = CTLineGetStringRange(line);
+ NSRange _range = NSMakeRange(range.location == kCFNotFound ? NSNotFound : range.location, range.length == kCFNotFound ? 0 : range.length);
+
+ BOOL contains = (index - _range.location <= _range.length);
+
+ if (contains) {
+
+ if ([_attributedString.string characterAtIndex:index-1] == '\n' && _range.location!=index) {
+ index = MAX(0, index-1);
+ }
+
+ CGFloat xPos;
+ xPos = CTLineGetOffsetForStringIndex((CTLineRef)[lines objectAtIndex:i], index, NULL);
+
+ CGFloat ascent, descent;
+ CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
+
+ CGPoint origin = origins[i];
+ returnRect = CGRectMake(xPos, floorf(origin.y - descent), 3, MAX(floorf(ascent + descent), self.font.lineHeight));
+
+ break;
+ }
+ }
+
+ free(origins);
+ return returnRect;
+}
+
+- (CGRect)firstRectForNSRange:(NSRange)range {
+ NSInteger index = range.location;
+
+ NSArray *lines = (NSArray *) CTFrameGetLines(_frame);
+ NSInteger count = [lines count];
+ CGPoint *origins = (CGPoint*)malloc(count * sizeof(CGPoint));
+ CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins);
+ CGRect returnRect = CGRectNull;
+
+ for (int i = 0; i < count; i++) {
+
+ CTLineRef line = (CTLineRef) [lines objectAtIndex:i];
+ CFRange lineRange = CTLineGetStringRange(line);
+ NSInteger localIndex = index - lineRange.location;
+
+ if (localIndex >= 0 && localIndex < lineRange.length) {
+
+ NSInteger finalIndex = MIN(lineRange.location + lineRange.length, range.location + range.length);
+ CGFloat xStart = CTLineGetOffsetForStringIndex(line, index, NULL);
+ CGFloat xEnd = CTLineGetOffsetForStringIndex(line, finalIndex, NULL);
+ CGPoint origin = origins[i];
+ CGFloat ascent, descent;
+ CTLineGetTypographicBounds(line, &ascent, &descent, NULL);
+
+ returnRect = [_textContentView convertRect:CGRectMake(xStart, origin.y - descent, xEnd - xStart, ascent + descent) toView:self];
+ break;
+ }
+ }
+
+ free(origins);
+ return returnRect;
+}
+
+
+#pragma mark -
+#pragma mark Text Selection
+
+- (void)selectionChanged {
+
+ if (!self.editing) {
+ [_caretView removeFromSuperview];
+ return;
+ }
+
+ if (self.selectedRange.length == 0) {
+
+ if (_selectionView!=nil) {
+ [_selectionView removeFromSuperview];
+ _selectionView=nil;
+ }
+
+ if (!_caretView.superview) {
+ [_textContentView addSubview:_caretView];
+ [_textContentView setNeedsDisplay];
+ }
+
+ _caretView.frame = [self caretRectForIndex:self.selectedRange.location];
+ [_caretView delayBlink];
+
+ CGRect frame = _caretView.frame;
+ frame.origin.y -= (self.font.lineHeight*2);
+ [self scrollRectToVisible:[_textContentView convertRect:frame toView:self] animated:YES];
+
+ [_textContentView setNeedsDisplay];
+
+ _longPress.minimumPressDuration = 0.5f;
+
+ } else {
+
+ _longPress.minimumPressDuration = 0.1f;
+
+ if (_selectionView==nil) {
+ EGOSelectionView *view = [[EGOSelectionView alloc] initWithFrame:_textContentView.bounds];
+ [_textContentView addSubview:view];
+ _selectionView=view;
+ [view release];
+ }
+
+ if (_caretView.superview) {
+ [_caretView removeFromSuperview];
+ }
+
+ CGRect begin = [self caretRectForIndex:_selectedRange.location];
+ CGRect end = [self caretRectForIndex:_selectedRange.location+_selectedRange.length];
+ [_selectionView setBeginCaret:begin endCaret:end];
+
+ [_textContentView setNeedsDisplay];
+
+ }
+
+ if (self.markedRange.location != NSNotFound) {
+ [_textContentView setNeedsDisplay];
+ }
+}
+
+- (NSRange)markedRange {
+ return _markedRange;
+}
+
+- (void)setMarkedRange:(NSRange)range {
+ _markedRange = range;
+ //[self selectionChanged];
+}
+
+- (NSRange)selectedRange {
+ return _selectedRange;
+}
+
+- (void)setSelectedRange:(NSRange)range {
+ _selectedRange = range;
+ [self selectionChanged];
+}
+
+- (void)setCorrectionRange:(NSRange)range {
+
+ if (NSEqualRanges(range, _correctionRange) && range.location == NSNotFound && range.length == 0) {
+ _correctionRange = range;
+ return;
+ }
+
+ _correctionRange = range;
+ if (range.location != NSNotFound && range.length > 0) {
+
+ if (_caretView.superview) {
+ [_caretView removeFromSuperview];
+ }
+
+ [self removeCorrectionAttributesForRange:_correctionRange];
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
+ NSString *string = [_attributedString.string substringWithRange:range];
+ NSString *theLanguage = [[UITextChecker availableLanguages] objectAtIndex:0];
+ if (!theLanguage)
+ theLanguage = @"en_US";
+ NSArray *guesses = [_textChecker guessesForWordRange:range inString:string language:theLanguage];
+
+ if (guesses!=nil && [guesses count]>0) {
+
+ NSMutableArray *items = [[NSMutableArray alloc] init];
+
+ if (self.menuItemActions==nil) {
+ self.menuItemActions = [NSMutableDictionary dictionary];
+ }
+
+ for (NSString *word in guesses){
+
+ NSString *selString = [NSString stringWithFormat:@"spellCheckMenu_%i:", [word hash]];
+ SEL sel = sel_registerName([selString UTF8String]);
+
+ [self.menuItemActions setObject:word forKey:NSStringFromSelector(sel)];
+ class_addMethod([self class], sel, [[self class] instanceMethodForSelector:@selector(spellingCorrection:)], "v@:@");
+
+ UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:word action:sel];
+ [items addObject:item];
+ [item release];
+ if ([items count]>=4) {
+ break;
+ }
+ }
+
+ [menuController setMenuItems:items];
+ [items release];
+
+ [menuController setTargetRect:[self firstRectForNSRange:_correctionRange] inView:self];
+ [menuController setMenuVisible:YES animated:YES];
+
+
+ } else {
+
+ UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:@"No Replacements Found" action:@selector(spellCheckMenuEmpty:)];
+ [menuController setMenuItems:[NSArray arrayWithObject:item]];
+ [item release];
+
+ [menuController setTargetRect:[self firstRectForNSRange:_correctionRange] inView:self];
+ [menuController setMenuVisible:YES animated:YES];
+
+ }
+
+ } else {
+
+ if (!_caretView.superview) {
+ [_textContentView addSubview:_caretView];
+ [_caretView delayBlink];
+ }
+
+ }
+
+ [_textContentView setNeedsDisplay];
+
+}
+
+- (void)setEditing:(BOOL)editing {
+ _editing = editing;
+ [self selectionChanged];
+}
+
+- (void)setEditable:(BOOL)editable {
+
+ if (editable) {
+
+ if (_caretView==nil) {
+ _caretView = [[EGOCaretView alloc] initWithFrame:CGRectZero];
+ }
+
+ _tokenizer = [[UITextInputStringTokenizer alloc] initWithTextInput:self];
+ _textChecker = [[UITextChecker alloc] init];
+ _mutableAttributedString = [[NSMutableAttributedString alloc] init];
+
+ NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:(int)(kCTUnderlineStyleThick|kCTUnderlinePatternDot)], kCTUnderlineStyleAttributeName, (id)[UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:1.0f].CGColor, kCTUnderlineColorAttributeName, nil];
+ self.correctionAttributes = dictionary;
+ [dictionary release];
+
+ } else {
+
+ if (_caretView) {
+ [_caretView removeFromSuperview];
+ [_caretView release], _caretView=nil;
+ }
+
+ self.correctionAttributes=nil;
+ [_textChecker release], _textChecker=nil;
+ [_tokenizer release], _tokenizer=nil;
+ [_mutableAttributedString release], _mutableAttributedString=nil;
+
+ }
+ _editable = editable;
+
+}
+
++ (UIColor*)selectionColor {
+ static UIColor *color = nil;
+ if (color == nil) {
+ color = [[UIColor colorWithRed:0.800f green:0.867f blue:0.929f alpha:1.0f] retain];
+ }
+ return color;
+}
+
++ (UIColor*)caretColor {
+ static UIColor *color = nil;
+ if (color == nil) {
+ color = [[UIColor colorWithRed:0.25 green:0.50 blue:1.0 alpha:1.0] retain];
+ }
+ return color;
+}
+
++ (UIColor*)spellingSelectionColor {
+ static UIColor *color = nil;
+ if (color == nil) {
+ color = [[UIColor colorWithRed:1.000f green:0.851f blue:0.851f alpha:1.0f] retain];
+ }
+ return color;
+}
+
+
+#pragma mark -
+#pragma mark UITextInput methods
+
+#pragma mark UITextInput - Replacing and Returning Text
+
+- (NSString *)textInRange:(UITextRange *)range {
+ IndexedRange *r = (IndexedRange *)range;
+ return ([_attributedString.string substringWithRange:r.range]);
+}
+
+- (void)replaceRange:(UITextRange *)range withText:(NSString *)text {
+
+ IndexedRange *r = (IndexedRange *)range;
+
+ NSRange selectedNSRange = self.selectedRange;
+ if ((r.range.location + r.range.length) <= selectedNSRange.location) {
+ selectedNSRange.location -= (r.range.length - text.length);
+ } else {
+ selectedNSRange = [self rangeIntersection:r.range withSecond:_selectedRange];
+ }
+
+ [_mutableAttributedString replaceCharactersInRange:r.range withString:text];
+ self.attributedString = _mutableAttributedString;
+ self.selectedRange = selectedNSRange;
+
+}
+
+
+#pragma mark UITextInput - Working with Marked and Selected Text
+
+- (UITextRange *)selectedTextRange {
+ return [IndexedRange rangeWithNSRange:self.selectedRange];
+}
+
+- (void)setSelectedTextRange:(UITextRange *)range {
+ IndexedRange *r = (IndexedRange *)range;
+ self.selectedRange = r.range;
+}
+
+- (UITextRange *)markedTextRange {
+ return [IndexedRange rangeWithNSRange:self.markedRange];
+}
+
+- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange {
+ NSRange selectedNSRange = self.selectedRange;
+ NSRange markedTextRange = self.markedRange;
+
+ if (markedTextRange.location != NSNotFound) {
+ if (!markedText)
+ markedText = @"";
+
+ [_mutableAttributedString replaceCharactersInRange:markedTextRange withString:markedText];
+ markedTextRange.length = markedText.length;
+
+ } else if (selectedNSRange.length > 0) {
+
+ [_mutableAttributedString replaceCharactersInRange:selectedNSRange withString:markedText];
+ markedTextRange.location = selectedNSRange.location;
+ markedTextRange.length = markedText.length;
+
+ } else {
+
+ NSAttributedString *string = [[NSAttributedString alloc] initWithString:markedText attributes:self.defaultAttributes];
+ [_mutableAttributedString insertAttributedString:string atIndex:selectedNSRange.location];
+ [string release];
+
+ markedTextRange.location = selectedNSRange.location;
+ markedTextRange.length = markedText.length;
+ }
+
+ selectedNSRange = NSMakeRange(selectedRange.location + markedTextRange.location, selectedRange.length);
+
+ self.attributedString = _attributedString;
+ self.markedRange = markedTextRange;
+ self.selectedRange = selectedNSRange;
+
+}
+
+- (void)unmarkText {
+
+ NSRange markedTextRange = self.markedRange;
+
+ if (markedTextRange.location == NSNotFound)
+ return;
+
+ markedTextRange.location = NSNotFound;
+ self.markedRange = markedTextRange;
+
+}
+
+
+#pragma mark UITextInput - Computing Text Ranges and Text Positions
+
+- (UITextPosition*)beginningOfDocument {
+ return [IndexedPosition positionWithIndex:0];
+}
+
+- (UITextPosition*)endOfDocument {
+ return [IndexedPosition positionWithIndex:_attributedString.length];
+}
+
+- (UITextRange*)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition {
+
+ IndexedPosition *from = (IndexedPosition *)fromPosition;
+ IndexedPosition *to = (IndexedPosition *)toPosition;
+ NSRange range = NSMakeRange(MIN(from.index, to.index), ABS(to.index - from.index));
+ return [IndexedRange rangeWithNSRange:range];
+
+}
+
+- (UITextPosition*)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset {
+
+ IndexedPosition *pos = (IndexedPosition *)position;
+ NSInteger end = pos.index + offset;
+
+ if (end > _attributedString.length || end < 0)
+ return nil;
+
+ return [IndexedPosition positionWithIndex:end];
+}
+
+- (UITextPosition*)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset {
+
+ IndexedPosition *pos = (IndexedPosition *)position;
+ NSInteger newPos = pos.index;
+
+ switch (direction) {
+ case UITextLayoutDirectionRight:
+ newPos += offset;
+ break;
+ case UITextLayoutDirectionLeft:
+ newPos -= offset;
+ break;
+ UITextLayoutDirectionUp:
+ UITextLayoutDirectionDown:
+ break;
+ }
+
+ if (newPos < 0)
+ newPos = 0;
+
+ if (newPos > _attributedString.length)
+ newPos = _attributedString.length;
+
+ return [IndexedPosition positionWithIndex:newPos];
+}
+
+
+#pragma mark UITextInput - Evaluating Text Positions
+
+- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other {
+ IndexedPosition *pos = (IndexedPosition *)position;
+ IndexedPosition *o = (IndexedPosition *)other;
+
+ if (pos.index == o.index) {
+ return NSOrderedSame;
+ } if (pos.index < o.index) {
+ return NSOrderedAscending;
+ } else {
+ return NSOrderedDescending;
+ }
+}
+
+- (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition {
+ IndexedPosition *f = (IndexedPosition *)from;
+ IndexedPosition *t = (IndexedPosition *)toPosition;
+ return (t.index - f.index);
+}
+
+
+#pragma mark UITextInput - Text Input Delegate and Text Input Tokenizer
+
+- (id <UITextInputTokenizer>)tokenizer {
+ return _tokenizer;
+}
+
+
+#pragma mark UITextInput - Text Layout, writing direction and position
+
+- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction {
+
+ IndexedRange *r = (IndexedRange *)range;
+ NSInteger pos = r.range.location;
+
+ switch (direction) {
+ case UITextLayoutDirectionUp:
+ case UITextLayoutDirectionLeft:
+ pos = r.range.location;
+ break;
+ case UITextLayoutDirectionRight:
+ case UITextLayoutDirectionDown:
+ pos = r.range.location + r.range.length;
+ break;
+ }
+
+ return [IndexedPosition positionWithIndex:pos];
+}
+
+- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction {
+
+ IndexedPosition *pos = (IndexedPosition *)position;
+ NSRange result = NSMakeRange(pos.index, 1);
+
+ switch (direction) {
+ case UITextLayoutDirectionUp:
+ case UITextLayoutDirectionLeft:
+ result = NSMakeRange(pos.index - 1, 1);
+ break;
+ case UITextLayoutDirectionRight:
+ case UITextLayoutDirectionDown:
+ result = NSMakeRange(pos.index, 1);
+ break;
+ }
+
+ return [IndexedRange rangeWithNSRange:result];
+}
+
+- (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction {
+ return UITextWritingDirectionLeftToRight;
+}
+
+- (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRange:(UITextRange *)range {
+ // only ltr supported for now.
+}
+
+
+#pragma mark UITextInput - Geometry
+
+- (CGRect)firstRectForRange:(UITextRange *)range {
+
+ IndexedRange *r = (IndexedRange *)range;
+ return [self firstRectForNSRange:r.range];
+}
+
+- (CGRect)caretRectForPosition:(UITextPosition *)position {
+
+ IndexedPosition *pos = (IndexedPosition *)position;
+ return [self caretRectForIndex:pos.index];
+}
+
+
+#pragma mark UITextInput - Hit testing
+
+- (UITextPosition*)closestPositionToPoint:(CGPoint)point {
+
+ IndexedPosition *position = [IndexedPosition positionWithIndex:[self closestIndexToPoint:point]];
+ return position;
+
+}
+
+- (UITextPosition*)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range {
+
+ IndexedPosition *position = [IndexedPosition positionWithIndex:[self closestIndexToPoint:point]];
+ return position;
+
+}
+
+- (UITextRange*)characterRangeAtPoint:(CGPoint)point {
+
+ IndexedRange *range = [IndexedRange rangeWithNSRange:[self characterRangeAtPoint_:point]];
+ return range;
+
+}
+
+
+#pragma mark UITextInput - Styling Information
+
+- (NSDictionary*)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction {
+ // This sample assumes all text is single-styled, so this is easy.
+ return [NSDictionary dictionaryWithObject:self.font forKey:UITextInputTextFontKey];
+}
+
+
+#pragma mark -
+#pragma mark UIKeyInput methods
+
+- (BOOL)hasText {
+ return (_attributedString.length != 0);
+}
+
+- (void)insertText:(NSString *)text {
+
+ NSRange selectedNSRange = self.selectedRange;
+ NSRange markedTextRange = self.markedRange;
+
+ NSAttributedString *newString = [[NSAttributedString alloc] initWithString:text attributes:self.defaultAttributes];
+
+ if (_correctionRange.location != NSNotFound && _correctionRange.length > 0){
+
+ [_mutableAttributedString replaceCharactersInRange:self.correctionRange withAttributedString:newString];
+ selectedNSRange.length = 0;
+ selectedNSRange.location = (self.correctionRange.location+text.length);
+ self.correctionRange = NSMakeRange(NSNotFound, 0);
+
+ } else if (markedTextRange.location != NSNotFound) {
+
+ [_mutableAttributedString replaceCharactersInRange:markedTextRange withAttributedString:newString];
+ selectedNSRange.location = markedTextRange.location + text.length;
+ selectedNSRange.length = 0;
+ markedTextRange = NSMakeRange(NSNotFound, 0);
+
+ } else if (selectedNSRange.length > 0) {
+
+ [_mutableAttributedString replaceCharactersInRange:selectedNSRange withAttributedString:newString];
+ selectedNSRange.length = 0;
+ selectedNSRange.location = (selectedNSRange.location + text.length);
+
+ } else {
+
+ [_mutableAttributedString insertAttributedString:newString atIndex:selectedNSRange.location];
+ selectedNSRange.location += text.length;
+
+ }
+
+ [newString release];
+
+ self.attributedString = _mutableAttributedString;
+ self.markedRange = markedTextRange;
+ self.selectedRange = selectedNSRange;
+
+ if (text.length > 1 || ([text isEqualToString:@" "] || [text isEqualToString:@"\n"])) {
+ [self checkSpelling];
+ }
+
+}
+
+- (void)deleteBackward {
+
+ NSRange selectedNSRange = self.selectedRange;
+ NSRange markedTextRange = self.markedRange;
+
+
+ if (_correctionRange.location != NSNotFound && _correctionRange.length > 0) {
+
+ [_mutableAttributedString beginEditing];
+ [_mutableAttributedString deleteCharactersInRange:self.correctionRange];
+ [_mutableAttributedString endEditing];
+ self.correctionRange = NSMakeRange(NSNotFound, 0);
+ selectedNSRange.length = 0;
+
+ } else if (markedTextRange.location != NSNotFound) {
+
+ [_mutableAttributedString beginEditing];
+ [_mutableAttributedString deleteCharactersInRange:selectedNSRange];
+ [_mutableAttributedString endEditing];
+
+ selectedNSRange.location = markedTextRange.location;
+ selectedNSRange.length = 0;
+ markedTextRange = NSMakeRange(NSNotFound, 0);
+
+ } else if (selectedNSRange.length > 0) {
+
+ [_mutableAttributedString beginEditing];
+ [_mutableAttributedString deleteCharactersInRange:selectedNSRange];
+ [_mutableAttributedString endEditing];
+
+ selectedNSRange.length = 0;
+
+ } else if (selectedNSRange.location > 0) {
+
+ selectedNSRange.location--;
+ selectedNSRange.length = 1;
+
+ [_mutableAttributedString beginEditing];
+ [_mutableAttributedString deleteCharactersInRange:selectedNSRange];
+ [_mutableAttributedString endEditing];
+
+ selectedNSRange.length = 0;
+
+ }
+
+ self.attributedString = _mutableAttributedString;
+ self.markedRange = markedTextRange;
+ self.selectedRange = selectedNSRange;
+
+}
+
+
+#pragma mark -
+#pragma mark SpellCheck
+
+- (void)insertCorrectionAttributesForRange:(NSRange)range {
+
+ NSMutableAttributedString *string = [_attributedString mutableCopy];
+ [string removeAttribute:(NSString*)kCTUnderlineStyleAttributeName range:range];
+ self.attributedString = string;
+ [string release];
+
+}
+
+- (void)removeCorrectionAttributesForRange:(NSRange)range {
+
+ NSMutableAttributedString *string = [_attributedString mutableCopy];
+ [string addAttributes:self.correctionAttributes range:range];
+ self.attributedString = string;
+ [string release];
+
+}
+
+- (void)checkSpellingForRange:(NSRange)range {
+
+ range = [_textChecker rangeOfMisspelledWordInString:_attributedString.string range:NSMakeRange(0, _attributedString.length) startingAt:0 wrap:YES language:@"en_US"];
+
+ if (range.location!=NSNotFound && range.length > 1) {
+
+ NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:(int)(kCTUnderlineStyleThick|kCTUnderlinePatternDot)], kCTUnderlineStyleAttributeName, (id)[UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:1.0f].CGColor, kCTUnderlineColorAttributeName, nil];
+ [_mutableAttributedString addAttributes:dictionary range:range];
+ self.attributedString = _attributedString;
+ [dictionary release];
+
+ }
+
+
+}
+
+- (void)checkSpelling {
+
+ NSInteger currentOffset = 0;
+ NSRange currentRange = NSMakeRange(0, 0);
+ NSString *theText = _attributedString.string;
+ NSRange stringRange = NSMakeRange(0, theText.length-1);
+ NSArray *guesses;
+ BOOL done = NO;
+
+ NSString *theLanguage = [[UITextChecker availableLanguages] objectAtIndex:0];
+ if (!theLanguage)
+ theLanguage = @"en_US";
+
+ while (!done) {
+
+ currentRange = [_textChecker rangeOfMisspelledWordInString:theText range:stringRange
+ startingAt:currentOffset wrap:NO language:theLanguage];
+ if (currentRange.location == NSNotFound) {
+ done = YES;
+ continue;
+ }
+ guesses = [_textChecker guessesForWordRange:currentRange inString:theText
+ language:theLanguage];
+
+
+ if (guesses!=nil) {
+ [_mutableAttributedString addAttributes:self.correctionAttributes range:currentRange];
+ }
+
+ currentOffset = currentOffset + (currentRange.length-1);
+
+ }
+
+ if (![self.attributedString isEqualToAttributedString:_mutableAttributedString]) {
+ self.attributedString = _mutableAttributedString;
+ }
+
+
+}
+
+
+#pragma mark -
+#pragma mark Gestures
+
+- (void)longPress:(UILongPressGestureRecognizer*)gesture {
+
+ if (gesture.state==UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged) {
+
+ BOOL _selection = (_selectionView!=nil);
+
+ if (!_selection && _caretView!=nil) {
+ [_caretView show];
+ }
+
+ if (_textWindow==nil) {
+
+ EGOTextWindow *window = nil;
+
+ for (EGOTextWindow *aWindow in [[UIApplication sharedApplication] windows]){
+ if ([aWindow isKindOfClass:[EGOTextWindow class]]) {
+ window = aWindow;
+ window.hidden=NO;
+ window.frame = [[UIScreen mainScreen] bounds];
+ break;
+ }
+ }
+
+ if (window==nil) {
+ window = [[EGOTextWindow alloc] initWithFrame:self.window.frame];
+ window.windowLevel = UIWindowLevelStatusBar;
+ [window makeKeyAndVisible];
+ }
+
+ _textWindow=window;
+ [_textWindow setType:_selection ? EGOWindowMagnify : EGOWindowLoupe];
+ }
+
+ CGPoint point = [gesture locationInView:self];
+ point.y -= 20.0f;
+ NSInteger index = [self closestIndexToPoint:point];
+
+ if (index!=kCFNotFound) {
+ if (_selection) {
+
+ if (gesture.state == UIGestureRecognizerStateBegan) {
+ BOOL left = NO;
+ if (index < _selectedRange.location) {
+ left = YES;
+ } else if (index > _selectedRange.location+_selectedRange.length) {
+ left = NO;
+ } else {
+
+ NSInteger leftDiff = index - _selectedRange.location;
+ NSInteger rightDiff = (_selectedRange.location+_selectedRange.length)-index;
+
+ left = (leftDiff < rightDiff);
+
+ }
+
+ _textWindow.selectionType = left ? EGOSelectionTypeLeft : EGOSelectionTypeRight;
+ }
+
+ CGRect rect = CGRectZero;
+ if (_textWindow.selectionType==EGOSelectionTypeLeft) {
+
+ NSInteger begin = MAX(0, index);
+ begin = MIN(_selectedRange.location+_selectedRange.length-1, begin);
+
+ NSInteger end = _selectedRange.location + _selectedRange.length;
+ end = MIN(_attributedString.string.length, end-begin);
+
+ self.selectedRange = NSMakeRange(begin, end);
+ rect = [self caretRectForIndex:(self.selectedRange.location)];
+
+ } else {
+
+ NSInteger length = MIN(index-_selectedRange.location, _attributedString.string.length-_selectedRange.location);
+ length = MAX(1, length);
+
+ self.selectedRange = NSMakeRange(self.selectedRange.location, length);
+ rect = [self caretRectForIndex:(self.selectedRange.location+length)];
+
+ }
+
+ if (gesture.state == UIGestureRecognizerStateBegan) {
+ [_textWindow showFromView:_textContentView rect:[_textContentView convertRect:rect toView:_textWindow]];
+ } else {
+ [_textWindow renderWithContentView:_textContentView fromRect:rect];
+ }
+
+ } else {
+
+ CGPoint location = [gesture locationInView:_textWindow];
+ CGRect rect = CGRectMake(location.x, location.y, _caretView.bounds.size.width, _caretView.bounds.size.height);
+
+ self.selectedRange = NSMakeRange(index, 0);
+
+ if (gesture.state == UIGestureRecognizerStateBegan) {
+
+ [_textWindow showFromView:_textContentView rect:rect];
+
+ } else {
+
+ [_textWindow renderWithContentView:_textContentView fromRect:rect];
+
+ }
+
+ }
+ }
+
+ } else {
+
+ if (_caretView!=nil) {
+ [_caretView delayBlink];
+ }
+
+ if ((_textWindow!=nil)) {
+ [_textWindow hide:YES];
+ _textWindow=nil;
+ }
+
+ if (self.selectedRange.length>0) {
+
+ UIMenuController *controller = [UIMenuController sharedMenuController];
+ [controller setTargetRect:_caretView.frame inView:_textContentView];
+ [controller update];
+ [controller setMenuVisible:YES animated:YES];
+
+ }
+
+ }
+
+}
+
+
+#pragma mark -
+#pragma mark Touches
+
+
+- (void)showMenu {
+
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
+ [menuController setMenuItems:nil];
+ [menuController setTargetRect:_caretView.frame inView:self];
+ [menuController update];
+ [menuController setMenuVisible:YES animated:YES];
+
+}
+
+- (void)showCorrectionMenu {
+
+ if (_editing) {
+
+ NSRange range = [self characterRangeAtIndex:self.selectedRange.location];
+ NSLog(@"char at index : %i %i", range.location, range.length);
+ if (range.location!=NSNotFound && range.length>0) {
+
+ NSString *language = [[UITextChecker availableLanguages] objectAtIndex:0];
+ if (!language)
+ language = @"en_US";
+ self.correctionRange = [_textChecker rangeOfMisspelledWordInString:_attributedString.string range:range startingAt:0 wrap:YES language:language];
+
+ }
+
+ }
+
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ [super touchesBegan:touches withEvent:event];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showMenu) object:nil];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showCorrectionMenu) object:nil];
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+ [super touchesMoved:touches withEvent:event];
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
+ [super touchesEnded:touches withEvent:event];
+
+ if ([self isEditable] && ![self isFirstResponder]) {
+ [self becomeFirstResponder];
+ return;
+ }
+
+ UIMenuController *menuController = [UIMenuController sharedMenuController];
+
+ self.correctionRange = NSMakeRange(NSNotFound, 0);
+ if (self.selectedRange.length>0) {
+ self.selectedRange = NSMakeRange(_selectedRange.location, 0);
+ }
+
+ if ([menuController isMenuVisible]) {
+ [menuController setMenuVisible:NO animated:NO];
+ return;
+ }
+
+ UITouch *touch = [touches anyObject];
+
+ if (([touch tapCount] == 2)) {
+
+ NSRange range = [self characterRangeAtPoint_:[touch locationInView:_textContentView]];
+ if (range.location!=NSNotFound && range.length>0) {
+
+ self.selectedRange = range;
+
+ if (![menuController isMenuVisible]) {
+ [menuController setMenuItems:nil];
+ [menuController setTargetRect:[self firstRectForNSRange:self.selectedRange] inView:self];
+ [menuController update];
+ [menuController setMenuVisible:YES animated:YES];
+ }
+
+ }
+
+ } else if ([touch tapCount] == 1) {
+
+ [self.inputDelegate selectionWillChange:self];
+
+ NSInteger index = [self closestWhiteSpaceIndexToPoint:[touch locationInView:self]];
+ if (index==self.selectedRange.location) {
+ [self performSelector:@selector(showMenu) withObject:nil afterDelay:0.3f];
+ } else {
+ [self performSelector:@selector(showCorrectionMenu) withObject:nil afterDelay:0.3f];
+ }
+ if (index!=kCFNotFound) {
+ self.markedRange = NSMakeRange(NSNotFound, 0);
+ self.selectedRange = NSMakeRange(index, 0);
+ }
+ [self.inputDelegate selectionDidChange:self];
+
+
+ }
+
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
+ [super touchesCancelled:touches withEvent:event];
+}
+
+
+#pragma mark -
+#pragma mark UIResponder
+
+- (BOOL)canBecomeFirstResponder {
+
+ if ([self isEditable] && ([self.delegate respondsToSelector:@selector(textViewShouldBeginEditing:)])) {
+ return [self.delegate textViewShouldBeginEditing:self];
+ }
+
+ return YES;
+}
+
+- (BOOL)becomeFirstResponder {
+
+ if (([self.delegate respondsToSelector:@selector(textViewDidBeginEditing:)])) {
+ [self.delegate textViewDidBeginEditing:self];
+ }
+
+ self.editing = YES;
+ return [super becomeFirstResponder];
+}
+
+- (BOOL)canResignFirstResponder {
+
+ if (([self.delegate respondsToSelector:@selector(textViewShouldEndEditing:)])) {
+ return [self.delegate textViewShouldEndEditing:self];
+ }
+
+ return YES;
+}
+
+- (BOOL)resignFirstResponder {
+
+ if (([self.delegate respondsToSelector:@selector(textViewDidEndEditing:)])) {
+ [self.delegate textViewDidEndEditing:self];
+ }
+
+ self.editing = NO;
+ return [super resignFirstResponder];
+
+}
+
+
+#pragma mark -
+#pragma mark Menu Actions
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
+
+ if (self.correctionRange.length>0) {
+
+ if ([NSStringFromSelector(action) hasPrefix:@"spellCheckMenu"]) {
+ return YES;
+ }
+
+ return NO;
+ }
+
+ if ((action==@selector(cut:)) || (action==@selector(delete:))) {
+ return (_selectedRange.length>0 && _editing);
+ } else if (action==@selector(copy:)) {
+ return ((_selectedRange.length>0));
+ } else if ((action == @selector(select:) || action == @selector(selectAll:))) {
+ return (_selectedRange.length==0 && [self hasText]);
+ } else if (action == @selector(paste:)) {
+ return (_editing && [[UIPasteboard generalPasteboard] containsPasteboardTypes:[NSArray arrayWithObject:@"public.utf8-plain-text"]]);
+ }
+
+ return [super canPerformAction:action withSender:sender];
+
+}
+
+- (void)spellingCorrection:(UIMenuController*)sender {
+
+ [self replaceRange:[IndexedRange rangeWithNSRange:self.correctionRange] withText:[self.menuItemActions objectForKey:NSStringFromSelector(_cmd)]];
+ self.correctionRange = NSMakeRange(NSNotFound, 0);
+ self.menuItemActions = nil;
+ [sender setMenuItems:nil];
+
+}
+
+- (void)spellCheckMenuEmpty:(id)sender{
+
+ self.correctionRange = NSMakeRange(NSNotFound, 0);
+
+}
+
+- (void)paste:(id)sender {
+
+ NSString *pasteText = [[UIPasteboard generalPasteboard] valueForPasteboardType:@"public.utf8-plain-text"];
+
+ if (pasteText!=nil) {
+
+ NSMutableAttributedString *string = [self.attributedString mutableCopy];
+ NSAttributedString *newString = [[NSAttributedString alloc] initWithString:pasteText attributes:self.defaultAttributes];
+ [string insertAttributedString:newString atIndex:_selectedRange.location];
+ [self setAttributedString:string];
+
+ NSRange range = NSMakeRange(_selectedRange.location+[newString length], 0);
+ self.selectedRange = range;
+
+ [newString release];
+ [string release];
+
+ }
+
+}
+
+- (void)menuDidHide:(NSNotification*)notification {
+
+ if (_selectionView) {
+ UIMenuController *controller = [UIMenuController sharedMenuController];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [controller update];
+ [controller setTargetRect:_selectionView.frame inView:self];
+ [controller setMenuVisible:YES animated:YES];
+ });
+ }
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidHideMenuNotification object:nil];
+
+}
+
+- (void)selectAll:(id)sender {
+
+ NSString *string = [_attributedString string];
+ NSString *trimmedString = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ self.selectedRange = [_attributedString.string rangeOfString:trimmedString];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuDidHide:) name:UIMenuControllerDidHideMenuNotification object:nil];
+
+}
+
+- (void)select:(id)sender {
+
+ NSRange range = [self characterRangeAtPoint_:_caretView.center];
+ self.selectedRange = range;
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuDidHide:) name:UIMenuControllerDidHideMenuNotification object:nil];
+
+}
+
+- (void)cut:(id)sender {
+
+ NSString *string = [_attributedString.string substringWithRange:_selectedRange];
+ [[UIPasteboard generalPasteboard] setValue:string forPasteboardType:@"public.utf8-plain-text"];
+
+ NSMutableAttributedString *mutableString = [self.attributedString mutableCopy];
+ [mutableString deleteCharactersInRange:_selectedRange];
+ [self setAttributedString:mutableString];
+ [mutableString release];
+
+ self.selectedRange = NSMakeRange(_selectedRange.location, 0);
+
+}
+
+- (void)copy:(id)sender {
+
+ NSString *string = [self.attributedString.string substringWithRange:_selectedRange];
+ [[UIPasteboard generalPasteboard] setValue:string forPasteboardType:@"public.utf8-plain-text"];
+
+}
+
+- (void)delete:(id)sender {
+
+ NSMutableAttributedString *string = [self.attributedString mutableCopy];
+ [string deleteCharactersInRange:_selectedRange];
+ [self setAttributedString:string];
+ [string release];
+
+ self.selectedRange = NSMakeRange(_selectedRange.location, 0);
+
+}
+
+- (void)replace:(id)sender {
+
+
+}
+
+
+#pragma mark -
+#pragma mark Dealloc EGOTextView
+
+- (void)dealloc {
+
+ _textWindow=nil;
+ self.font = nil;
+ self.menuItemActions=nil;
+ self.defaultAttributes=nil;
+ self.correctionAttributes=nil;
+ self.attributedString=nil;
+ self.text=nil;
+ [_caretView release];
+ [super dealloc];
+}
+
+@end
+
+#pragma mark -
+#pragma mark IndexedPosition
+
+@implementation IndexedPosition
+@synthesize index=_index;
+
++ (IndexedPosition *)positionWithIndex:(NSUInteger)index {
+ IndexedPosition *pos = [[IndexedPosition alloc] init];
+ pos.index = index;
+ return [pos autorelease];
+}
+
+@end
+
+
+#pragma mark -
+#pragma mark IndexedRange
+
+@implementation IndexedRange
+@synthesize range=_range;
+
++ (IndexedRange *)rangeWithNSRange:(NSRange)theRange {
+ if (theRange.location == NSNotFound)
+ return nil;
+
+ IndexedRange *range = [[IndexedRange alloc] init];
+ range.range = theRange;
+ return [range autorelease];
+}
+
+- (UITextPosition *)start {
+ return [IndexedPosition positionWithIndex:self.range.location];
+}
+
+- (UITextPosition *)end {
+ return [IndexedPosition positionWithIndex:(self.range.location + self.range.length)];
+}
+
+-(BOOL)isEmpty {
+ return (self.range.length == 0);
+}
+
+@end
+
+
+#pragma mark -
+#pragma mark ContentView
+
+@implementation EGOContentView
+
+@synthesize delegate=_delegate;
+
+- (id)initWithFrame:(CGRect)frame {
+ if ((self = [super initWithFrame:frame])) {
+
+ self.userInteractionEnabled = NO;
+ self.layer.geometryFlipped = YES;
+ self.backgroundColor = [UIColor whiteColor];
+
+ }
+ return self;
+}
+
+- (void)drawRect:(CGRect)rect {
+
+ [_delegate drawContentInRect:rect];
+
+}
+
+- (void)dealloc {
+ [super dealloc];
+}
+
+@end
+
+
+#pragma mark -
+#pragma mark CaretView
+
+@implementation EGOCaretView
+
+static const NSTimeInterval kInitialBlinkDelay = 0.7;
+static const NSTimeInterval kBlinkRate = 0.5;
+
+- (id)initWithFrame:(CGRect)frame {
+ if ((self = [super initWithFrame:frame])) {
+ self.backgroundColor = [EGOTextView caretColor];
+ }
+ return self;
+}
+
+- (void)blink {
+ self.hidden = !self.hidden;
+}
+
+- (void)show {
+
+ self.hidden = NO;
+ [_blinkTimer setFireDate:[NSDate distantFuture]];
+
+}
+
+- (void)didMoveToSuperview {