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

@ -120,7 +120,6 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
private let scrollNode: ASScrollNode
private let textNode: ImmediateTextNode
private var textSelectionNode: TextSelectionNode?
private let authorNameNode: ASTextNode
private let dateNode: ASTextNode
private let backwardButton: HighlightableButtonNode
@ -362,23 +361,6 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
}
self.statusButtonNode.addTarget(self, action: #selector(self.statusPressed), forControlEvents: .touchUpInside)
let accentColor = presentationData.theme.list.itemAccentColor
let textSelectionNode = TextSelectionNode(theme: TextSelectionTheme(selection: accentColor.withAlphaComponent(0.2), knob: accentColor), strings: presentationData.strings, textNode: self.textNode, updateIsActive: { [weak self] value in
// self?.updateIsTextSelectionActive?(value)
}, present: { [weak self] c, a in
present(c, a)
}, rootNode: self, performAction: { [weak self] text, action in
// guard let strongSelf = self, let item = strongSelf.item else {
// return
// }
// item.controllerInteraction.performTextSelectionAction(item.message.stableId, text, action)
})
self.textSelectionNode = textSelectionNode
self.scrollNode.addSubnode(textSelectionNode)
self.scrollNode.insertSubnode(textSelectionNode.highlightAreaNode, belowSubnode: self.textNode)
textSelectionNode.frame = self.textNode.frame
textSelectionNode.highlightAreaNode.frame = self.textNode.frame
}
deinit {
@ -608,12 +590,6 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
textFrame = CGRect(origin: CGPoint(x: sideInset, y: topInset + textOffset), size: textSize)
if self.textNode.frame != textFrame {
self.textNode.frame = textFrame
if let textSelectionNode = self.textSelectionNode {
textSelectionNode.frame = textFrame
textSelectionNode.highlightAreaNode.frame = textFrame
textSelectionNode.updateLayout()
}
}
}

View File

