Video editor fixes

This commit is contained in:
Ilya Laktyushin
2020-05-26 11:11:27 +03:00
parent 01a3152ce4
commit 3185ffb47c
14 changed files with 509 additions and 149 deletions

View File

@@ -30,6 +30,14 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGPoint strokeOffset;
@property (nonatomic, assign) UIColor *frameColor;
@property (nonatomic, assign) CGFloat frameWidthInset;
@property (nonatomic, assign) CGFloat frameCornerRadius;
@end
@interface TGPhotoTextStorage : NSTextStorage
@end
@@ -40,7 +48,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
TGPhotoPaintFont *_font;
CGFloat _baseFontSize;
CGFloat _maxWidth;
bool _stroke;
TGPhotoPaintTextEntityStyle _style;
TGPhotoTextView *_textView;
}
@@ -68,8 +76,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
_textView.selectable = false;
_textView.contentInset = UIEdgeInsetsZero;
_textView.showsHorizontalScrollIndicator = false;
_textView.showsVerticalScrollIndicator = false;
_textView.textContainerInset = UIEdgeInsetsZero;
_textView.showsVerticalScrollIndicator = false;;
_textView.scrollsToTop = false;
_textView.scrollEnabled = false;
_textView.textContainerInset = UIEdgeInsetsZero;
@@ -80,9 +87,10 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
_textView.autocorrectionType = UITextAutocorrectionTypeNo;
_textView.spellCheckingType = UITextSpellCheckingTypeNo;
_textView.font = [UIFont boldSystemFontOfSize:_baseFontSize];
_textView.frameWidthInset = floor(_baseFontSize * 0.03);
[self setSwatch:entity.swatch];
[self setStroke:entity.stroke];
[self setStyle:entity.style];
[self addSubview:_textView];
}
@@ -96,7 +104,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
- (TGPhotoPaintTextEntity *)entity
{
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:_textView.text font:_font swatch:_swatch baseFontSize:_baseFontSize maxWidth:_maxWidth stroke:_stroke];
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:_textView.text font:_font swatch:_swatch baseFontSize:_baseFontSize maxWidth:_maxWidth style:_style];
entity.uuid = _entityUUID;
entity.angle = self.angle;
entity.scale = self.scale;
@@ -109,7 +117,6 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
CGRect rect = self.bounds;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(rect.size.width, rect.size.height), false, 1.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[self drawViewHierarchyInRect:rect afterScreenUpdates:false];
@@ -142,6 +149,8 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
_textView.editable = false;
_textView.selectable = false;
_textView.text = [_textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (self.finishedEditing != nil)
self.finishedEditing(self);
}
@@ -166,25 +175,28 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
{
_font = font;
_textView.font = [UIFont boldSystemFontOfSize:_baseFontSize];
_textView.frameWidthInset = floor(_baseFontSize * 0.03);
[self sizeToFit];
}
- (void)setStroke:(bool)stroke
- (void)setStyle:(TGPhotoPaintTextEntityStyle)style
{
_stroke = stroke;
if (stroke)
{
_textView.layer.shadowRadius = 0.0f;
_textView.layer.shadowOpacity = 0.0f;
_textView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
_textView.layer.shadowColor = [[UIColor clearColor] CGColor];
}
else
{
_textView.layer.shadowColor = [[UIColor blackColor] CGColor];
_textView.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
_textView.layer.shadowOpacity = 0.4f;
_textView.layer.shadowRadius = 4.0f;
_style = style;
switch (_style) {
case TGPhotoPaintTextEntityStyleClassic:
_textView.layer.shadowColor = [[UIColor blackColor] CGColor];
_textView.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
_textView.layer.shadowOpacity = 0.4f;
_textView.layer.shadowRadius = 4.0f;
break;
default:
_textView.layer.shadowRadius = 0.0f;
_textView.layer.shadowOpacity = 0.0f;
_textView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
_textView.layer.shadowColor = [[UIColor clearColor] CGColor];
break;
}
[self updateColor];
@@ -193,15 +205,45 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
- (void)updateColor
{
if (_stroke)
{
_textView.textColor = [UIColor whiteColor];
_textView.strokeColor = _swatch.color;
}
else
{
_textView.textColor = _swatch.color;
_textView.strokeColor = nil;
switch (_style) {
case TGPhotoPaintTextEntityStyleClassic:
{
_textView.textColor = _swatch.color;
_textView.strokeColor = nil;
_textView.frameColor = nil;
}
break;
case TGPhotoPaintTextEntityStyleBorder:
{
_textView.textColor = [UIColor whiteColor];
_textView.strokeColor = _swatch.color;
_textView.frameColor = nil;
}
break;
case TGPhotoPaintTextEntityStyleFrame:
{
CGFloat lightness = 0.0f;
CGFloat r = 0.0f;
CGFloat g = 0.0f;
CGFloat b = 0.0f;
if ([_swatch.color getRed:&r green:&g blue:&b alpha:NULL]) {
lightness = 0.2126f * r + 0.7152f * g + 0.0722f * b;
} else if ([_swatch.color getWhite:&r alpha:NULL]) {
lightness = r;
}
if (lightness > 0.87) {
_textView.textColor = [UIColor blackColor];
} else {
_textView.textColor = [UIColor whiteColor];
}
_textView.strokeColor = nil;
_textView.frameColor = _swatch.color;
}
break;
}
}
@@ -441,7 +483,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
- (instancetype)initWithFrame:(CGRect)frame
{
NSTextStorage *textStorage = [[NSTextStorage alloc] init];
TGPhotoTextStorage *textStorage = [[TGPhotoTextStorage alloc] init];
TGPhotoTextLayoutManager *layoutManager = [[TGPhotoTextLayoutManager alloc] init];
NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(0.0f, CGFLOAT_MAX)];
@@ -449,7 +491,7 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
[layoutManager addTextContainer:container];
[textStorage addLayoutManager:layoutManager];
return [self initWithFrame:frame textContainer:container];;
return [self initWithFrame:frame textContainer:container];
}
- (CGRect)caretRectForPosition:(UITextPosition *)position
@@ -492,10 +534,49 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
[self setNeedsDisplay];
}
- (UIColor *)frameColor {
return ((TGPhotoTextLayoutManager *)self.layoutManager).frameColor;
}
- (void)setFrameColor:(UIColor *)frameColor {
[(TGPhotoTextLayoutManager *)self.layoutManager setFrameColor:frameColor];
[self setNeedsDisplay];
}
- (CGFloat)frameWidthInset {
return ((TGPhotoTextLayoutManager *)self.layoutManager).frameWidthInset;
}
- (void)setFrameWidthInset:(CGFloat)frameWidthInset {
[(TGPhotoTextLayoutManager *)self.layoutManager setFrameWidthInset:frameWidthInset];
[self setNeedsDisplay];
}
- (void)setFont:(UIFont *)font {
[super setFont:font];
self.layoutManager.textContainers.firstObject.lineFragmentPadding = floor(font.pointSize * 0.3);
}
@end
@implementation TGPhotoTextLayoutManager
{
CGFloat _radius;
NSInteger _maxIndex;
NSArray *_pointArray;
UIBezierPath *_path;
NSMutableArray *_rectArray;
}
- (instancetype)init {
self = [super init];
if (self != nil) {
_radius = 8.0f;
}
return self;
}
- (void)showCGGlyphs:(const CGGlyph *)glyphs positions:(const CGPoint *)positions count:(NSUInteger)glyphCount font:(UIFont *)font matrix:(CGAffineTransform)textMatrix attributes:(NSDictionary<NSString *,id> *)attributes inContext:(CGContextRef)context
{
@@ -520,4 +601,189 @@ const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f;
[super showCGGlyphs:glyphs positions:positions count:glyphCount font:font matrix:textMatrix attributes:attributes inContext:context];
}
- (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin {
[super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin];
if (self.frameColor != nil) {
NSRange range = [self characterRangeForGlyphRange:glyphsToShow actualGlyphRange:NULL];
NSRange glyphRange = [self glyphRangeForCharacterRange:range actualCharacterRange:NULL];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, origin.x, origin.y);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextSetFillColorWithColor(context, self.frameColor.CGColor);
CGContextSetStrokeColorWithColor(context, self.frameColor.CGColor);
_path = nil;
[self.rectArray removeAllObjects];
[self enumerateLineFragmentsForGlyphRange:glyphRange usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) {
CGRect newRect = CGRectMake(usedRect.origin.x - self.frameWidthInset, usedRect.origin.y, usedRect.size.width + self.frameWidthInset * 2, usedRect.size.height);
NSValue *value = [NSValue valueWithCGRect:newRect];
[self.rectArray addObject:value];
}];
[self preProccess];
for (int i = 0; i < self.rectArray.count; i ++) {
NSValue *curValue = [self.rectArray objectAtIndex:i];
CGRect cur = curValue.CGRectValue;
_radius = cur.size.height * 0.18;
[self.path appendPath:[UIBezierPath bezierPathWithRoundedRect:cur cornerRadius:_radius]];
CGRect last = CGRectNull;
if (i > 0) {
NSValue *lastValue = [self.rectArray objectAtIndex:i-1];
last = lastValue.CGRectValue;
CGPoint a = cur.origin;
CGPoint b = CGPointMake(CGRectGetMaxX(cur), cur.origin.y);
CGPoint c = CGPointMake(last.origin.x, CGRectGetMaxY(last));
CGPoint d = CGPointMake(CGRectGetMaxX(last), CGRectGetMaxY(last));
if (a.x - c.x >= 2 * _radius) {
UIBezierPath * addPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(a.x - _radius, a.y + _radius) radius:_radius startAngle:M_PI_2 * 3 endAngle:0 clockwise:YES];
[addPath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(a.x + _radius, a.y + _radius) radius:_radius startAngle:M_PI endAngle:3 * M_PI_2 clockwise:YES]];
[addPath addLineToPoint:CGPointMake(a.x - _radius, a.y)];
[self.path appendPath:addPath];
}
if (a.x == c.x) {
[self.path moveToPoint:CGPointMake(a.x, a.y - _radius)];
[self.path addLineToPoint:CGPointMake(a.x, a.y + _radius)];
[self.path addArcWithCenter:CGPointMake(a.x + _radius, a.y + _radius) radius:_radius startAngle:M_PI endAngle:M_PI_2 * 3 clockwise:YES];
[self.path addArcWithCenter:CGPointMake(a.x + _radius, a.y - _radius) radius:_radius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
}
if (d.x - b.x >= 2 * _radius) {
UIBezierPath * addPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(b.x + _radius, b.y + _radius) radius:_radius startAngle:M_PI_2 * 3 endAngle:M_PI clockwise:NO];
[addPath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(b.x - _radius, b.y + _radius) radius:_radius startAngle:0 endAngle:3 * M_PI_2 clockwise:NO]];
[addPath addLineToPoint:CGPointMake(b.x + _radius, b.y)];
[self.path appendPath:addPath];
}
if (d.x == b.x) {
[self.path moveToPoint:CGPointMake(b.x, b.y - _radius)];
[self.path addLineToPoint:CGPointMake(b.x, b.y + _radius)];
[self.path addArcWithCenter:CGPointMake(b.x - _radius, b.y + _radius) radius:_radius startAngle:0 endAngle:M_PI_2 * 3 clockwise:NO];
[self.path addArcWithCenter:CGPointMake(b.x - _radius, b.y - _radius) radius:_radius startAngle:M_PI_2 endAngle:0 clockwise:NO];
}
if (c.x - a.x >= 2 * _radius) {
UIBezierPath * addPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(c.x - _radius, c.y - _radius) radius:_radius startAngle:M_PI_2 endAngle:0 clockwise:NO];
[addPath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(c.x + _radius, c.y - _radius) radius:_radius startAngle:M_PI endAngle:M_PI_2 clockwise:NO]];
[addPath addLineToPoint:CGPointMake(c.x - _radius, c.y)];
[self.path appendPath:addPath];
}
if (b.x - d.x >= 2 * _radius) {
UIBezierPath * addPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(d.x + _radius, d.y - _radius) radius:_radius startAngle:M_PI_2 endAngle:M_PI clockwise:YES];
[addPath appendPath:[UIBezierPath bezierPathWithArcCenter:CGPointMake(d.x - _radius, d.y - _radius) radius:_radius startAngle:0 endAngle:M_PI_2 clockwise:YES]];
[addPath addLineToPoint:CGPointMake(d.x + _radius, d.y)];
[self.path appendPath:addPath];
}
}
}
[self.path fill];
[self.path stroke];
CGContextRestoreGState(context);
}
}
- (UIBezierPath *)path {
if (!_path) {
_path = [UIBezierPath bezierPath];
}
return _path;
}
- (NSMutableArray *)rectArray {
if (!_rectArray) {
_rectArray = [[NSMutableArray alloc] init];
}
return _rectArray;
}
- (void)preProccess {
_maxIndex = 0;
if (self.rectArray.count < 2) {
return;
}
for (int i = 1; i < self.rectArray.count; i++) {
_maxIndex = i;
[self processRectIndex:i];
}
}
- (void)processRectIndex:(int) index {
if (self.rectArray.count < 2 || index < 1 || index > _maxIndex) {
return;
}
NSValue *value1 = [self.rectArray objectAtIndex:index - 1];
NSValue *value2 = [self.rectArray objectAtIndex:index];
CGRect last = value1.CGRectValue;
CGRect cur = value2.CGRectValue;
_radius = cur.size.height * 0.18;
BOOL t1 = ((cur.origin.x - last.origin.x < 2 * _radius) && (cur.origin.x > last.origin.x)) || ((CGRectGetMaxX(cur) - CGRectGetMaxX(last) > -2 * _radius) && (CGRectGetMaxX(cur) < CGRectGetMaxX(last)));
BOOL t2 = ((last.origin.x - cur.origin.x < 2 * _radius) && (last.origin.x > cur.origin.x)) || ((CGRectGetMaxX(last) - CGRectGetMaxX(cur) > -2 * _radius) && (CGRectGetMaxX(last) < CGRectGetMaxX(cur)));
if (t2) {
CGRect newRect = CGRectMake(cur.origin.x, last.origin.y, cur.size.width, last.size.height);
NSValue *newValue = [NSValue valueWithCGRect:newRect];
[self.rectArray replaceObjectAtIndex:index - 1 withObject:newValue];
[self processRectIndex:index - 1];
}
if (t1) {
CGRect newRect = CGRectMake(last.origin.x, cur.origin.y, last.size.width, cur.size.height);
NSValue *newValue = [NSValue valueWithCGRect:newRect];
[self.rectArray replaceObjectAtIndex:index withObject:newValue];
[self processRectIndex:index + 1];
}
return;
}
@end
@implementation TGPhotoTextStorage
{
NSTextStorage *_impl;
}
- (instancetype)init
{
self = [super init];
if (self) {
_impl = [NSTextStorage new];
}
return self;
}
- (NSString *)string
{
return _impl.string;
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
{
return [_impl attributesAtIndex:location effectiveRange:range];
}
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str {
[self beginEditing];
[_impl replaceCharactersInRange:range withString:str];
[self edited:NSTextStorageEditedCharacters range:range changeInLength:(NSInteger)str.length - (NSInteger)range.length];
[self endEditing];
}
- (void)setAttributes:(NSDictionary<NSAttributedStringKey,id> *)attrs range:(NSRange)range {
[self beginEditing];
[_impl setAttributes:attrs range:range];
[self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
[self endEditing];
}
@end