Skip to content

Commit

Permalink
Merge branch 'release-1.6.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
odrobnik committed Jul 11, 2013
2 parents 87c8543 + c303e10 commit b1e5a27
Show file tree
Hide file tree
Showing 24 changed files with 485 additions and 54 deletions.
2 changes: 1 addition & 1 deletion AppledocSettings.plist
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<key>--project-company</key>
<string>Cocoanetics</string>
<key>--project-version</key>
<string>1.5</string>
<string>1.6</string>
<key>--company-id</key>
<string>com.cocoanetics</string>
<key>--docset-atom-filename</key>
Expand Down
23 changes: 23 additions & 0 deletions Core/Source/DTAttributedTextContentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,3 +339,26 @@ typedef NSUInteger DTAttributedTextContentViewRelayoutMask;

@end


/**
Methods for getting cursor position and frame. Those are convenience methods that call through to the layoutFrame property which has the same coordinate system as the receiver.
*/
@interface DTAttributedTextContentView (Cursor)

/**
Determines the closest string index to a point in the receiver's frame.
This can be used to find the cursor position to position an input caret at.
@param point The point
@returns The resulting string index
*/
- (NSInteger)closestCursorIndexToPoint:(CGPoint)point;

/**
The rectangle to draw a caret for a given index
@param index The string index for which to determine a cursor frame
@returns The cursor rectangle
*/
- (CGRect)cursorRectAtIndex:(NSInteger)index;

@end
15 changes: 15 additions & 0 deletions Core/Source/DTAttributedTextContentView.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,21 @@ + (Class)layerClass
@end


@implementation DTAttributedTextContentView (Cursor)

- (NSInteger)closestCursorIndexToPoint:(CGPoint)point
{
return [self.layoutFrame closestCursorIndexToPoint:point];
}

- (CGRect)cursorRectAtIndex:(NSInteger)index
{
return [self.layoutFrame cursorRectAtIndex:index];
}

@end


@implementation DTAttributedTextContentView

- (void)setup
Expand Down
20 changes: 20 additions & 0 deletions Core/Source/DTAttributedTextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,24 @@
*/
- (void)scrollRangeToVisible:(NSRange)range animated:(BOOL)animated;

/**
@name Working with a Cursor
*/

/**
Determines the closest string index to a point in the receiver's frame.
This can be used to find the cursor position to position an input caret at.
@param point The point
@returns The resulting string index
*/
- (NSInteger)closestCursorIndexToPoint:(CGPoint)point;

/**
The rectangle to draw a caret for a given index
@param index The string index for which to determine a cursor frame
@returns The cursor rectangle
*/
- (CGRect)cursorRectAtIndex:(NSInteger)index;

@end
20 changes: 20 additions & 0 deletions Core/Source/DTAttributedTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ - (void)relayoutText
[self setNeedsLayout];
}

#pragma mark - Working with a Cursor

- (NSInteger)closestCursorIndexToPoint:(CGPoint)point
{
// the point is in the coordinate system of the receiver, need to convert into those of the content view first
CGPoint pointInContentView = [self.attributedTextContentView convertPoint:point fromView:self];

return [self.attributedTextContentView closestCursorIndexToPoint:pointInContentView];
}

- (CGRect)cursorRectAtIndex:(NSInteger)index
{
CGRect rectInContentView = [self.attributedTextContentView cursorRectAtIndex:index];

// the point is in the coordinate system of the content view, need to convert into those of the receiver first
CGRect rect = [self.attributedTextContentView convertRect:rectInContentView toView:self];

return rect;
}