@ -47,8 +47,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
private let scrollNodeHeader: ASDisplayNode
private let scrollNodeFooter: ASDisplayNode
private var linkHighlightingNode: LinkHighlightingNode?
private var textSelectionNode: InstantPageTextSelectionNode?
private var textSelectionNode: LinkHighlightingNode?
private var settingsNode: InstantPageSettingsNode?
private var settingsDimNode: ASDisplayNode?
@ -156,31 +155,6 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|> deliverOnMainQueue).start(next: { [weak self] value in
self?.navigationBar.setLoadProgress(value)
}))
let selectionNode = InstantPageTextSelectionNode(theme: InstantPageTextSelectionTheme(selection: presentationTheme.chat.message.incoming.textSelectionColor, knob: presentationTheme.chat.message.incoming.textSelectionKnobColor), strings: strings, textItemAtLocation: { [weak self] point in
if let strongSelf = self {
return strongSelf.textItemAtLocation(point)
}
return nil
}, updateIsActive: { active in
}, present: { [weak self] controller, args in
if let strongSelf = self {
strongSelf.present(controller, args)
}
}, rootNode: self, performAction: { text, action in
// let controller = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: {
// UIPasteboard.general.string = text
// }), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
// if let strongSelf = self, let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
// strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
// }
// })])
})
// self.scrollNode.addSubnode(selectionNode)
self.textSelectionNode = selectionNode
self.scrollNode.addSubnode(selectionNode.highlightAreaNode)
}
deinit {
@ -484,7 +458,6 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.scrollNode.view.contentSize = currentLayout.contentSize
self.scrollNodeFooter.frame = CGRect(origin: CGPoint(x: 0.0, y: currentLayout.contentSize.height), size: CGSize(width: containerLayout.size.width, height: 2000.0))
self.textSelectionNode?.frame = CGRect(origin: CGPoint(), size: self.scrollNode.view.contentSize)
}
func updateVisibleItems(visibleBounds: CGRect, animated: Bool = false) {
@ -656,7 +629,6 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
if effectiveContentHeight != self.scrollNode.view.contentSize.height {
transition.animateView {
self.scrollNode.view.contentSize = CGSize(width: currentLayout.contentSize.width, height: effectiveContentHeight)
self.textSelectionNode?.frame = CGRect(origin: CGPoint(), size: self.scrollNode.view.contentSize)
}
let previousFrame = self.scrollNodeFooter.frame
self.scrollNodeFooter.frame = CGRect(origin: CGPoint(x: 0.0, y: effectiveContentHeight), size: CGSize(width: previousFrame.width, height: 2000.0))
@ -971,12 +943,12 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
])])
self.present(actionSheet, nil)
} else if let (item, parentOffset) = self.textItemAtLocation(location) {
// let textFrame = item.frame
// var itemRects = item.lineRects()
// for i in 0 ..< itemRects.count {
// itemRects[i] = itemRects[i].offsetBy(dx: parentOffset.x + textFrame.minX, dy: parentOffset.y + textFrame.minY).insetBy(dx: -2.0, dy: -2.0)
// }
// self.updateTextSelectionRects(itemRects, text: item.plainText())
let textFrame = item.frame
var itemRects = item.lineRects()
for i in 0 ..< itemRects.count {
itemRects[i] = itemRects[i].offsetBy(dx: parentOffset.x + textFrame.minX, dy: parentOffset.y + textFrame.minY).insetBy(dx: -2.0, dy: -2.0)
}
self.updateTextSelectionRects(itemRects, text: item.plainText())
}
default:
break
@ -987,6 +959,51 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
private func updateTextSelectionRects(_ rects: [CGRect], text: String?) {
if let text = text, !rects.isEmpty {
let textSelectionNode: LinkHighlightingNode
if let current = self.textSelectionNode {
textSelectionNode = current
} else {
textSelectionNode = LinkHighlightingNode(color: UIColor.lightGray.withAlphaComponent(0.4))
textSelectionNode.isUserInteractionEnabled = false
self.textSelectionNode = textSelectionNode
self.scrollNode.addSubnode(textSelectionNode)
}
textSelectionNode.frame = CGRect(origin: CGPoint(), size: self.scrollNode.bounds.size)
textSelectionNode.updateRects(rects)
var coveringRect = rects[0]
for i in 1 ..< rects.count {
coveringRect = coveringRect.union(rects[i])
}
let controller = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: {
UIPasteboard.general.string = text
}), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
if let strongSelf = self, let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
}
})])
controller.dismissed = { [weak self] in
self?.updateTextSelectionRects([], text: nil)
}
self.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
if let strongSelf = self {
return (strongSelf.scrollNode, coveringRect.insetBy(dx: -3.0, dy: -3.0), strongSelf, strongSelf.bounds)
} else {
return nil
}
}))
textSelectionNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
} else if let textSelectionNode = self.textSelectionNode {
self.textSelectionNode = nil
textSelectionNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.18, removeOnCompletion: false, completion: { [weak textSelectionNode] _ in
textSelectionNode?.removeFromSupernode()
})
}
}
private func findAnchorItem(_ anchor: String, items: [InstantPageItem]) -> (InstantPageItem, CGFloat, Bool, [InstantPageDetailsItem])? {
for item in items {
if let item = item as? InstantPageAnchorItem, item.anchor == anchor {

View File

@ -3,6 +3,12 @@
@class TGPaintSwatch;
@class TGPhotoPaintFont;
typedef enum {
TGPhotoPaintTextEntityStyleBorder,
TGPhotoPaintTextEntityStyleClassic,
TGPhotoPaintTextEntityStyleFrame
} TGPhotoPaintTextEntityStyle;
@interface TGPhotoPaintTextEntity : TGPhotoPaintEntity
@property (nonatomic, strong) NSString *text;
@ -10,10 +16,10 @@
@property (nonatomic, strong) TGPaintSwatch *swatch;
@property (nonatomic, assign) CGFloat baseFontSize;
@property (nonatomic, assign) CGFloat maxWidth;
@property (nonatomic, assign) bool stroke;
@property (nonatomic, assign) TGPhotoPaintTextEntityStyle style;
@property (nonatomic, strong) UIImage *renderImage;
- (instancetype)initWithText:(NSString *)text font:(TGPhotoPaintFont *)font swatch:(TGPaintSwatch *)swatch baseFontSize:(CGFloat)baseFontSize maxWidth:(CGFloat)maxWidth stroke:(bool)stroke;
- (instancetype)initWithText:(NSString *)text font:(TGPhotoPaintFont *)font swatch:(TGPaintSwatch *)swatch baseFontSize:(CGFloat)baseFontSize maxWidth:(CGFloat)maxWidth style:(TGPhotoPaintTextEntityStyle)style;
@end

View File

@ -40,7 +40,6 @@
- (void)cleanup;
- (void)setImage:(UIImage *)image forCropRect:(CGRect)cropRect cropRotation:(CGFloat)cropRotation cropOrientation:(UIImageOrientation)cropOrientation cropMirrored:(bool)cropMirrored fullSize:(bool)fullSize;
- (void)setVideoAsset:(AVAsset *)asset;
- (void)setPlayerItem:(AVPlayerItem *)playerItem;
- (void)setCIImage:(CIImage *)ciImage;

View File

@ -160,18 +160,6 @@
_fullSize = fullSize;
}
- (void)setVideoAsset:(AVAsset *)asset {
[_toolComposer invalidate];
_currentProcessChain = nil;
[_currentInput removeAllTargets];
PGVideoMovie *movie = [[PGVideoMovie alloc] initWithAsset:asset];
movie.shouldRepeat = true;
_currentInput = movie;
_fullSize = true;
}
- (void)setPlayerItem:(AVPlayerItem *)playerItem {
[_toolComposer invalidate];
_currentProcessChain = nil;

View File

@ -70,6 +70,12 @@
UIImage *_screenImage;
UIImage *_thumbnailImage;
AVPlayerItem *_playerItem;
AVPlayer *_player;
SMetaDisposable *_playerItemDisposable;
id _playerStartedObserver;
id _playerReachedEndObserver;
id<TGMediaEditAdjustments> _initialAdjustments;
NSString *_caption;
@ -395,7 +401,13 @@
if ([next isKindOfClass:[UIImage class]]) {
[_photoEditor setImage:(UIImage *)next forCropRect:_photoEditor.cropRect cropRotation:_photoEditor.cropRotation cropOrientation:_photoEditor.cropOrientation cropMirrored:_photoEditor.cropMirrored fullSize:false];
} else if ([next isKindOfClass:[AVAsset class]]) {
[_photoEditor setVideoAsset:(AVAsset *)next];
_playerItem = [AVPlayerItem playerItemWithAsset:(AVAsset *)next];
_player = [AVPlayer playerWithPlayerItem:_playerItem];
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
_player.muted = true;
[_photoEditor setPlayerItem:_playerItem];
TGDispatchOnMainThread(^
{
[_previewView performTransitionInWithCompletion:^
@ -430,6 +442,66 @@
}];
}
- (void)_setupPlaybackStartedObserver
{
CMTime startTime = CMTimeMake(10, 100);
if (_photoEditor.trimStartValue > DBL_EPSILON)
startTime = CMTimeMakeWithSeconds(_photoEditor.trimStartValue + 0.1, NSEC_PER_SEC);
__weak TGPhotoEditorController *weakSelf = self;
_playerStartedObserver = [_player addBoundaryTimeObserverForTimes:@[[NSValue valueWithCMTime:startTime]] queue:NULL usingBlock:^
{
__strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf->_player removeTimeObserver:strongSelf->_playerStartedObserver];
strongSelf->_playerStartedObserver = nil;
if (CMTimeGetSeconds(strongSelf->_player.currentItem.duration) > 0)
[strongSelf _setupPlaybackReachedEndObserver];
}];
}
- (void)_setupPlaybackReachedEndObserver
{
CMTime endTime = CMTimeSubtract(_player.currentItem.duration, CMTimeMake(10, 100));
if (_photoEditor.trimEndValue > DBL_EPSILON && _photoEditor.trimEndValue < CMTimeGetSeconds(_player.currentItem.duration))
endTime = CMTimeMakeWithSeconds(_photoEditor.trimEndValue - 0.1, NSEC_PER_SEC);
CMTime startTime = CMTimeMake(5, 100);
if (_photoEditor.trimStartValue > DBL_EPSILON)
startTime = CMTimeMakeWithSeconds(_photoEditor.trimStartValue + 0.05, NSEC_PER_SEC);
__weak TGPhotoEditorController *weakSelf = self;
_playerReachedEndObserver = [_player addBoundaryTimeObserverForTimes:@[[NSValue valueWithCMTime:endTime]] queue:NULL usingBlock:^
{
__strong TGPhotoEditorController *strongSelf = weakSelf;
if (strongSelf != nil)
[strongSelf->_player seekToTime:startTime];
}];
}
- (void)startVideoPlayback {
NSTimeInterval startPosition = 0.0f;
if (_photoEditor.trimStartValue > DBL_EPSILON)
startPosition = _photoEditor.trimStartValue;
CMTime targetTime = CMTimeMakeWithSeconds(startPosition, NSEC_PER_SEC);
[_player.currentItem seekToTime:targetTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
[self _setupPlaybackStartedObserver];
[_player play];
}
- (void)stopVideoPlayback {
if (_playerStartedObserver != nil)
[_player removeTimeObserver:_playerStartedObserver];
if (_playerReachedEndObserver != nil)
[_player removeTimeObserver:_playerReachedEndObserver];
[_player pause];
}
- (void)viewWillAppear:(BOOL)animated
{
if (![self inFormSheet] && (self.navigationController != nil || self.dontHideStatusBar))
@ -870,6 +942,7 @@
strongSelf.finishedTransitionIn();
strongSelf->_switchingTab = false;
[strongSelf startVideoPlayback];
};
controller = paintController;
@ -1119,6 +1192,8 @@
strongSelf.finishedTransitionIn();
strongSelf->_switchingTab = false;
[strongSelf startVideoPlayback];
};
controller = toolsController;

View File

@ -99,7 +99,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
bool _appeared;
TGPhotoPaintFont *_selectedTextFont;
bool _selectedStroke;
TGPhotoPaintTextEntityStyle _selectedTextStyle;
TGPhotoEntitiesContainerView *_entitiesContainerView;
TGPhotoPaintEntityView *_currentEntityView;
@ -156,7 +156,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[[TGPaintNeonBrush alloc] init]
];
_selectedTextFont = [[TGPhotoPaintFont availableFonts] firstObject];
_selectedStroke = true;
_selectedTextStyle = TGPhotoPaintTextEntityStyleBorder;
if (_photoEditor.paintingData.undoManager != nil)
_undoManager = [_photoEditor.paintingData.undoManager copy];
@ -1106,10 +1106,10 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
TGPaintSwatch *currentSwatch = _portraitSettingsView.swatch;
TGPaintSwatch *whiteSwatch = [TGPaintSwatch swatchWithColor:[UIColor whiteColor] colorLocation:1.0f brushWeight:currentSwatch.brushWeight];
TGPaintSwatch *blackSwatch = [TGPaintSwatch swatchWithColor:[UIColor blackColor] colorLocation:0.85f brushWeight:currentSwatch.brushWeight];
[self setCurrentSwatch:_selectedStroke ? blackSwatch : whiteSwatch sender:nil];
[self setCurrentSwatch:_selectedTextStyle == TGPhotoPaintTextEntityStyleBorder ? blackSwatch : whiteSwatch sender:nil];
CGFloat maxWidth = [self fittedContentSize].width - 26.0f;
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:@"" font:_selectedTextFont swatch:_portraitSettingsView.swatch baseFontSize:[self _textBaseFontSizeForCurrentPainting] maxWidth:maxWidth stroke:_selectedStroke];
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:@"" font:_selectedTextFont swatch:_portraitSettingsView.swatch baseFontSize:[self _textBaseFontSizeForCurrentPainting] maxWidth:maxWidth style:_selectedTextStyle];
entity.position = [self startPositionRelativeToEntity:nil];
entity.angle = [self startRotation];
@ -1413,7 +1413,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
- (void)presentTextSettingsView
{
TGPhotoTextSettingsView *view = [[TGPhotoTextSettingsView alloc] initWithFonts:[TGPhotoPaintFont availableFonts] selectedFont:_selectedTextFont selectedStroke:_selectedStroke];
TGPhotoTextSettingsView *view = [[TGPhotoTextSettingsView alloc] initWithFonts:[TGPhotoPaintFont availableFonts] selectedFont:_selectedTextFont selectedStyle:_selectedTextStyle];
__weak TGPhotoPaintController *weakSelf = self;
view.fontChanged = ^(TGPhotoPaintFont *font)
@ -1429,21 +1429,21 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
[strongSelf settingsWrapperPressed];
};
view.strokeChanged = ^(bool stroke)
view.styleChanged = ^(TGPhotoPaintTextEntityStyle style)
{
__strong TGPhotoPaintController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_selectedStroke = stroke;
strongSelf->_selectedTextStyle = style;
if (stroke && [strongSelf->_portraitSettingsView.swatch.color isEqual:[UIColor whiteColor]])
if (style == TGPhotoPaintTextEntityStyleBorder && [strongSelf->_portraitSettingsView.swatch.color isEqual:[UIColor whiteColor]])
{
TGPaintSwatch *currentSwatch = strongSelf->_portraitSettingsView.swatch;
TGPaintSwatch *blackSwatch = [TGPaintSwatch swatchWithColor:[UIColor blackColor] colorLocation:0.85f brushWeight:currentSwatch.brushWeight];
[strongSelf setCurrentSwatch:blackSwatch sender:nil];
}
else if (!stroke && [strongSelf->_portraitSettingsView.swatch.color isEqual:UIColorRGB(0x000000)])
else if (style != TGPhotoPaintTextEntityStyleBorder && [strongSelf->_portraitSettingsView.swatch.color isEqual:UIColorRGB(0x000000)])
{
TGPaintSwatch *currentSwatch = strongSelf->_portraitSettingsView.swatch;
TGPaintSwatch *whiteSwatch = [TGPaintSwatch swatchWithColor:[UIColor whiteColor] colorLocation:1.0f brushWeight:currentSwatch.brushWeight];
@ -1451,7 +1451,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
}
TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)strongSelf->_currentEntityView;
[textView setStroke:stroke];
[textView setStyle:style];
[strongSelf settingsWrapperPressed];
};

