From c1c85145cf44ba6f767877b65eb012aeaea50376 Mon Sep 17 00:00:00 2001 From: poetwang Date: Sat, 21 Dec 2013 00:51:57 +0800 Subject: [PATCH 01/11] Add api for replace string --- EGOTextView/EGOTextView.h | 1 + EGOTextView/EGOTextView.m | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/EGOTextView/EGOTextView.h b/EGOTextView/EGOTextView.h index 67974aa..8b12ae2 100644 --- a/EGOTextView/EGOTextView.h +++ b/EGOTextView/EGOTextView.h @@ -121,5 +121,6 @@ extern NSString * const EGOTextAttachmentPlaceholderString; @property(nonatomic) NSRange markedRange; - (BOOL)hasText; +- (void)replaceNSRange:(NSRange)range withText:(NSString *)text; @end \ No newline at end of file diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index cb5b4ef..199bf41 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -384,7 +384,9 @@ - (void)setText:(NSString *)text { - (void)setAttributedString:(NSAttributedString*)string { NSAttributedString *aString = _attributedString; - _attributedString = [string copy]; + _mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:string]; + + _attributedString = _mutableAttributedString; [aString release], aString = nil; NSRange range = NSMakeRange(0, _attributedString.string.length); @@ -1111,6 +1113,12 @@ - (void)replaceRange:(UITextRange *)range withText:(NSString *)text { } +- (void)replaceNSRange:(NSRange)range withText:(NSString *)text +{ + UITextRange *r = [EGOIndexedRange rangeWithNSRange:range]; + [self replaceRange:r withText:text]; +} + // MARK: UITextInput - Working with Marked and Selected Text - (UITextRange *)selectedTextRange { From 0ac8e0c5c5027c143c90e646270df2a43026e71b Mon Sep 17 00:00:00 2001 From: poetwang Date: Sat, 21 Dec 2013 13:20:51 +0800 Subject: [PATCH 02/11] Fix Chinese input bug --- EGOTextView/EGOTextView.m | 7 ++++--- EGOTextView_Demo.xcodeproj/project.pbxproj | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 199bf41..60c6bc4 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -375,6 +375,8 @@ - (void)setText:(NSString *)text { NSAttributedString *string = [[NSAttributedString alloc] initWithString:text attributes:self.defaultAttributes]; [self setAttributedString:string]; + _mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:string]; + [string release]; [self.inputDelegate textDidChange:self]; @@ -384,9 +386,8 @@ - (void)setText:(NSString *)text { - (void)setAttributedString:(NSAttributedString*)string { NSAttributedString *aString = _attributedString; - _mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:string]; - _attributedString = _mutableAttributedString; + _attributedString = [string copy]; [aString release], aString = nil; NSRange range = NSMakeRange(0, _attributedString.string.length); @@ -1164,7 +1165,7 @@ - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRang selectedNSRange = NSMakeRange(selectedRange.location + markedTextRange.location, selectedRange.length); - self.attributedString = _attributedString; + self.attributedString = _mutableAttributedString; self.markedRange = markedTextRange; self.selectedRange = selectedNSRange; diff --git a/EGOTextView_Demo.xcodeproj/project.pbxproj b/EGOTextView_Demo.xcodeproj/project.pbxproj index 9aac921..0fe3b95 100644 --- a/EGOTextView_Demo.xcodeproj/project.pbxproj +++ b/EGOTextView_Demo.xcodeproj/project.pbxproj @@ -190,6 +190,8 @@ /* Begin PBXProject section */ 03FF5EBE135CA49D00268656 /* Project object */ = { isa = PBXProject; + attributes = { + }; buildConfigurationList = 03FF5EC1135CA49D00268656 /* Build configuration list for PBXProject "EGOTextView_Demo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; @@ -319,6 +321,7 @@ GCC_DYNAMIC_NO_PIC = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "EGOTextView_Demo/EGOTextView_Demo-Prefix.pch"; + GCC_VERSION = ""; INFOPLIST_FILE = "EGOTextView_Demo/EGOTextView_Demo-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -334,6 +337,7 @@ COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "EGOTextView_Demo/EGOTextView_Demo-Prefix.pch"; + GCC_VERSION = ""; INFOPLIST_FILE = "EGOTextView_Demo/EGOTextView_Demo-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; From 8173a733d625fadce58a613936c0b1e9860bb9ff Mon Sep 17 00:00:00 2001 From: poetwang Date: Sun, 22 Dec 2013 03:23:43 +0800 Subject: [PATCH 03/11] Fix warning --- EGOTextView/EGOTextView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 60c6bc4..f6ba99d 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -844,7 +844,7 @@ - (CGRect)caretRectForIndex:(NSInteger)index { CTLineRef line = (CTLineRef)[lines objectAtIndex:i]; CFRange cfRange = CTLineGetStringRange(line); - NSRange range = NSMakeRange(range.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length); + NSRange range = NSMakeRange(cfRange.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length); if (index >= range.location && index <= range.location+range.length) { From 2f517dfc719ef4c7e3066657cedc6a5d6fc5be71 Mon Sep 17 00:00:00 2001 From: poetwang Date: Sat, 4 Jan 2014 11:15:26 +0800 Subject: [PATCH 04/11] Fix bug for delete/backward in the end, out of range --- EGOTextView/EGOTextView.m | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index f6ba99d..d1c3758 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -975,10 +975,19 @@ - (void)selectionChanged { } - (NSRange)markedRange { + if (_markedRange.location > _mutableAttributedString.length) + _markedRange.location = _mutableAttributedString.length; + if (_markedRange.location + _markedRange.length > _mutableAttributedString.length) + _markedRange.length = _mutableAttributedString.length - _markedRange.location; return _markedRange; } - (NSRange)selectedRange { + if (_selectedRange.location > _mutableAttributedString.length) + _selectedRange.location = _mutableAttributedString.length; + if (_selectedRange.location + _selectedRange.length > _mutableAttributedString.length) + _selectedRange.length = _mutableAttributedString.length - _selectedRange.length; + return _selectedRange; } @@ -1484,13 +1493,12 @@ - (void)deleteBackward { selectedNSRange.location--; selectedNSRange.length = 1; - + [_mutableAttributedString beginEditing]; [_mutableAttributedString deleteCharactersInRange:selectedNSRange]; [_mutableAttributedString endEditing]; selectedNSRange.length = 0; - } self.attributedString = _mutableAttributedString; From e58804fa850e37efd230392213b96dbbc769bf68 Mon Sep 17 00:00:00 2001 From: poetwang Date: Sun, 5 Jan 2014 19:32:57 +0800 Subject: [PATCH 05/11] Fix bug for delete/backward in the end, out of range again --- EGOTextView/EGOTextView.m | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index d1c3758..6f0cdc5 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -974,20 +974,21 @@ - (void)selectionChanged { } +- (NSRange)checkRange:(NSRange)r +{ + if (r.location == NSNotFound) return r; + if (r.location > self.attributedString.length) + r.location = self.attributedString.length; + if (r.location + r.length > self.attributedString.length) + r.length = self.attributedString.length - r.location; + return r; +} + - (NSRange)markedRange { - if (_markedRange.location > _mutableAttributedString.length) - _markedRange.location = _mutableAttributedString.length; - if (_markedRange.location + _markedRange.length > _mutableAttributedString.length) - _markedRange.length = _mutableAttributedString.length - _markedRange.location; return _markedRange; } - (NSRange)selectedRange { - if (_selectedRange.location > _mutableAttributedString.length) - _selectedRange.location = _mutableAttributedString.length; - if (_selectedRange.location + _selectedRange.length > _mutableAttributedString.length) - _selectedRange.length = _mutableAttributedString.length - _selectedRange.length; - return _selectedRange; } @@ -998,6 +999,7 @@ - (void)setMarkedRange:(NSRange)range { - (void)setSelectedRange:(NSRange)range { _selectedRange = NSMakeRange(range.location == NSNotFound ? NSNotFound : MAX(0, range.location), range.length); + _selectedRange = [self checkRange:_selectedRange]; [self selectionChanged]; } @@ -1103,7 +1105,7 @@ + (UIColor*)spellingSelectionColor { - (NSString *)textInRange:(UITextRange *)range { EGOIndexedRange *r = (EGOIndexedRange *)range; - return ([_attributedString.string substringWithRange:r.range]); + return ([self.attributedString.string substringWithRange:[self checkRange:r.range]]); } - (void)replaceRange:(UITextRange *)range withText:(NSString *)text { @@ -1111,12 +1113,6 @@ - (void)replaceRange:(UITextRange *)range withText:(NSString *)text { EGOIndexedRange *r = (EGOIndexedRange *)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; @@ -1452,11 +1448,10 @@ - (void)deleteBackward { [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showCorrectionMenuWithoutSelection) object:nil]; - NSRange selectedNSRange = self.selectedRange; - NSRange markedTextRange = self.markedRange; - [_mutableAttributedString setAttributedString:self.attributedString]; - + NSRange selectedNSRange = [self checkRange:self.selectedRange]; + NSRange markedTextRange = [self checkRange:self.markedRange];; + if (_correctionRange.location != NSNotFound && _correctionRange.length > 0) { [_mutableAttributedString beginEditing]; @@ -2245,7 +2240,7 @@ - (void)select:(id)sender { - (void)cut:(id)sender { - NSString *string = [_attributedString.string substringWithRange:_selectedRange]; + NSString *string = [self.attributedString.string substringWithRange:self.selectedRange]; [[UIPasteboard generalPasteboard] setValue:string forPasteboardType:@"public.utf8-plain-text"]; [_mutableAttributedString setAttributedString:self.attributedString]; @@ -2261,7 +2256,7 @@ - (void)cut:(id)sender { - (void)copy:(id)sender { - NSString *string = [self.attributedString.string substringWithRange:_selectedRange]; + NSString *string = [self.attributedString.string substringWithRange:self.selectedRange]; [[UIPasteboard generalPasteboard] setValue:string forPasteboardType:@"public.utf8-plain-text"]; } From 24ae69e2c1205387bec6b56b60d4289d6c298338 Mon Sep 17 00:00:00 2001 From: poetwang Date: Wed, 15 Jan 2014 22:16:09 +0800 Subject: [PATCH 06/11] Fix bugs in deleteBackward chinese --- EGOTextView/EGOTextView.m | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 6f0cdc5..d5a108b 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -993,7 +993,8 @@ - (NSRange)selectedRange { } - (void)setMarkedRange:(NSRange)range { - _markedRange = range; + _markedRange = NSMakeRange(range.location == NSNotFound ? NSNotFound : MAX(0, range.location), range.length); + _markedRange = [self checkRange:_markedRange]; //[self selectionChanged]; } @@ -1399,11 +1400,9 @@ - (void)insertText:(NSString *)text { NSRange selectedNSRange = self.selectedRange; NSRange markedTextRange = self.markedRange; - [_mutableAttributedString setAttributedString:self.attributedString]; - NSAttributedString *newString = [[NSAttributedString alloc] initWithString:text attributes:self.defaultAttributes]; - + if (_correctionRange.location != NSNotFound && _correctionRange.length > 0){ [_mutableAttributedString replaceCharactersInRange:self.correctionRange withAttributedString:newString]; @@ -1441,7 +1440,6 @@ - (void)insertText:(NSString *)text { [self checkSpellingForRange:[self characterRangeAtIndex:self.selectedRange.location-1]]; [self checkLinksForRange:NSMakeRange(0, self.attributedString.length)]; } - } - (void)deleteBackward { @@ -1451,9 +1449,12 @@ - (void)deleteBackward { [_mutableAttributedString setAttributedString:self.attributedString]; NSRange selectedNSRange = [self checkRange:self.selectedRange]; NSRange markedTextRange = [self checkRange:self.markedRange];; - + + if ((_correctionRange.location > selectedNSRange.location + selectedNSRange.length) || (selectedNSRange.location > _correctionRange.location + _correctionRange.length)) { + _correctionRange.location = NSNotFound; + _correctionRange.length = 0; + } if (_correctionRange.location != NSNotFound && _correctionRange.length > 0) { - [_mutableAttributedString beginEditing]; [_mutableAttributedString deleteCharactersInRange:self.correctionRange]; [_mutableAttributedString endEditing]; @@ -1461,17 +1462,15 @@ - (void)deleteBackward { selectedNSRange.length = 0; } else if (markedTextRange.location != NSNotFound) { - [_mutableAttributedString beginEditing]; [_mutableAttributedString deleteCharactersInRange:selectedNSRange]; [_mutableAttributedString endEditing]; - selectedNSRange.location = markedTextRange.location; + //selectedNSRange.location = markedTextRange.location; selectedNSRange.length = 0; markedTextRange = NSMakeRange(NSNotFound, 0); } else if (selectedNSRange.length > 0) { - [_mutableAttributedString beginEditing]; [_mutableAttributedString deleteCharactersInRange:selectedNSRange]; [_mutableAttributedString endEditing]; @@ -1479,7 +1478,6 @@ - (void)deleteBackward { selectedNSRange.length = 0; } else if (selectedNSRange.location > 0) { - NSInteger index = MAX(0, selectedNSRange.location-1); index = MIN(_attributedString.length-1, index); if ([_attributedString.string characterAtIndex:index] == ' ') { @@ -1498,8 +1496,7 @@ - (void)deleteBackward { self.attributedString = _mutableAttributedString; self.markedRange = markedTextRange; - self.selectedRange = selectedNSRange; - + self.selectedRange = selectedNSRange; } From 511e418808c91d3ec0b847b5cfdb23180124e7b5 Mon Sep 17 00:00:00 2001 From: poetwang Date: Wed, 19 Feb 2014 14:16:57 +0800 Subject: [PATCH 07/11] Add option to disable spelling correction --- EGOTextView/EGOTextView.h | 1 + EGOTextView/EGOTextView.m | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/EGOTextView/EGOTextView.h b/EGOTextView/EGOTextView.h index 8b12ae2..25922da 100644 --- a/EGOTextView/EGOTextView.h +++ b/EGOTextView/EGOTextView.h @@ -117,6 +117,7 @@ extern NSString * const EGOTextAttachmentPlaceholderString; @property(nonatomic,copy) NSString *text; @property(nonatomic,retain) UIFont *font; // ignored when attributedString is not nil @property(nonatomic,getter=isEditable) BOOL editable; //default YES +@property(nonatomic) BOOL correctable; //default YES @property(nonatomic) NSRange selectedRange; @property(nonatomic) NSRange markedRange; diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index d5a108b..741a877 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -195,6 +195,7 @@ @implementation EGOTextView @synthesize text=_text; @synthesize font=_font; @synthesize editable=_editable; +@synthesize correctable = _correctable; @synthesize markedRange=_markedRange; @synthesize selectedRange=_selectedRange; @synthesize correctionRange=_correctionRange; @@ -419,6 +420,22 @@ - (void)setDelegate:(id)aDelegate { } +- (void)setCorrectable:(BOOL)correctable { + if (!_editable) + return; + + if (correctable) { + if (!_textChecker) + _textChecker = [[UITextChecker alloc] init]; + } else { + if (_textChecker!=nil) { + [_textChecker release], + _textChecker=nil; + } + } + _correctable = correctable; +} + - (void)setEditable:(BOOL)editable { if (editable) { From cb16d9f826ed10a870a533083b6ee204845d23a9 Mon Sep 17 00:00:00 2001 From: poetwang Date: Sat, 1 Mar 2014 11:33:45 +0800 Subject: [PATCH 08/11] Fix a bug for disable spelling correction --- EGOTextView/EGOTextView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 741a877..8c83319 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -1642,7 +1642,7 @@ - (void)removeCorrectionAttributesForRange:(NSRange)range { } - (void)checkSpellingForRange:(NSRange)range { - + if (!self.correctable) return; [_mutableAttributedString setAttributedString:self.attributedString]; NSInteger location = range.location-1; From 99f6a48732fecefb589433105d5b64b9e09dfc7d Mon Sep 17 00:00:00 2001 From: poetwang Date: Wed, 5 Mar 2014 13:12:39 +0800 Subject: [PATCH 09/11] Do with the dos/unix line break --- EGOTextView/EGOTextView.h | 30 +- EGOTextView/EGOTextView.m | 1208 ++++++++++++++++++------------------- 2 files changed, 619 insertions(+), 619 deletions(-) diff --git a/EGOTextView/EGOTextView.h b/EGOTextView/EGOTextView.h index 25922da..927631a 100644 --- a/EGOTextView/EGOTextView.h +++ b/EGOTextView/EGOTextView.h @@ -70,7 +70,7 @@ extern NSString * const EGOTextAttachmentPlaceholderString; UITextInputStringTokenizer *_tokenizer; UITextChecker *_textChecker; UILongPressGestureRecognizer *_longPress; - + BOOL _ignoreSelectionMenu; BOOL _delegateRespondsToShouldBeginEditing; BOOL _delegateRespondsToShouldEndEditing; @@ -79,38 +79,38 @@ extern NSString * const EGOTextAttachmentPlaceholderString; BOOL _delegateRespondsToDidChange; BOOL _delegateRespondsToDidChangeSelection; BOOL _delegateRespondsToDidSelectURL; - + NSAttributedString *_attributedString; - UIFont *_font; + UIFont *_font; BOOL _editing; - BOOL _editable; + BOOL _editable; BOOL _spellCheck; BOOL _dataDetectors; - - NSRange _markedRange; + + NSRange _markedRange; NSRange _selectedRange; NSRange _correctionRange; NSRange _linkRange; CTFramesetterRef _framesetter; CTFrameRef _frame; - + EGOContentView *_textContentView; EGOTextWindow *_textWindow; EGOCaretView *_caretView; EGOSelectionView *_selectionView; - + NSMutableArray *_attachmentViews; - + } @property(nonatomic) UIDataDetectorTypes dataDetectorTypes; // UIDataDetectorTypeLink supported @property(nonatomic) UITextAutocapitalizationType autocapitalizationType; -@property(nonatomic) UITextAutocorrectionType autocorrectionType; -@property(nonatomic) UIKeyboardType keyboardType; -@property(nonatomic) UIKeyboardAppearance keyboardAppearance; -@property(nonatomic) UIReturnKeyType returnKeyType; -@property(nonatomic) BOOL enablesReturnKeyAutomatically; +@property(nonatomic) UITextAutocorrectionType autocorrectionType; +@property(nonatomic) UIKeyboardType keyboardType; +@property(nonatomic) UIKeyboardAppearance keyboardAppearance; +@property(nonatomic) UIReturnKeyType returnKeyType; +@property(nonatomic) BOOL enablesReturnKeyAutomatically; @property(nonatomic,assign) id delegate; @property(nonatomic,copy) NSAttributedString *attributedString; @@ -124,4 +124,4 @@ extern NSString * const EGOTextAttachmentPlaceholderString; - (BOOL)hasText; - (void)replaceNSRange:(NSRange)range withText:(NSString *)text; -@end \ No newline at end of file +@end diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 8c83319..9a88e82 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -109,7 +109,7 @@ @interface EGOTextWindow : UIWindow { EGOWindowType _type; EGOSelectionType _selectionType; BOOL _showing; - + } @property(nonatomic,assign) EGOWindowType type; @property(nonatomic,assign) EGOSelectionType selectionType; @@ -185,6 +185,7 @@ @interface EGOTextView () @property(nonatomic,retain) NSDictionary *correctionAttributes; @property(nonatomic,retain) NSMutableDictionary *menuItemActions; @property(nonatomic) NSRange correctionRange; +@property BOOL dos; @end @@ -222,25 +223,25 @@ - (void)commonInit { self.backgroundColor = [UIColor whiteColor]; self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.clipsToBounds = YES; - + EGOContentView *contentView = [[EGOContentView alloc] initWithFrame:CGRectInset(self.bounds, 8.0f, 8.0f)]; contentView.autoresizingMask = self.autoresizingMask; contentView.delegate = self; [self addSubview:contentView]; _textContentView = [contentView retain]; [contentView release]; - + UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; gesture.delegate = (id)self; [self addGestureRecognizer:gesture]; [gesture release]; _longPress = gesture; - + UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; [doubleTap setNumberOfTapsRequired:2]; [self addGestureRecognizer:doubleTap]; [doubleTap release]; - + UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)]; [self addGestureRecognizer:singleTap]; [singleTap release]; @@ -266,7 +267,7 @@ - (id)initWithCoder: (NSCoder *)aDecoder { } - (void)dealloc { - + _textWindow=nil; [_font release], _font=nil; [_attributedString release], _attributedString=nil; @@ -278,12 +279,12 @@ - (void)dealloc { } - (void)clearPreviousLayoutInformation { - + if (_framesetter != NULL) { CFRelease(_framesetter); _framesetter = NULL; } - + if (_frame != NULL) { CFRelease(_frame); _frame = NULL; @@ -291,35 +292,35 @@ - (void)clearPreviousLayoutInformation { } - (CGFloat)boundingWidthForHeight:(CGFloat)height { - + CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(_framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(CGFLOAT_MAX, height), NULL); - return suggestedSize.width; + 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); + CFRelease(framesetter); } - + CGRect rect = _textContentView.frame; CGFloat height = [self boundingHeightForWidth:rect.size.width]; rect.size.height = height+self.font.lineHeight; - _textContentView.frame = rect; + _textContentView.frame = rect; self.contentSize = CGSizeMake(self.frame.size.width, rect.size.height+(self.font.lineHeight*2)); UIBezierPath *path = [UIBezierPath bezierPathWithRect:_textContentView.bounds]; @@ -329,87 +330,86 @@ - (void)textChanged { if (frameRef!=NULL) { CFRelease(frameRef); } - + for (UIView *view in _attachmentViews) { [view removeFromSuperview]; } [_attributedString enumerateAttribute: EGOTextAttachmentAttributeName inRange: NSMakeRange(0, [_attributedString length]) options: 0 usingBlock: ^(id value, NSRange range, BOOL *stop) { - + if ([value respondsToSelector: @selector(attachmentView)]) { UIView *view = [value attachmentView]; [_attachmentViews addObject: view]; - + CGRect rect = [self firstRectForNSRange: range]; rect.size = [view frame].size; [view setFrame: rect]; [self addSubview: view]; } }]; - + [_textContentView setNeedsDisplay]; - + } - (NSString *)text { - return _attributedString.string; + NSString *text = _attributedString.string; + return self.dos ? [text stringByReplacingOccurrencesOfString:@"\n" withString:@"\r\n"] : text; } - (void)setFont:(UIFont *)font { - + UIFont *oldFont = _font; _font = [font retain]; [oldFont release]; - - CTFontRef ctFont = CTFontCreateWithName((CFStringRef) self.font.fontName, self.font.pointSize, NULL); + + 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); - + CFRelease(ctFont); + [self textChanged]; - + } - (void)setText:(NSString *)text { - - [self.inputDelegate textWillChange:self]; - + if ([text rangeOfString:@"\r\n"].location == NSNotFound) { + self.dos = NO; + } else { + self.dos = YES; + text = [text stringByReplacingOccurrencesOfString:@"\r\n" withString:@"\n"]; + } + [self.inputDelegate textWillChange:self]; NSAttributedString *string = [[NSAttributedString alloc] initWithString:text attributes:self.defaultAttributes]; [self setAttributedString:string]; _mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:string]; - [string release]; - - [self.inputDelegate textDidChange:self]; - + [self.inputDelegate textDidChange:self]; } - (void)setAttributedString:(NSAttributedString*)string { NSAttributedString *aString = _attributedString; - _attributedString = [string copy]; [aString release], aString = nil; - + NSRange range = NSMakeRange(0, _attributedString.string.length); if (!_editing && !_editable) { [self checkLinksForRange:range]; [self scanAttachments]; } - - [self textChanged]; + [self textChanged]; if (_delegateRespondsToDidChange) { [self.delegate egoTextViewDidChange:self]; } - } - (void)setDelegate:(id)aDelegate { [super setDelegate:(id)aDelegate]; - + delegate = aDelegate; - + _delegateRespondsToShouldBeginEditing = [delegate respondsToSelector:@selector(egoTextViewShouldBeginEditing:)]; _delegateRespondsToShouldEndEditing = [delegate respondsToSelector:@selector(egoTextViewShouldEndEditing:)]; _delegateRespondsToDidBeginEditing = [delegate respondsToSelector:@selector(egoTextViewDidBeginEditing:)]; @@ -417,7 +417,7 @@ - (void)setDelegate:(id)aDelegate { _delegateRespondsToDidChange = [delegate respondsToSelector:@selector(egoTextViewDidChange:)]; _delegateRespondsToDidChangeSelection = [delegate respondsToSelector:@selector(egoTextViewDidChangeSelection:)]; _delegateRespondsToDidSelectURL = [delegate respondsToSelector:@selector(egoTextView:didSelectURL:)]; - + } - (void)setCorrectable:(BOOL)correctable { @@ -437,28 +437,28 @@ - (void)setCorrectable:(BOOL)correctable { } - (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; if (_textChecker!=nil) { [_textChecker release], _textChecker=nil; @@ -469,10 +469,10 @@ - (void)setEditable:(BOOL)editable { if (_mutableAttributedString!=nil) { [_mutableAttributedString release], _mutableAttributedString=nil; } - + } _editable = editable; - + } @@ -484,34 +484,34 @@ - (void)setEditable:(BOOL)editable { - (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; + + return result; } - (void)drawPathFromRects:(NSArray*)array cornerRadius:(CGFloat)cornerRadius { - + if (array==nil || [array count] == 0) return; - + CGMutablePathRef _path = CGPathCreateMutable(); - + CGRect firstRect = CGRectFromString([array lastObject]); - CGRect lastRect = CGRectFromString([array objectAtIndex:0]); + CGRect lastRect = CGRectFromString([array objectAtIndex:0]); if ([array count]>1) { lastRect.size.width = _textContentView.bounds.size.width-lastRect.origin.x; } - + if (cornerRadius>0) { CGPathAddPath(_path, NULL, [UIBezierPath bezierPathWithRoundedRect:firstRect cornerRadius:cornerRadius].CGPath); CGPathAddPath(_path, NULL, [UIBezierPath bezierPathWithRoundedRect:lastRect cornerRadius:cornerRadius].CGPath); @@ -519,18 +519,18 @@ - (void)drawPathFromRects:(NSArray*)array cornerRadius:(CGFloat)cornerRadius { 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); - + if (cornerRadius>0) { CGPathAddPath(_path, NULL, [UIBezierPath bezierPathWithRoundedRect:fillRect cornerRadius:cornerRadius].CGPath); } else { @@ -538,7 +538,7 @@ - (void)drawPathFromRects:(NSArray*)array cornerRadius:(CGFloat)cornerRadius { } } - + CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextAddPath(ctx, _path); CGContextFillPath(ctx); @@ -547,51 +547,51 @@ - (void)drawPathFromRects:(NSArray*)array cornerRadius:(CGFloat)cornerRadius { } - (void)drawBoundingRangeAsSelection:(NSRange)selectionRange cornerRadius:(CGFloat)cornerRadius { - + if (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(origin.x + xStart, origin.y - descent, xEnd - xStart, ascent + descent); - + + CGRect selectionRect = CGRectMake(origin.x + 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 cornerRadius:cornerRadius]; [pathRects release]; free(origins); } -- (void)drawContentInRect:(CGRect)rect { +- (void)drawContentInRect:(CGRect)rect { [[UIColor colorWithRed:0.8f green:0.8f blue:0.8f alpha:1.0f] setFill]; [self drawBoundingRangeAsSelection:_linkRange cornerRadius:2.0f]; @@ -599,21 +599,21 @@ - (void)drawContentInRect:(CGRect)rect { [self drawBoundingRangeAsSelection:self.selectedRange cornerRadius:0.0f]; [[EGOTextView spellingSelectionColor] setFill]; [self drawBoundingRangeAsSelection:self.correctionRange cornerRadius:2.0f]; - + 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); + 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); - + CFArrayRef runs = CTLineGetGlyphRuns(line); CFIndex runsCount = CFArrayGetCount(runs); for (CFIndex runsIndex = 0; runsIndex < runsCount; runsIndex++) { @@ -623,10 +623,10 @@ - (void)drawContentInRect:(CGRect)rect { if (attachmentCell != nil && [attachmentCell respondsToSelector: @selector(attachmentSize)] && [attachmentCell respondsToSelector: @selector(attachmentDrawInRect:)]) { CGPoint position; CTRunGetPositions(run, CFRangeMake(0, 1), &position); - + CGSize size = [attachmentCell attachmentSize]; CGRect rect = { { origins[i].x + position.x, origins[i].y + position.y }, size }; - + UIGraphicsPushContext(UIGraphicsGetCurrentContext()); [attachmentCell attachmentDrawInRect: rect]; UIGraphicsPopContext(); @@ -634,204 +634,204 @@ - (void)drawContentInRect:(CGRect)rect { } } free(origins); - + } - (NSInteger)closestWhiteSpaceIndexToPoint:(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); - + 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]; CFRange cfRange = CTLineGetStringRange(line); NSRange range = NSMakeRange(cfRange.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length); CGPoint convertedPoint = CGPointMake(point.x - origins[i].x, point.y - origins[i].y); CFIndex cfIndex = CTLineGetStringIndexForPosition(line, convertedPoint); NSInteger index = cfIndex == kCFNotFound ? NSNotFound : cfIndex; - + if(range.location==NSNotFound) break; - + if (index>=_attributedString.length) { returnRange = NSMakeRange(_attributedString.length, 0); break; } - + if (range.length <= 1) { returnRange = NSMakeRange(range.location, 0); break; } - + if (index == range.location) { returnRange = NSMakeRange(range.location, 0); - break; + break; } - - + + if (index >= (range.location+range.length)) { - + if (range.length > 1 && [_attributedString.string characterAtIndex:(range.location+range.length)-1] == '\n') { - + returnRange = NSMakeRange(index-1, 0); break; - + } else { - + returnRange = NSMakeRange(range.location+range.length, 0); break; - + } - + } - + [_attributedString.string enumerateSubstringsInRange:range options:NSStringEnumerationByWords usingBlock:^(NSString *subString, NSRange subStringRange, NSRange enclosingRange, BOOL *stop){ - - + + if (NSLocationInRange(index, enclosingRange)) { - + if (index > (enclosingRange.location+(enclosingRange.length/2))) { - + returnRange = NSMakeRange(subStringRange.location+subStringRange.length, 0); - + } else { - + returnRange = NSMakeRange(subStringRange.location, 0); - + } - + *stop = YES; } - + }]; - + break; - + } } return returnRange.location; } -- (NSInteger)closestIndexToPoint:(CGPoint)point { +- (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); + CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins); CFIndex index = kCFNotFound; - + for (int i = 0; i < lines.count; i++) { if (point.y > origins[i].y) { CTLineRef line = (CTLineRef)[lines objectAtIndex:i]; CGPoint convertedPoint = CGPointMake(point.x - origins[i].x, point.y - origins[i].y); - index = CTLineGetStringIndexForPosition(line, convertedPoint); + index = CTLineGetStringIndexForPosition(line, convertedPoint); break; } } - + if (index == kCFNotFound) { index = [_attributedString length]; } - + free(origins); return index; - + } - (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); + 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]; CGPoint convertedPoint = CGPointMake(point.x - origins[i].x, point.y - origins[i].y); NSInteger index = CTLineGetStringIndexForPosition(line, convertedPoint); - + 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]; + NSInteger count = [lines count]; __block NSRange returnRange = NSMakeRange(NSNotFound, 0); - + for (int i=0; i < count; 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 && index <= range.location+range.length) { - + if (range.length > 1) { - + [_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; } - + }]; - + } } } - + return returnRange; - + } -- (CGRect)caretRectForIndex:(NSInteger)index { - +- (CGRect)caretRectForIndex:(NSInteger)index { + NSArray *lines = (NSArray*)CTFrameGetLines(_frame); - + // no text / first index if (_attributedString.length == 0 || index == 0) { CGPoint origin = CGPointMake(CGRectGetMinX(_textContentView.bounds), CGRectGetMaxY(_textContentView.bounds) - self.font.leading); return CGRectMake(origin.x, origin.y, 3, self.font.ascender + fabs(self.font.descender*2)); - } + } // last index is newline 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); @@ -843,69 +843,69 @@ - (CGRect)caretRectForIndex:(NSInteger)index { CTFrameGetLineOrigins(_frame, CFRangeMake([lines count]-1, 0), origins); origin = origins[0]; free(origins); - + origin.y -= self.font.leading; - return CGRectMake(origin.x + xPos, floorf(origin.y - descent), 3, ceilf((descent*2) + ascent)); - + return CGRectMake(origin.x + xPos, floorf(origin.y - descent), 3, ceilf((descent*2) + ascent)); + } index = MAX(index, 0); index = MIN(_attributedString.string.length, index); - NSInteger count = [lines count]; + NSInteger count = [lines count]; CGPoint *origins = (CGPoint*)malloc(count * sizeof(CGPoint)); CTFrameGetLineOrigins(_frame, CFRangeMake(0, count), origins); CGRect returnRect = CGRectZero; - + for (int i = 0; i < count; i++) { CTLineRef line = (CTLineRef)[lines objectAtIndex:i]; CFRange cfRange = CTLineGetStringRange(line); NSRange range = NSMakeRange(cfRange.location == kCFNotFound ? NSNotFound : cfRange.location, cfRange.length); - + if (index >= range.location && index <= range.location+range.length) { CGFloat ascent, descent, xPos; - xPos = CTLineGetOffsetForStringIndex((CTLineRef)[lines objectAtIndex:i], index, NULL); + xPos = CTLineGetOffsetForStringIndex((CTLineRef)[lines objectAtIndex:i], index, NULL); CTLineGetTypographicBounds(line, &ascent, &descent, NULL); CGPoint origin = origins[i]; if (_selectedRange.length>0 && index != _selectedRange.location && range.length == 1) { - + xPos = _textContentView.bounds.size.width - 3.0f; // selection of entire line - + } else if ([_attributedString.string characterAtIndex:index-1] == '\n' && range.length == 1) { - + xPos = 0.0f; // empty line } - + returnRect = CGRectMake(origin.x + xPos, floorf(origin.y - descent), 3, ceilf((descent*2) + ascent)); - } - + } + } - + 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); @@ -914,12 +914,12 @@ - (CGRect)firstRectForNSRange:(NSRange)range { CGPoint origin = origins[i]; CGFloat ascent, descent; CTLineGetTypographicBounds(line, &ascent, &descent, NULL); - + returnRect = [_textContentView convertRect:CGRectMake(origin.x + xStart, origin.y - descent, xEnd - xStart, ascent + (descent*2)) toView:self]; break; } } - + free(origins); return returnRect; } @@ -931,15 +931,15 @@ - (CGRect)firstRectForNSRange:(NSRange)range { ///////////////////////////////////////////////////////////////////////////// - (void)selectionChanged { - + if (!_editing) { [_caretView removeFromSuperview]; } - + _ignoreSelectionMenu = NO; - + if (self.selectedRange.length == 0) { - + if (_selectionView!=nil) { [_selectionView removeFromSuperview]; _selectionView=nil; @@ -947,48 +947,48 @@ - (void)selectionChanged { if (!_caretView.superview) { [_textContentView addSubview:_caretView]; - [_textContentView setNeedsDisplay]; + [_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.0f; - + if ((_caretView!=nil) && _caretView.superview) { [_caretView removeFromSuperview]; } - + if (_selectionView==nil) { - + EGOSelectionView *view = [[EGOSelectionView alloc] initWithFrame:_textContentView.bounds]; [_textContentView addSubview:view]; _selectionView=view; - [view release]; - + [view release]; + } - + 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)checkRange:(NSRange)r @@ -1009,7 +1009,7 @@ - (NSRange)selectedRange { return _selectedRange; } -- (void)setMarkedRange:(NSRange)range { +- (void)setMarkedRange:(NSRange)range { _markedRange = NSMakeRange(range.location == NSNotFound ? NSNotFound : MAX(0, range.location), range.length); _markedRange = [self checkRange:_markedRange]; //[self selectionChanged]; @@ -1027,43 +1027,43 @@ - (void)setCorrectionRange:(NSRange)range { _correctionRange = range; return; } - + _correctionRange = range; if (range.location != NSNotFound && range.length > 0) { - + if (_caretView.superview) { [_caretView removeFromSuperview]; } - + [self removeCorrectionAttributesForRange:_correctionRange]; [self showCorrectionMenuForRange:_correctionRange]; - + } else { - + if (!_caretView.superview) { [_textContentView addSubview:_caretView]; [_caretView delayBlink]; } - + } - + [_textContentView setNeedsDisplay]; - + } - (void)setLinkRange:(NSRange)range { - + _linkRange = range; - + if (_linkRange.length>0) { - + if (_caretView.superview!=nil) { [_caretView removeFromSuperview]; } - + } else { - + if (_caretView.superview==nil) { if (!_caretView.superview) { [_textContentView addSubview:_caretView]; @@ -1071,28 +1071,28 @@ - (void)setLinkRange:(NSRange)range { [_caretView delayBlink]; } } - + } - + [_textContentView setNeedsDisplay]; } - (void)setLinkRangeFromTextCheckerResults:(NSTextCheckingResult*)results { - + if (_linkRange.length>0) { UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:[[results URL] absoluteString] delegate:(id)self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Open", nil]; [actionSheet showInView:self]; [actionSheet release]; } - + } + (UIColor*)selectionColor { static UIColor *color = nil; if (color == nil) { - color = [[UIColor colorWithRed:0.800f green:0.867f blue:0.929f alpha:1.0f] retain]; - } + color = [[UIColor colorWithRed:0.800f green:0.867f blue:0.929f alpha:1.0f] retain]; + } return color; } @@ -1127,14 +1127,14 @@ - (NSString *)textInRange:(UITextRange *)range { } - (void)replaceRange:(UITextRange *)range withText:(NSString *)text { - + EGOIndexedRange *r = (EGOIndexedRange *)range; NSRange selectedNSRange = self.selectedRange; - [_mutableAttributedString replaceCharactersInRange:r.range withString:text]; + [_mutableAttributedString replaceCharactersInRange:r.range withString:text]; self.attributedString = _mutableAttributedString; self.selectedRange = selectedNSRange; - + } - (void)replaceNSRange:(NSRange)range withText:(NSString *)text @@ -1155,55 +1155,55 @@ - (void)setSelectedTextRange:(UITextRange *)range { } - (UITextRange *)markedTextRange { - return [EGOIndexedRange rangeWithNSRange:self.markedRange]; + return [EGOIndexedRange 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]; + [_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 = _mutableAttributedString; self.markedRange = markedTextRange; - self.selectedRange = selectedNSRange; - + self.selectedRange = selectedNSRange; + } - (void)unmarkText { - + NSRange markedTextRange = self.markedRange; - + if (markedTextRange.location == NSNotFound) return; - + markedTextRange.location = NSNotFound; - self.markedRange = markedTextRange; - + self.markedRange = markedTextRange; + } // MARK: UITextInput - Computing Text Ranges and Text Positions @@ -1219,20 +1219,20 @@ - (UITextPosition*)endOfDocument { - (UITextRange*)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition { EGOIndexedPosition *from = (EGOIndexedPosition *)fromPosition; - EGOIndexedPosition *to = (EGOIndexedPosition *)toPosition; + EGOIndexedPosition *to = (EGOIndexedPosition *)toPosition; NSRange range = NSMakeRange(MIN(from.index, to.index), ABS(to.index - from.index)); - return [EGOIndexedRange rangeWithNSRange:range]; - + return [EGOIndexedRange rangeWithNSRange:range]; + } - (UITextPosition*)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset { - EGOIndexedPosition *pos = (EGOIndexedPosition *)position; + EGOIndexedPosition *pos = (EGOIndexedPosition *)position; NSInteger end = pos.index + offset; - + if (end > _attributedString.length || end < 0) return nil; - + return [EGOIndexedPosition positionWithIndex:end]; } @@ -1240,7 +1240,7 @@ - (UITextPosition*)positionFromPosition:(UITextPosition *)position inDirection:( EGOIndexedPosition *pos = (EGOIndexedPosition *)position; NSInteger newPos = pos.index; - + switch (direction) { case UITextLayoutDirectionRight: newPos += offset; @@ -1249,20 +1249,20 @@ - (UITextPosition*)positionFromPosition:(UITextPosition *)position inDirection:( newPos -= offset; break; UITextLayoutDirectionUp: // not supported right now - break; + break; UITextLayoutDirectionDown: // not supported right now break; default: break; } - + if (newPos < 0) newPos = 0; - + if (newPos > _attributedString.length) newPos = _attributedString.length; - + return [EGOIndexedPosition positionWithIndex:newPos]; } @@ -1271,7 +1271,7 @@ - (UITextPosition*)positionFromPosition:(UITextPosition *)position inDirection:( - (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other { EGOIndexedPosition *pos = (EGOIndexedPosition *)position; EGOIndexedPosition *o = (EGOIndexedPosition *)other; - + if (pos.index == o.index) { return NSOrderedSame; } if (pos.index < o.index) { @@ -1300,38 +1300,38 @@ - (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection EGOIndexedRange *r = (EGOIndexedRange *)range; NSInteger pos = r.range.location; - + switch (direction) { case UITextLayoutDirectionUp: case UITextLayoutDirectionLeft: pos = r.range.location; break; case UITextLayoutDirectionRight: - case UITextLayoutDirectionDown: + case UITextLayoutDirectionDown: pos = r.range.location + r.range.length; break; } - - return [EGOIndexedPosition positionWithIndex:pos]; + + return [EGOIndexedPosition positionWithIndex:pos]; } - (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction { EGOIndexedPosition *pos = (EGOIndexedPosition *)position; NSRange result = NSMakeRange(pos.index, 1); - + switch (direction) { case UITextLayoutDirectionUp: case UITextLayoutDirectionLeft: result = NSMakeRange(pos.index - 1, 1); break; case UITextLayoutDirectionRight: - case UITextLayoutDirectionDown: + case UITextLayoutDirectionDown: result = NSMakeRange(pos.index, 1); break; } - - return [EGOIndexedRange rangeWithNSRange:result]; + + return [EGOIndexedRange rangeWithNSRange:result]; } - (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction { @@ -1345,15 +1345,15 @@ - (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection forRang // MARK: UITextInput - Geometry - (CGRect)firstRectForRange:(UITextRange *)range { - - EGOIndexedRange *r = (EGOIndexedRange *)range; - return [self firstRectForNSRange:r.range]; + + EGOIndexedRange *r = (EGOIndexedRange *)range; + return [self firstRectForNSRange:r.range]; } - (CGRect)caretRectForPosition:(UITextPosition *)position { - + EGOIndexedPosition *pos = (EGOIndexedPosition *)position; - return [self caretRectForIndex:pos.index]; + return [self caretRectForIndex:pos.index]; } - (UIView *)textInputView { @@ -1363,24 +1363,24 @@ - (UIView *)textInputView { // MARK: UITextInput - Hit testing - (UITextPosition*)closestPositionToPoint:(CGPoint)point { - + EGOIndexedPosition *position = [EGOIndexedPosition positionWithIndex:[self closestIndexToPoint:point]]; return position; - + } - (UITextPosition*)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range { - + EGOIndexedPosition *position = [EGOIndexedPosition positionWithIndex:[self closestIndexToPoint:point]]; return position; - + } - (UITextRange*)characterRangeAtPoint:(CGPoint)point { - + EGOIndexedRange *range = [EGOIndexedRange rangeWithNSRange:[self characterRangeAtPoint_:point]]; return range; - + } // MARK: UITextInput - Styling Information @@ -1390,15 +1390,15 @@ - (NSDictionary*)textStylingAtPosition:(UITextPosition *)position inDirection:(U EGOIndexedPosition *pos = (EGOIndexedPosition*)position; NSInteger index = MAX(pos.index, 0); index = MIN(index, _attributedString.length-1); - + NSDictionary *attribs = [self.attributedString attributesAtIndex:index effectiveRange:nil]; NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:1]; - + CTFontRef ctFont = (CTFontRef)[attribs valueForKey:(NSString*)kCTFontAttributeName]; UIFont *font = [UIFont fontWithName:(NSString*)CTFontCopyFamilyName(ctFont) size:CTFontGetSize(ctFont)]; - + [dictionary setObject:font forKey:UITextInputTextFontKey]; - + return dictionary; } @@ -1414,45 +1414,45 @@ - (BOOL)hasText { } - (void)insertText:(NSString *)text { - + NSRange selectedNSRange = self.selectedRange; NSRange markedTextRange = self.markedRange; [_mutableAttributedString setAttributedString:self.attributedString]; 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); - + 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]; + + [_mutableAttributedString insertAttributedString:newString atIndex:selectedNSRange.location]; selectedNSRange.location += text.length; - + } - + [newString release]; - + self.attributedString = _mutableAttributedString; self.markedRange = markedTextRange; - self.selectedRange = selectedNSRange; - + self.selectedRange = selectedNSRange; + if (text.length > 1 || ([text isEqualToString:@" "] || [text isEqualToString:@"\n"])) { [self checkSpellingForRange:[self characterRangeAtIndex:self.selectedRange.location-1]]; [self checkLinksForRange:NSMakeRange(0, self.attributedString.length)]; @@ -1460,9 +1460,9 @@ - (void)insertText:(NSString *)text { } - (void)deleteBackward { - + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showCorrectionMenuWithoutSelection) object:nil]; - + [_mutableAttributedString setAttributedString:self.attributedString]; NSRange selectedNSRange = [self checkRange:self.selectedRange]; NSRange markedTextRange = [self checkRange:self.markedRange];; @@ -1477,40 +1477,40 @@ - (void)deleteBackward { [_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) { NSInteger index = MAX(0, selectedNSRange.location-1); index = MIN(_attributedString.length-1, index); if ([_attributedString.string characterAtIndex:index] == ' ') { [self performSelector:@selector(showCorrectionMenuWithoutSelection) withObject:nil afterDelay:0.2f]; } - + selectedNSRange.location--; selectedNSRange.length = 1; [_mutableAttributedString beginEditing]; [_mutableAttributedString deleteCharactersInRange:selectedNSRange]; [_mutableAttributedString endEditing]; - + selectedNSRange.length = 0; } - + self.attributedString = _mutableAttributedString; self.markedRange = markedTextRange; self.selectedRange = selectedNSRange; @@ -1523,32 +1523,32 @@ - (void)deleteBackward { ///////////////////////////////////////////////////////////////////////////// - (NSTextCheckingResult*)linkAtIndex:(NSInteger)index { - + NSRange range = [self characterRangeAtIndex:index]; if (range.location==NSNotFound || range.length == 0) { return nil; } - + __block NSTextCheckingResult *link = nil; NSError *error = nil; NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error]; [linkDetector enumerateMatchesInString:[self.attributedString string] options:0 range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { - + if ([result resultType] == NSTextCheckingTypeLink) { *stop = YES; link = [result retain]; } - + }]; return [link autorelease]; - + } - (void)checkLinksForRange:(NSRange)range { - + NSDictionary *linkAttributes = [NSDictionary dictionaryWithObjectsAndKeys:(id)[UIColor blueColor].CGColor, kCTForegroundColorAttributeName, [NSNumber numberWithInt:(int)kCTUnderlineStyleSingle], kCTUnderlineStyleAttributeName, nil]; - + NSMutableAttributedString *string = [_attributedString mutableCopy]; NSError *error = nil; NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error]; @@ -1559,24 +1559,24 @@ - (void)checkLinksForRange:(NSRange)range { } }]; - + if (![self.attributedString isEqualToAttributedString:string]) { self.attributedString = string; } - + } - (void)scanAttachments { - + __block NSMutableAttributedString *mutableAttributedString = nil; - + [_attributedString enumerateAttribute: EGOTextAttachmentAttributeName inRange: NSMakeRange(0, [_attributedString length]) options: 0 usingBlock: ^(id value, NSRange range, BOOL *stop) { // we only care when an attachment is set if (value != nil) { // create the mutable version of the string if it's not already there if (mutableAttributedString == nil) mutableAttributedString = [_attributedString mutableCopy]; - + CTRunDelegateCallbacks callbacks = { .version = kCTRunDelegateVersion1, .dealloc = AttachmentRunDelegateDealloc, @@ -1584,14 +1584,14 @@ - (void)scanAttachments { //.getDescent = AttachmentRunDelegateGetDescent, .getWidth = AttachmentRunDelegateGetWidth }; - + // the retain here is balanced by the release in the Dealloc function CTRunDelegateRef runDelegate = CTRunDelegateCreate(&callbacks, [value retain]); [mutableAttributedString addAttribute: (NSString *)kCTRunDelegateAttributeName value: (id)runDelegate range:range]; CFRelease(runDelegate); } }]; - + if (mutableAttributedString) { [_attributedString release]; _attributedString = mutableAttributedString; @@ -1599,22 +1599,22 @@ - (void)scanAttachments { } - (BOOL)selectedLinkAtIndex:(NSInteger)index { - + NSTextCheckingResult *_link = [self linkAtIndex:index]; if (_link!=nil) { [self setLinkRange:[_link range]]; return YES; } - + return NO; } - (void)openLink:(NSURL*)aURL { - + [[UIApplication sharedApplication] openURL:aURL]; - + //self. - + } @@ -1624,27 +1624,27 @@ - (void)openLink:(NSURL*)aURL { ///////////////////////////////////////////////////////////////////////////// - (void)insertCorrectionAttributesForRange:(NSRange)range { - + NSMutableAttributedString *string = [_attributedString mutableCopy]; [string addAttributes:self.correctionAttributes range:range]; self.attributedString = string; [string release]; - + } - (void)removeCorrectionAttributesForRange:(NSRange)range { - + NSMutableAttributedString *string = [_attributedString mutableCopy]; [string removeAttribute:(NSString*)kCTUnderlineStyleAttributeName range:range]; self.attributedString = string; [string release]; - + } - (void)checkSpellingForRange:(NSRange)range { if (!self.correctable) return; [_mutableAttributedString setAttributedString:self.attributedString]; - + NSInteger location = range.location-1; NSInteger currentOffset = MAX(0, location); NSRange currentRange; @@ -1652,35 +1652,35 @@ - (void)checkSpellingForRange:(NSRange)range { NSRange stringRange = NSMakeRange(0, string.length-1); NSArray *guesses; BOOL done = NO; - + NSString *language = [[UITextChecker availableLanguages] objectAtIndex:0]; if (!language) { language = @"en_US"; } - + while (!done) { - + currentRange = [_textChecker rangeOfMisspelledWordInString:string range:stringRange startingAt:currentOffset wrap:NO language:language]; - + if (currentRange.location == NSNotFound || currentRange.location > range.location) { done = YES; continue; } guesses = [_textChecker guessesForWordRange:currentRange inString:string language:language]; - - if (guesses!=nil) { + + if (guesses!=nil) { [_mutableAttributedString addAttributes:self.correctionAttributes range:currentRange]; } - + currentOffset = currentOffset + (currentRange.length-1); - + } - + if (![self.attributedString isEqualToAttributedString:_mutableAttributedString]) { self.attributedString = _mutableAttributedString; } - + } @@ -1690,11 +1690,11 @@ - (void)checkSpellingForRange:(NSRange)range { ///////////////////////////////////////////////////////////////////////////// - (EGOTextWindow*)egoTextWindow { - + if (_textWindow==nil) { - + EGOTextWindow *window = nil; - + for (EGOTextWindow *aWindow in [[UIApplication sharedApplication] windows]){ if ([aWindow isKindOfClass:[EGOTextWindow class]]) { window = aWindow; @@ -1702,139 +1702,139 @@ - (EGOTextWindow*)egoTextWindow { break; } } - + if (window==nil) { window = [[EGOTextWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; } - + window.windowLevel = UIWindowLevelStatusBar; window.hidden = NO; _textWindow=window; - + } - + return _textWindow; - + } - (void)longPress:(UILongPressGestureRecognizer*)gesture { if (gesture.state==UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged) { - + if (_linkRange.length>0 && gesture.state == UIGestureRecognizerStateBegan) { NSTextCheckingResult *link = [self linkAtIndex:_linkRange.location]; [self setLinkRangeFromTextCheckerResults:link]; gesture.enabled=NO; gesture.enabled=YES; } - - + + UIMenuController *menuController = [UIMenuController sharedMenuController]; if ([menuController isMenuVisible]) { [menuController setMenuVisible:NO animated:NO]; } - + CGPoint point = [gesture locationInView:self]; BOOL _selection = (_selectionView!=nil); if (!_selection && _caretView!=nil) { [_caretView show]; } - + _textWindow = [self egoTextWindow]; [_textWindow updateWindowTransform]; [_textWindow setType:_selection ? EGOWindowMagnify : EGOWindowLoupe]; point.y -= 20.0f; NSInteger index = [self closestIndexToPoint:point]; - + if (_selection) { - + if (gesture.state == UIGestureRecognizerStateBegan) { _textWindow.selectionType = (index > (_selectedRange.location+(_selectedRange.length/2))) ? EGOSelectionTypeRight : EGOSelectionTypeLeft; } - + 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); index = _selectedRange.location; - + } else { - + NSInteger length = MIN(index-_selectedRange.location, _attributedString.string.length-_selectedRange.location); - length = MAX(1, length); + length = MAX(1, length); self.selectedRange = NSMakeRange(self.selectedRange.location, length); - index = (_selectedRange.location+_selectedRange.length); - + index = (_selectedRange.location+_selectedRange.length); + } - + rect = [self caretRectForIndex:index]; - + if (gesture.state == UIGestureRecognizerStateBegan) { - + [_textWindow showFromView:_textContentView rect:[_textContentView convertRect:rect toView:_textWindow]]; } else { - + [_textWindow renderWithContentView:_textContentView fromRect:[_textContentView convertRect:rect toView:_textWindow]]; - + } - + } 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 (gesture.state == UIGestureRecognizerStateEnded) { if (self.selectedRange.location!=NSNotFound && self.selectedRange.length>0) { [self showMenu]; } } } - + } - (void)doubleTap:(UITapGestureRecognizer*)gesture { - + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showMenu) object:nil]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showCorrectionMenu) object:nil]; NSInteger index = [self closestWhiteSpaceIndexToPoint:[gesture locationInView:self]]; NSRange range = [self characterRangeAtIndex:index]; if (range.location!=NSNotFound && range.length>0) { - + [self.inputDelegate selectionWillChange:self]; self.selectedRange = range; [self.inputDelegate selectionDidChange:self]; @@ -1842,40 +1842,40 @@ - (void)doubleTap:(UITapGestureRecognizer*)gesture { if (![[UIMenuController sharedMenuController] isMenuVisible]) { [self performSelector:@selector(showMenu) withObject:nil afterDelay:0.1f]; } - } - + } + } - (void)tap:(UITapGestureRecognizer*)gesture { - + if (_editable && ![self isFirstResponder]) { - [self becomeFirstResponder]; + [self becomeFirstResponder]; return; } - + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showMenu) object:nil]; [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showCorrectionMenu) object:nil]; - + self.correctionRange = NSMakeRange(NSNotFound, 0); if (self.selectedRange.length>0) { self.selectedRange = NSMakeRange(_selectedRange.location, 0); } - + NSInteger index = [self closestWhiteSpaceIndexToPoint:[gesture locationInView:self]]; - + if (_delegateRespondsToDidSelectURL && !_editing) { if ([self selectedLinkAtIndex:index]) { return; } } - + UIMenuController *menuController = [UIMenuController sharedMenuController]; if ([menuController isMenuVisible]) { [menuController setMenuVisible:NO animated:NO]; - + } else { - + if (index==self.selectedRange.location) { [self performSelector:@selector(showMenu) withObject:nil afterDelay:0.35f]; } else { @@ -1883,16 +1883,16 @@ - (void)tap:(UITapGestureRecognizer*)gesture { [self performSelector:@selector(showCorrectionMenu) withObject:nil afterDelay:0.35f]; } } - + } - + [self.inputDelegate selectionWillChange:self]; - + self.markedRange = NSMakeRange(NSNotFound, 0); self.selectedRange = NSMakeRange(index, 0); - + [self.inputDelegate selectionDidChange:self]; - + } @@ -1902,30 +1902,30 @@ - (void)tap:(UITapGestureRecognizer*)gesture { ///////////////////////////////////////////////////////////////////////////// - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ - + if ([gestureRecognizer isKindOfClass:NSClassFromString(@"UIScrollViewPanGestureRecognizer")]) { UIMenuController *menuController = [UIMenuController sharedMenuController]; if ([menuController isMenuVisible]) { [menuController setMenuVisible:NO animated:NO]; } } - + return NO; - + } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ - + if (gestureRecognizer==_longPress) { - - if (_selectedRange.length>0 && _selectionView!=nil) { + + if (_selectedRange.length>0 && _selectionView!=nil) { return CGRectContainsPoint(CGRectInset([_textContentView convertRect:_selectionView.frame toView:self], -20.0f, -20.0f) , [gestureRecognizer locationInView:self]); } - + } - + return YES; - + } @@ -1935,21 +1935,21 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ ///////////////////////////////////////////////////////////////////////////// - (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex { - + if (actionSheet.cancelButtonIndex != buttonIndex) { - + if (_delegateRespondsToDidChange) { [self.delegate egoTextView:self didSelectURL:[NSURL URLWithString:actionSheet.title]]; } else { [self openLink:[NSURL URLWithString:actionSheet.title]]; } - + } else { - + [self becomeFirstResponder]; - + } - + [self setLinkRange:NSMakeRange(NSNotFound, 0)]; } @@ -1965,20 +1965,20 @@ - (BOOL)canBecomeFirstResponder { if (_editable && _delegateRespondsToShouldBeginEditing) { return [self.delegate egoTextViewShouldBeginEditing:self]; } - + return YES; } - (BOOL)becomeFirstResponder { if (_editable) { - + _editing = YES; if (_delegateRespondsToDidBeginEditing) { [self.delegate egoTextViewDidBeginEditing:self]; } - + [self selectionChanged]; } @@ -1986,30 +1986,30 @@ - (BOOL)becomeFirstResponder { } - (BOOL)canResignFirstResponder { - + if (_editable && _delegateRespondsToShouldEndEditing) { return [self.delegate egoTextViewShouldEndEditing:self]; } - + return YES; } - (BOOL)resignFirstResponder { if (_editable) { - - _editing = NO; + + _editing = NO; if (_delegateRespondsToDidEndEditing) { [self.delegate egoTextViewDidEndEditing:self]; } - + [self selectionChanged]; - + } return [super resignFirstResponder]; - + } @@ -2019,117 +2019,117 @@ - (BOOL)resignFirstResponder { ///////////////////////////////////////////////////////////////////////////// - (CGRect)menuPresentationRect { - + CGRect rect = [_textContentView convertRect:_caretView.frame toView:self]; - + if (_selectedRange.location != NSNotFound && _selectedRange.length > 0) { - + if (_selectionView!=nil) { rect = [_textContentView convertRect:_selectionView.frame toView:self]; } else { rect = [self firstRectForNSRange:_selectedRange]; } - + } else if (_editing && _correctionRange.location != NSNotFound && _correctionRange.length > 0) { - + rect = [self firstRectForNSRange:_correctionRange]; - - } - + + } + return rect; - + } - (void)showMenu { - + UIMenuController *menuController = [UIMenuController sharedMenuController]; - + if ([menuController isMenuVisible]) { - [menuController setMenuVisible:NO animated:NO]; + [menuController setMenuVisible:NO animated:NO]; } - + dispatch_async(dispatch_get_main_queue(), ^{ [menuController setMenuItems:nil]; [menuController setTargetRect:[self menuPresentationRect] inView:self]; [menuController update]; - [menuController setMenuVisible:YES animated:YES]; + [menuController setMenuVisible:YES animated:YES]; }); - - - + + + } - (void)showCorrectionMenu { - + if (_editing) { - + NSRange range = [self characterRangeAtIndex:self.selectedRange.location]; if (range.location!=NSNotFound && range.length>1) { - + 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)showCorrectionMenuWithoutSelection { - + if (_editing) { - + NSRange range = [self characterRangeAtIndex:self.selectedRange.location]; [self showCorrectionMenuForRange:range]; - + } else { - + [self showMenu]; - + } - + } - (void)showCorrectionMenuForRange:(NSRange)range { - + if (range.location==NSNotFound || range.length==0) return; - + range.location = MAX(0, range.location); range.length = MIN(_attributedString.string.length, range.length); - + [self removeCorrectionAttributesForRange:range]; - + UIMenuController *menuController = [UIMenuController sharedMenuController]; - + if ([menuController isMenuVisible]) return; _ignoreSelectionMenu = YES; - + NSString *language = [[UITextChecker availableLanguages] objectAtIndex:0]; if (!language) { language = @"en_US"; - } - + } + NSArray *guesses = [_textChecker guessesForWordRange:range inString:_attributedString.string language:language]; - + [menuController setTargetRect:[self menuPresentationRect] inView:self]; - + 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)]; + + [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]; @@ -2137,22 +2137,22 @@ - (void)showCorrectionMenuForRange:(NSRange)range { break; } } - - [menuController setMenuItems:items]; + + [menuController setMenuItems:items]; [items release]; - - - + + + } else { - + UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:@"No Replacements Found" action:@selector(spellCheckMenuEmpty:)]; [menuController setMenuItems:[NSArray arrayWithObject:item]]; - [item release]; - + [item release]; + } - + [menuController setMenuVisible:YES animated:YES]; - + } @@ -2162,7 +2162,7 @@ - (void)showCorrectionMenuForRange:(NSRange)range { ///////////////////////////////////////////////////////////////////////////// - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { - + if (self.correctionRange.length>0 || _ignoreSelectionMenu) { if ([NSStringFromSelector(action) hasPrefix:@"spellCheckMenu"]) { return YES; @@ -2183,25 +2183,25 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { } return [super canPerformAction:action withSender:sender]; - + } - (void)spellingCorrection:(UIMenuController*)sender { - + NSRange replacementRange = _correctionRange; - + if (replacementRange.location==NSNotFound || replacementRange.length==0) { replacementRange = [self characterRangeAtIndex:self.selectedRange.location]; } if (replacementRange.location!=NSNotFound && replacementRange.length!=0) { NSString *text = [self.menuItemActions objectForKey:NSStringFromSelector(_cmd)]; - [self.inputDelegate textWillChange:self]; + [self.inputDelegate textWillChange:self]; [self replaceRange:[EGOIndexedRange rangeWithNSRange:replacementRange] withText:text]; - [self.inputDelegate textDidChange:self]; + [self.inputDelegate textDidChange:self]; replacementRange.length = text.length; [self removeCorrectionAttributesForRange:replacementRange]; } - + self.correctionRange = NSMakeRange(NSNotFound, 0); self.menuItemActions = nil; [sender setMenuItems:nil]; @@ -2211,85 +2211,85 @@ - (void)spellingCorrection:(UIMenuController*)sender { - (void)spellCheckMenuEmpty:(id)sender { self.correctionRange = NSMakeRange(NSNotFound, 0); - + } - (void)menuDidHide:(NSNotification*)notification { - + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidHideMenuNotification object:nil]; - + if (_selectionView) { [self showMenu]; } } - (void)paste:(id)sender { - + NSString *pasteText = [[UIPasteboard generalPasteboard] valueForPasteboardType:@"public.utf8-plain-text"]; - + if (pasteText!=nil) { [self insertText:pasteText]; } - + } - (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 = [self.attributedString.string substringWithRange:self.selectedRange]; [[UIPasteboard generalPasteboard] setValue:string forPasteboardType:@"public.utf8-plain-text"]; - + [_mutableAttributedString setAttributedString:self.attributedString]; [_mutableAttributedString deleteCharactersInRange:_selectedRange]; - - [self.inputDelegate textWillChange:self]; + + [self.inputDelegate textWillChange:self]; [self setAttributedString:_mutableAttributedString]; - [self.inputDelegate textDidChange:self]; - + [self.inputDelegate textDidChange:self]; + self.selectedRange = NSMakeRange(_selectedRange.location, 0); - + } - (void)copy:(id)sender { - + NSString *string = [self.attributedString.string substringWithRange:self.selectedRange]; [[UIPasteboard generalPasteboard] setValue:string forPasteboardType:@"public.utf8-plain-text"]; - + } - (void)delete:(id)sender { - + [_mutableAttributedString setAttributedString:self.attributedString]; [_mutableAttributedString deleteCharactersInRange:_selectedRange]; - [self.inputDelegate textWillChange:self]; + [self.inputDelegate textWillChange:self]; [self setAttributedString:_mutableAttributedString]; - [self.inputDelegate textDidChange:self]; - + [self.inputDelegate textDidChange:self]; + self.selectedRange = NSMakeRange(_selectedRange.location, 0); - + } - (void)replace:(id)sender { - - + + } @end @@ -2299,7 +2299,7 @@ - (void)replace:(id)sender { // MARK: EGOIndexedPosition ///////////////////////////////////////////////////////////////////////////// -@implementation EGOIndexedPosition +@implementation EGOIndexedPosition @synthesize index=_index; + (EGOIndexedPosition *)positionWithIndex:(NSUInteger)index { @@ -2316,13 +2316,13 @@ + (EGOIndexedPosition *)positionWithIndex:(NSUInteger)index { // MARK: EGOIndexedRange ///////////////////////////////////////////////////////////////////////////// -@implementation EGOIndexedRange +@implementation EGOIndexedRange @synthesize range=_range; + (EGOIndexedRange *)rangeWithNSRange:(NSRange)theRange { if (theRange.location == NSNotFound) return nil; - + EGOIndexedRange *range = [[EGOIndexedRange alloc] init]; range.range = theRange; return [range autorelease]; @@ -2354,26 +2354,26 @@ @implementation EGOContentView - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { - + self.userInteractionEnabled = NO; self.layer.geometryFlipped = YES; self.backgroundColor = [UIColor whiteColor]; - + } return self; } - (void)layoutSubviews { [super layoutSubviews]; - + [self.delegate textChanged]; // reset layout on frame / orientation change - + } - (void)drawRect:(CGRect)rect { - + [_delegate drawContentInRect:rect]; - + } - (void)dealloc { @@ -2396,31 +2396,31 @@ @implementation EGOCaretView - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { self.backgroundColor = [EGOTextView caretColor]; - } + } return self; } - (void)show { - + [self.layer removeAllAnimations]; - + } - (void)didMoveToSuperview { if (self.superview) { - + [self delayBlink]; - + } else { - + [self.layer removeAllAnimations]; - + } } - (void)delayBlink { - + CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; animation.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:1.0f], [NSNumber numberWithFloat:1.0f], [NSNumber numberWithFloat:0.0f], [NSNumber numberWithFloat:0.0f], nil]; animation.calculationMode = kCAAnimationCubic; @@ -2428,7 +2428,7 @@ - (void)delayBlink { animation.beginTime = CACurrentMediaTime() + kInitialBlinkDelay; animation.repeatCount = CGFLOAT_MAX; [self.layer addAnimation:animation forKey:@"BlinkAnimation"]; - + } - (void)dealloc { @@ -2455,24 +2455,24 @@ - (id)init { - (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); - + [[UIImage imageNamed:@"loupe-lo.png"] drawInRect:rect]; - + if ((_contentImage!=nil)) { - + CGContextSaveGState(ctx); CGContextClipToMask(ctx, rect, [UIImage imageNamed:@"loupe-mask.png"].CGImage); - [_contentImage drawInRect:rect]; + [_contentImage drawInRect:rect]; CGContextRestoreGState(ctx); - + } - + [[UIImage imageNamed:@"loupe-hi.png"] drawInRect:rect]; - + } - (void)setContentImage:(UIImage *)image { - + [_contentImage release], _contentImage=nil; _contentImage = [image retain]; [self setNeedsDisplay]; @@ -2502,7 +2502,7 @@ @implementation EGOTextWindow static const CGFloat kMagnifyScale = 1.0f; static const NSTimeInterval kDefaultAnimationDuration = 0.15f; -- (id)initWithFrame:(CGRect)frame { +- (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { self.backgroundColor = [UIColor clearColor]; _type = EGOWindowLoupe; @@ -2515,11 +2515,11 @@ - (NSInteger)selectionForRange:(NSRange)range { } - (void)showFromView:(UIView*)view rect:(CGRect)rect { - + CGPoint pos = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect)); - + if (!_showing) { - + if (_view==nil) { UIView *view; if (_type==EGOWindowLoupe) { @@ -2531,61 +2531,61 @@ - (void)showFromView:(UIView*)view rect:(CGRect)rect { _view=view; [view release]; } - + CGRect frame = _view.frame; frame.origin.x = floorf(pos.x - (_view.bounds.size.width/2)); frame.origin.y = floorf(pos.y - _view.bounds.size.height); - + if (_type==EGOWindowMagnify) { - + frame.origin.y = MAX(frame.origin.y+8.0f, 0.0f); frame.origin.x += 2.0f; - + } else { - + frame.origin.y = MAX(frame.origin.y-10.0f, -40.0f); - + } - + CGRect originFrame = frame; frame.origin.y += frame.size.height/2; _view.frame = frame; _view.transform = CGAffineTransformMakeScale(0.01f, 0.01f); _view.alpha = 0.01f; - + [UIView animateWithDuration:kDefaultAnimationDuration animations:^{ - + _view.alpha = 1.0f; _view.transform = CGAffineTransformMakeScale(1.0f, 1.0f); _view.frame = originFrame; } completion:^(BOOL finished) { - + _showing=YES; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.0f*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self renderWithContentView:view fromRect:rect]; }); - + }]; - + } - + } - (void)hide:(BOOL)animated { - + if ((_view!=nil)) { - + [UIView animateWithDuration:kDefaultAnimationDuration animations:^{ - + CGRect frame = _view.frame; CGPoint center = _view.center; frame.origin.x = floorf(center.x-(frame.size.width/2)); frame.origin.y = center.y; _view.frame = frame; _view.transform = CGAffineTransformMakeScale(0.01f, 0.01f); - + } completion:^(BOOL finished) { _showing=NO; @@ -2595,24 +2595,24 @@ - (void)hide:(BOOL)animated { self.hidden = YES; }]; - + } - + } - (UIImage*)screenshotFromCaretFrame:(CGRect)rect inView:(UIView*)view scale:(BOOL)scale { - + CGRect offsetRect = [self convertRect:rect toView:view]; offsetRect.origin.y += ((UIScrollView*)view.superview).contentOffset.y; offsetRect.origin.y -= _view.bounds.size.height+20.0f; offsetRect.origin.x -= (_view.bounds.size.width/2); - - //CGFloat magnifyScale = 1.0f; - + + //CGFloat magnifyScale = 1.0f; + if (scale) { //CGFloat max = 24.0f; - // magnifyScale = max/offsetRect.size.height; - // NSLog(@"max %f scale %f", max, magnifyScale); + // magnifyScale = max/offsetRect.size.height; + // NSLog(@"max %f scale %f", max, magnifyScale); } else if (rect.size.height < 22.0f) { //magnifyScale = 22.0f/offsetRect.size.height; //NSLog(@"cale %f", magnifyScale); @@ -2627,47 +2627,47 @@ - (UIImage*)screenshotFromCaretFrame:(CGRect)rect inView:(UIView*)view scale:(BO CGContextSaveGState(ctx); CGContextTranslateCTM(ctx, 0, view.bounds.size.height); CGContextScaleCTM(ctx, 1.0, -1.0); - -// CGContextConcatCTM(ctx, CGAffineTransformMakeScale(magnifyScale, magnifyScale)); + + // CGContextConcatCTM(ctx, CGAffineTransformMakeScale(magnifyScale, magnifyScale)); CGContextConcatCTM(ctx, CGAffineTransformMakeTranslation(-(offsetRect.origin.x), offsetRect.origin.y)); - + UIView *selectionView = nil; CGRect selectionFrame = CGRectZero; - + for (UIView *subview in view.subviews){ if ([subview isKindOfClass:[EGOSelectionView class]]) { selectionView = subview; } } - + if (selectionView!=nil) { selectionFrame = selectionView.frame; CGRect newFrame = selectionFrame; newFrame.origin.y = (selectionFrame.size.height - view.bounds.size.height) - ((selectionFrame.origin.y + selectionFrame.size.height) - view.bounds.size.height); selectionView.frame = newFrame; } - + [view.layer renderInContext:ctx]; - + if (selectionView!=nil) { selectionView.frame = selectionFrame; } - - + + CGContextRestoreGState(ctx); UIImage *aImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return aImage; - + } - (void)renderWithContentView:(UIView*)view fromRect:(CGRect)rect { - + CGPoint pos = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect)); - + if (_showing && _view!=nil) { - + CGRect frame = _view.frame; frame.origin.x = floorf((pos.x - (_view.bounds.size.width/2)) + (rect.size.width/2)); frame.origin.y = floorf(pos.y - _view.bounds.size.height); @@ -2683,13 +2683,13 @@ - (void)renderWithContentView:(UIView*)view fromRect:(CGRect)rect { UIImage *image = [self screenshotFromCaretFrame:rect inView:view scale:(_type==EGOWindowMagnify)]; [(EGOLoupeView*)_view setContentImage:image]; - + } - + } - (void)updateWindowTransform { - + self.frame = [[UIScreen mainScreen] bounds]; switch ([[UIApplication sharedApplication] statusBarOrientation]) { case UIInterfaceOrientationPortrait: @@ -2707,7 +2707,7 @@ - (void)updateWindowTransform { default: break; } - + } - (void)layoutSubviews { @@ -2738,30 +2738,30 @@ - (id)init { } - (void)drawRect:(CGRect)rect { - + CGContextRef ctx = UIGraphicsGetCurrentContext(); - + [[UIImage imageNamed:@"magnifier-ranged-lo.png"] drawInRect:rect]; - + if ((_contentImage!=nil)) { - + CGContextSaveGState(ctx); CGContextClipToMask(ctx, rect, [UIImage imageNamed:@"magnifier-ranged-mask.png"].CGImage); - [_contentImage drawInRect:rect]; + [_contentImage drawInRect:rect]; CGContextRestoreGState(ctx); - + } - + [[UIImage imageNamed:@"magnifier-ranged-hi.png"] drawInRect:rect]; - + } - (void)setContentImage:(UIImage *)image { - + [_contentImage release], _contentImage=nil; _contentImage = [image retain]; [self setNeedsDisplay]; - + } - (void)dealloc { @@ -2781,32 +2781,32 @@ @implementation EGOSelectionView - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { - - self.backgroundColor = [UIColor clearColor]; + + self.backgroundColor = [UIColor clearColor]; self.userInteractionEnabled = NO; self.layer.geometryFlipped = YES; - + } return self; } - (void)setBeginCaret:(CGRect)begin endCaret:(CGRect)end { - + if(!self.superview) return; - - self.frame = CGRectMake(begin.origin.x, begin.origin.y + begin.size.height, end.origin.x - begin.origin.x, (end.origin.y-end.size.height)-begin.origin.y); + + self.frame = CGRectMake(begin.origin.x, begin.origin.y + begin.size.height, end.origin.x - begin.origin.x, (end.origin.y-end.size.height)-begin.origin.y); begin = [self.superview convertRect:begin toView:self]; end = [self.superview convertRect:end toView:self]; - + if (_leftCaret==nil) { UIView *view = [[UIView alloc] initWithFrame:begin]; view.backgroundColor = [EGOTextView caretColor]; - [self addSubview:view]; + [self addSubview:view]; _leftCaret=[view retain]; [view release]; } - + if (_leftDot==nil) { UIImage *dotImage = [UIImage imageNamed:@"drag-dot.png"]; UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, dotImage.size.width, dotImage.size.height)]; @@ -2815,11 +2815,11 @@ - (void)setBeginCaret:(CGRect)begin endCaret:(CGRect)end { _leftDot = view; [view release]; } - + CGFloat _dotShadowOffset = 5.0f; _leftCaret.frame = begin; _leftDot.frame = CGRectMake(floorf(_leftCaret.center.x - (_leftDot.bounds.size.width/2)), _leftCaret.frame.origin.y-(_leftDot.bounds.size.height-_dotShadowOffset), _leftDot.bounds.size.width, _leftDot.bounds.size.height); - + if (_rightCaret==nil) { UIView *view = [[UIView alloc] initWithFrame:end]; view.backgroundColor = [EGOTextView caretColor]; @@ -2827,7 +2827,7 @@ - (void)setBeginCaret:(CGRect)begin endCaret:(CGRect)end { _rightCaret = [view retain]; [view release]; } - + if (_rightDot==nil) { UIImage *dotImage = [UIImage imageNamed:@"drag-dot.png"]; UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, dotImage.size.width, dotImage.size.height)]; @@ -2836,17 +2836,17 @@ - (void)setBeginCaret:(CGRect)begin endCaret:(CGRect)end { _rightDot = view; [view release]; } - + _rightCaret.frame = end; _rightDot.frame = CGRectMake(floorf(_rightCaret.center.x - (_rightDot.bounds.size.width/2)), CGRectGetMaxY(_rightCaret.frame), _rightDot.bounds.size.width, _rightDot.bounds.size.height); - + } - (void)dealloc { - - [_leftCaret release], _leftCaret=nil; - [_rightCaret release], _rightCaret=nil; + + [_leftCaret release], _leftCaret=nil; + [_rightCaret release], _rightCaret=nil; _rightDot=nil; _leftDot=nil; [super dealloc]; From 97cc32030fc4e8ffddbb7abdd6a12933e7c23b97 Mon Sep 17 00:00:00 2001 From: poetwang Date: Wed, 2 Apr 2014 11:49:58 +0800 Subject: [PATCH 10/11] Fix warning --- EGOTextView/EGOTextView.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 9a88e82..1d370f0 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -160,7 +160,7 @@ + (EGOIndexedRange *)rangeWithNSRange:(NSRange)range; @interface EGOTextView (Private) -- (CGRect)caretRectForIndex:(int)index; +- (CGRect)caretRectForIndex:(NSInteger)index; - (CGRect)firstRectForNSRange:(NSRange)range; - (NSInteger)closestIndexToPoint:(CGPoint)point; - (NSRange)characterRangeAtPoint_:(CGPoint)point; @@ -172,6 +172,7 @@ - (void)showCorrectionMenuForRange:(NSRange)range; - (void)checkLinksForRange:(NSRange)range; - (void)scanAttachments; - (void)showMenu; + - (CGRect)menuPresentationRect; + (UIColor *)selectionColor; @@ -2124,7 +2125,7 @@ - (void)showCorrectionMenuForRange:(NSRange)range { for (NSString *word in guesses){ - NSString *selString = [NSString stringWithFormat:@"spellCheckMenu_%i:", [word hash]]; + NSString *selString = [NSString stringWithFormat:@"spellCheckMenu_%lu:", (unsigned long)[word hash]]; SEL sel = sel_registerName([selString UTF8String]); [self.menuItemActions setObject:word forKey:NSStringFromSelector(sel)]; From b2a855d303f919d6667c2701d3a50affa4ab298b Mon Sep 17 00:00:00 2001 From: 34x Date: Sat, 29 Aug 2015 00:06:30 +0200 Subject: [PATCH 11/11] Fix line above the text If rect.size.height (line 323) is not round for example 320.01 sometimes tiny lines appears above editable text (it disappears after few attempts to select text), with round height value problem is not appears. I found it in Seafile iOS client when trying to edit text. --- EGOTextView/EGOTextView.m | 1 + 1 file changed, 1 insertion(+) diff --git a/EGOTextView/EGOTextView.m b/EGOTextView/EGOTextView.m index 1d370f0..f1f8101 100644 --- a/EGOTextView/EGOTextView.m +++ b/EGOTextView/EGOTextView.m @@ -321,6 +321,7 @@ - (void)textChanged { CGRect rect = _textContentView.frame; CGFloat height = [self boundingHeightForWidth:rect.size.width]; rect.size.height = height+self.font.lineHeight; + rect.size.height = round(rect.size.height); _textContentView.frame = rect; self.contentSize = CGSizeMake(self.frame.size.width, rect.size.height+(self.font.lineHeight*2));