#pragma mark Notifications
- (void)contentViewDidLayout:(NSNotification *)notification
{
Expand Down
2 changes: 2 additions & 0 deletions Core/Source/DTCoreText.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#import "DTCoreTextParagraphStyle.h"
#import "DTHTMLAttributedStringBuilder.h"
#import "DTHTMLElement.h"
#import "DTHTMLWriter.h"
#import "NSCharacterSet+HTML.h"
#import "NSDictionary+DTCoreText.h"
#import "NSAttributedString+HTML.h"
Expand Down Expand Up @@ -64,6 +65,7 @@
#import "DTCoreTextFontCollection.h"
#import "DTCoreTextGlyphRun.h"
#import "DTCoreTextLayoutFrame.h"
#import "DTCoreTextLayoutFrame+Cursor.h"
#import "DTCoreTextLayoutLine.h"
#import "DTCoreTextLayouter.h"

Expand Down
1 change: 1 addition & 0 deletions Core/Source/DTCoreTextConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern NSString * const DTDefaultHeadIndent;
extern NSString * const DTDefaultStyleSheet;
extern NSString * const DTUseiOS6Attributes;
extern NSString * const DTWillFlushBlockCallBack;
extern NSString * const DTProcessCustomHTMLAttributes;

// attributed string attribute constants

Expand Down
1 change: 1 addition & 0 deletions Core/Source/DTCoreTextConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
NSString * const DTDefaultStyleSheet = @"DTDefaultStyleSheet";
NSString * const DTUseiOS6Attributes = @"DTUseiOS6Attributes";
NSString * const DTWillFlushBlockCallBack = @"DTWillFlushBlockCallBack";
NSString * const DTProcessCustomHTMLAttributes = @"DTProcessCustomHTMLAttributes";

// attributed string attribute constants

Expand Down
33 changes: 33 additions & 0 deletions Core/Source/DTCoreTextLayoutFrame+Cursor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// DTCoreTextLayoutFrame+Cursor.h
// DTCoreText
//
// Created by Oliver Drobnik on 10.07.13.
// Copyright (c) 2013 Drobnik.com. All rights reserved.
//

#import "DTCoreTextLayoutFrame.h"

/**
The **Cursor** category extends DTCoreTextLayoutFrame for working with a caret and determine the string index of touch coordinates.
*/

@interface DTCoreTextLayoutFrame (Cursor)

/**
Determines the closest string index to a point in the receiver's frame.
This can be used to find the cursor position to position an input caret at.
@param point The point
@returns The resulting string index
*/
- (NSInteger)closestCursorIndexToPoint:(CGPoint)point;

/**
The rectangle to draw a caret for a given index
@param index The string index for which to determine a cursor frame
@returns The cursor rectangle
*/
- (CGRect)cursorRectAtIndex:(NSInteger)index;

@end
114 changes: 114 additions & 0 deletions Core/Source/DTCoreTextLayoutFrame+Cursor.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// DTCoreTextLayoutFrame+Cursor.m
// DTCoreText
//
// Created by Oliver Drobnik on 10.07.13.
// Copyright (c) 2013 Drobnik.com. All rights reserved.
//

#import "DTCoreTextLayoutFrame+Cursor.h"
#import "DTCoreTextLayoutLine.h"

@implementation DTCoreTextLayoutFrame (Cursor)

- (NSInteger)closestCursorIndexToPoint:(CGPoint)point
{
NSArray *lines = self.lines;

if (![lines count])
{
return NSNotFound;
}

DTCoreTextLayoutLine *firstLine = [lines objectAtIndex:0];
if (point.y < CGRectGetMinY(firstLine.frame))
{
return 0;
}

DTCoreTextLayoutLine *lastLine = [lines lastObject];
if (point.y > CGRectGetMaxY(lastLine.frame))
{
NSRange stringRange = [self visibleStringRange];

if (stringRange.length)
{
return NSMaxRange([self visibleStringRange])-1;
}
}

// find closest line
DTCoreTextLayoutLine *closestLine = nil;
CGFloat closestDistance = CGFLOAT_MAX;

for (DTCoreTextLayoutLine *oneLine in lines)
{
// line contains point
if (CGRectGetMinY(oneLine.frame) <= point.y && CGRectGetMaxY(oneLine.frame) >= point.y)
{
closestLine = oneLine;
break;
}

CGFloat top = CGRectGetMinY(oneLine.frame);
CGFloat bottom = CGRectGetMaxY(oneLine.frame);

CGFloat distance = CGFLOAT_MAX;

if (top > point.y)
{
distance = top - point.y;
}
else if (bottom < point.y)
{
distance = point.y - bottom;
}

if (distance < closestDistance)
{
closestLine = oneLine;
closestDistance = distance;
}
}

if (!closestLine)
{
return NSNotFound;
}

NSInteger closestIndex = [closestLine stringIndexForPosition:point];

NSInteger maxIndex = NSMaxRange([closestLine stringRange])-1;

if (closestIndex > maxIndex)
{
closestIndex = maxIndex;
}

if (closestIndex>=0)
{
return closestIndex;
}

return NSNotFound;
}

- (CGRect)cursorRectAtIndex:(NSInteger)index
{
DTCoreTextLayoutLine *line = [self lineContainingIndex:index];

if (!line)
{
return CGRectZero;
}

CGFloat offset = [line offsetForStringIndex:index];

CGRect rect = line.frame;
rect.size.width = 3.0;
rect.origin.x += offset;

return rect;
}

@end
36 changes: 15 additions & 21 deletions Core/Source/DTCoreTextLayoutFrame.m
Original file line number Diff line number Diff line change
Expand Up @@ -1144,13 +1144,26 @@ - (void)drawInContext:(CGContextRef)context options:(DTCoreTextLayoutFrameDrawin
runIndex ++;
}

DTTextAttachment *attachment = oneRun.attachment;

if (drawImages && [attachment conformsToProtocol:@protocol(DTTextAttachmentDrawing)])
{
id<DTTextAttachmentDrawing> drawableAttachment = (id<DTTextAttachmentDrawing>)attachment;

// frame might be different due to image vertical alignment
CGFloat ascender = [attachment ascentForLayout];
CGRect rect = CGRectMake(oneRun.frame.origin.x, oneLine.baselineOrigin.y - ascender, attachment.displaySize.width, attachment.displaySize.height);

[drawableAttachment drawInRect:rect context:context];
}

if (!drawLinks && oneRun.isHyperlink)
{
continue;
}

// don't draw decorations on images
if (oneRun.attachment)
if (attachment)
{
continue;
}
Expand Down Expand Up @@ -1210,26 +1223,7 @@ - (void)drawInContext:(CGContextRef)context options:(DTCoreTextLayoutFrameDrawin

CGContextSetTextPosition(context, textPosition.x, textPosition.y);

DTTextAttachment *attachment = oneRun.attachment;

if (attachment)
{
if (drawImages && [attachment conformsToProtocol:@protocol(DTTextAttachmentDrawing)])
{
id<DTTextAttachmentDrawing> drawableAttachment = (id<DTTextAttachmentDrawing>)attachment;

// frame might be different due to image vertical alignment
CGFloat ascender = [attachment ascentForLayout];
CGFloat descender = [attachment descentForLayout];

CGPoint origin = oneRun.frame.origin;
origin.y = self.frame.size.height - origin.y - ascender - descender;
CGRect flippedRect = CGRectMake(roundf(origin.x), roundf(origin.y), attachment.displaySize.width, attachment.displaySize.height);

[drawableAttachment drawInRect:flippedRect context:context];
}
}
else
if (!oneRun.attachment)
{
NSArray *shadows = [oneRun.attributes objectForKey:DTShadowsAttribute];

Expand Down
Loading

0 comments on commit b1e5a27

Please sign in to comment.