View File

@ -5,7 +5,7 @@
@implementation TGPhotoPaintTextEntity
- (instancetype)initWithText:(NSString *)text font:(TGPhotoPaintFont *)font swatch:(TGPaintSwatch *)swatch baseFontSize:(CGFloat)baseFontSize maxWidth:(CGFloat)maxWidth stroke:(bool)stroke
- (instancetype)initWithText:(NSString *)text font:(TGPhotoPaintFont *)font swatch:(TGPaintSwatch *)swatch baseFontSize:(CGFloat)baseFontSize maxWidth:(CGFloat)maxWidth style:(TGPhotoPaintTextEntityStyle)style
{
self = [super init];
if (self != nil)
@ -15,7 +15,7 @@
_swatch = swatch;
_baseFontSize = baseFontSize;
_maxWidth = maxWidth;
_stroke = stroke;
_style = style;
self.scale = 1.0f;
}
return self;
@ -23,7 +23,7 @@
- (instancetype)copyWithZone:(NSZone *)__unused zone
{
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:self.text font:self.font swatch:self.swatch baseFontSize:self.baseFontSize maxWidth:self.maxWidth stroke:self.stroke];
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:self.text font:self.font swatch:self.swatch baseFontSize:self.baseFontSize maxWidth:self.maxWidth style:self.style];
entity->_uuid = self.uuid;
entity.position = self.position;
@ -46,7 +46,7 @@
return false;
TGPhotoPaintTextEntity *entity = (TGPhotoPaintTextEntity *)object;
return entity.uuid == self.uuid && [entity.text isEqualToString:self.text] && [entity.font isEqual:self.font] && [entity.swatch isEqual:self.swatch] && fabs(entity.baseFontSize - self.baseFontSize) < FLT_EPSILON && fabs(entity.maxWidth - self.maxWidth) < FLT_EPSILON && entity.stroke == self.stroke && CGPointEqualToPoint(entity.position, self.position) && fabs(entity.scale - self.scale) < FLT_EPSILON && fabs(entity.angle - self.angle) < FLT_EPSILON && entity.mirrored == self.mirrored;
return entity.uuid == self.uuid && [entity.text isEqualToString:self.text] && [entity.font isEqual:self.font] && [entity.swatch isEqual:self.swatch] && fabs(entity.baseFontSize - self.baseFontSize) < FLT_EPSILON && fabs(entity.maxWidth - self.maxWidth) < FLT_EPSILON && entity.style == self.style && CGPointEqualToPoint(entity.position, self.position) && fabs(entity.scale - self.scale) < FLT_EPSILON && fabs(entity.angle - self.angle) < FLT_EPSILON && entity.mirrored == self.mirrored;
}
@end

View File

@ -21,7 +21,7 @@
- (instancetype)initWithEntity:(TGPhotoPaintTextEntity *)entity;
- (void)setFont:(TGPhotoPaintFont *)font;
- (void)setSwatch:(TGPaintSwatch *)swatch;
- (void)setStroke:(bool)stroke;
- (void)setStyle:(TGPhotoPaintTextEntityStyle)style;
@property (nonatomic, readonly) bool isEditing;
- (void)beginEditing;
@ -35,5 +35,7 @@
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGPoint strokeOffset;
@property (nonatomic, strong) UIColor *frameColor;
@property (nonatomic, assign) CGFloat frameWidthInset;
@end

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

View File

@ -1,15 +1,16 @@
#import <UIKit/UIKit.h>
#import "TGPhotoPaintSettingsView.h"
#import "TGPhotoPaintFont.h"
#import "TGPhotoPaintTextEntity.h"
@interface TGPhotoTextSettingsView : UIView <TGPhotoPaintPanelView>
@property (nonatomic, copy) void (^fontChanged)(TGPhotoPaintFont *font);
@property (nonatomic, copy) void (^strokeChanged)(bool stroke);
@property (nonatomic, copy) void (^styleChanged)(TGPhotoPaintTextEntityStyle style);
@property (nonatomic, strong) TGPhotoPaintFont *font;
@property (nonatomic, assign) bool stroke;
@property (nonatomic, assign) TGPhotoPaintTextEntityStyle style;
- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)font selectedStroke:(bool)selectedStroke;
- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)font selectedStyle:(TGPhotoPaintTextEntityStyle)selectedStyle;
@end

View File

@ -22,8 +22,6 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
NSArray *_fontViews;
NSArray *_fontSeparatorViews;
UIImageView *_selectedCheckView;
UIView *_separatorView;
}
@end
@ -31,7 +29,7 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
@synthesize interfaceOrientation = _interfaceOrientation;
- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)__unused selectedFont selectedStroke:(bool)selectedStroke
- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)__unused selectedFont selectedStyle:(TGPhotoPaintTextEntityStyle)selectedStyle
{
self = [super initWithFrame:CGRectZero];
if (self)
@ -53,10 +51,10 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
outlineButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
outlineButton.titleLabel.font = font;
outlineButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 44.0f, 0.0f, 0.0f);
outlineButton.tag = 0;
outlineButton.tag = TGPhotoPaintTextEntityStyleBorder;
[outlineButton setTitle:@"" forState:UIControlStateNormal];
[outlineButton setTitleColor:[UIColor clearColor]];
[outlineButton addTarget:self action:@selector(strokeValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[outlineButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:outlineButton];
[fontViews addObject:outlineButton];
@ -75,27 +73,52 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
UIView *separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGB(0xd6d6da);
[self addSubview:separatorView];
[separatorViews addObject:separatorView];
TGModernButton *regularButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight, 0, 0)];
regularButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
regularButton.titleLabel.font = font;
regularButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 44.0f, 0.0f, 0.0f);
regularButton.tag = 1;
regularButton.tag = TGPhotoPaintTextEntityStyleClassic;
[regularButton setTitle:TGLocalized(@"Paint.Regular") forState:UIControlStateNormal];
[regularButton setTitleColor:[UIColor blackColor]];
[regularButton addTarget:self action:@selector(strokeValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[regularButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:regularButton];
[fontViews addObject:regularButton];
separatorView = [[UIView alloc] init];
separatorView.backgroundColor = UIColorRGB(0xd6d6da);
[self addSubview:separatorView];
[separatorViews addObject:separatorView];
TGModernButton *frameButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight + TGPhotoTextSettingsItemHeight, 0, 0)];
frameButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
frameButton.titleLabel.font = font;
frameButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 44.0f, 0.0f, 0.0f);
frameButton.tag = TGPhotoPaintTextEntityStyleFrame;
[frameButton setTitle:@"" forState:UIControlStateNormal];
[frameButton setTitleColor:[UIColor blackColor]];
[frameButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:frameButton];
[fontViews addObject:frameButton];
textView = [[TGPhotoTextView alloc] init];
textView.backgroundColor = [UIColor clearColor];
textView.textColor = [UIColor whiteColor];
textView.frameColor = [UIColor blackColor];
textView.font = font;
textView.text = @"Framed";
[textView sizeToFit];
textView.frame = CGRectMake(39.0f, ceil((TGPhotoTextSettingsItemHeight - textView.frame.size.height) / 2.0f) - 1.0f, ceil(textView.frame.size.width), ceil(textView.frame.size.height + 0.5f));
[frameButton addSubview:textView];
_fontViews = fontViews;
_fontSeparatorViews = separatorViews;
_selectedCheckView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PaintCheck")];
_selectedCheckView.frame = CGRectMake(15.0f, 16.0f, _selectedCheckView.frame.size.width, _selectedCheckView.frame.size.height);
[self setStroke:selectedStroke];
[self setStyle:selectedStyle];
}
return self;
}
@ -108,10 +131,10 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
self.fontChanged(_fonts[sender.tag]);
}
- (void)strokeValueChanged:(TGModernButton *)sender
- (void)styleValueChanged:(TGModernButton *)sender
{
if (self.strokeChanged != nil)
self.strokeChanged(1 - sender.tag);
if (self.styleChanged != nil)
self.styleChanged((TGPhotoPaintTextEntityStyle)sender.tag);
}
- (void)present
@ -145,14 +168,14 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
}];
}
- (bool)stroke
- (TGPhotoPaintTextEntityStyle)style
{
return 1 - _selectedCheckView.superview.tag;
return (TGPhotoPaintTextEntityStyle)_selectedCheckView.superview.tag;
}
- (void)setStroke:(bool)stroke
- (void)setStyle:(TGPhotoPaintTextEntityStyle)style
{
[_fontViews[1 - stroke] addSubview:_selectedCheckView];
[_fontViews[style] addSubview:_selectedCheckView];
}
- (NSString *)font
@ -236,8 +259,6 @@ const CGFloat TGPhotoTextSettingsItemHeight = 44.0f;
{
view.frame = CGRectMake(TGPhotoTextSettingsViewMargin + 44.0f, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight * (index + 1), self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 - 44.0f, thickness);
}];
_separatorView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin + TGPhotoTextSettingsItemHeight * _fontViews.count, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2, thickness);
}
@end

View File

@ -88,7 +88,7 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
} else if ([dict[@"type"] isEqualToString:@"text"]) {
UIImage *renderImage = [[UIImage alloc] initWithData:dict[@"data"]];
if (renderImage != nil) {
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:nil font:nil swatch:nil baseFontSize:0.0 maxWidth:0.0 stroke:false];
TGPhotoPaintTextEntity *entity = [[TGPhotoPaintTextEntity alloc] initWithText:nil font:nil swatch:nil baseFontSize:0.0 maxWidth:0.0 style:TGPhotoPaintTextEntityStyleClassic];
entity.uuid = [dict[@"uuid"] integerValue];
entity.position = [dict[@"position"] CGPointValue];
entity.scale = [dict[@"scale"] floatValue];

View File

@ -15,6 +15,7 @@ protocol LegacyPaintEntity {
var scale: CGFloat { get }
var angle: CGFloat { get }
var baseSize: CGSize? { get }
var mirrored: Bool { get }
func image(for time: CMTime, completion: @escaping (CIImage?) -> Void)
}
@ -36,6 +37,10 @@ private class LegacyPaintStickerEntity: LegacyPaintEntity {
return self.entity.baseSize
}
var mirrored: Bool {
return self.entity.mirrored
}
let account: Account
let file: TelegramMediaFile
let entity: TGPhotoPaintStickerEntity
@ -183,6 +188,10 @@ private class LegacyPaintTextEntity: LegacyPaintEntity {
var baseSize: CGSize? {
return nil
}
var mirrored: Bool {
return false
}
let entity: TGPhotoPaintTextEntity
@ -239,8 +248,8 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
public func entities(for time: CMTime, size: CGSize, completion: (([CIImage]?) -> Void)!) {
let entities = self.entities
// let originalSize = self.originalSize
// let cropRect = self.cropRect
let maxSide = max(size.width, size.height)
let paintingScale = maxSide / 1920.0
self.queue.async {
if entities.isEmpty {
@ -262,9 +271,6 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
}
entity.image(for: time, completion: { image in
if var image = image {
let maxSide = max(size.width, size.height)
let paintingScale = maxSide / 1920.0
var transform = CGAffineTransform(translationX: -image.extent.midX, y: -image.extent.midY)
image = image.transformed(by: transform)
@ -276,6 +282,9 @@ public final class LegacyPaintEntityRenderer: NSObject, TGPhotoPaintEntityRender
transform = CGAffineTransform(translationX: entity.position.x * paintingScale, y: size.height - entity.position.y * paintingScale)
transform = transform.rotated(by: CGFloat.pi * 2 - entity.angle)
transform = transform.scaledBy(x: scale, y: scale)
if entity.mirrored {
transform = transform.scaledBy(x: -1.0, y: 1.0)
}
image = image.transformed(by: transform)
let _ = images.modify { current in