diff --git a/submodules/AttachmentUI/Sources/AttachmentContainer.swift b/submodules/AttachmentUI/Sources/AttachmentContainer.swift index 6e1c73fc0a..ff22529156 100644 --- a/submodules/AttachmentUI/Sources/AttachmentContainer.swift +++ b/submodules/AttachmentUI/Sources/AttachmentContainer.swift @@ -136,10 +136,16 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate { } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - if gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer { + if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer, otherGestureRecognizer is UIPanGestureRecognizer { if let _ = otherGestureRecognizer.view?.superview as? MKMapView { return false } + if let view = otherGestureRecognizer.view, view.description.contains("WKChildScroll") { + let velocity = panGestureRecognizer.velocity(in: nil) + if abs(velocity.x) > abs(velocity.y) * 2.0 { + return false + } + } if let _ = otherGestureRecognizer.view?.asyncdisplaykit_node as? CollectionIndexNode { return false } diff --git a/submodules/DrawingUI/Sources/DrawingBubbleEntity.swift b/submodules/DrawingUI/Sources/DrawingBubbleEntity.swift index 0e71863519..4d8cd77a13 100644 --- a/submodules/DrawingUI/Sources/DrawingBubbleEntity.swift +++ b/submodules/DrawingUI/Sources/DrawingBubbleEntity.swift @@ -295,6 +295,12 @@ final class DrawingBubbleEntititySelectionView: DrawingEntitySelectionView, UIGe entityView.onSnapToYAxis(snapped) } } + + self.snapTool.onSnapRotationUpdated = { [weak self] snappedAngle in + if let strongSelf = self, let entityView = strongSelf.entityView { + entityView.onSnapToAngle(snappedAngle) + } + } } required init?(coder: NSCoder) { @@ -401,6 +407,8 @@ final class DrawingBubbleEntititySelectionView: DrawingEntitySelectionView, UIGe default: break } + + entityView.onPositionUpdated(entity.position) } override func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) { @@ -425,16 +433,29 @@ final class DrawingBubbleEntititySelectionView: DrawingEntitySelectionView, UIGe return } + let velocity = gestureRecognizer.velocity + var updatedRotation = entity.rotation + var rotation: CGFloat = 0.0 + switch gestureRecognizer.state { - case .began, .changed: - let rotation = gestureRecognizer.rotation - entity.rotation += rotation - entityView.update() + case .began: + self.snapTool.maybeSkipFromStart(entityView: entityView, rotation: entity.rotation) + case .changed: + rotation = gestureRecognizer.rotation + updatedRotation += rotation gestureRecognizer.rotation = 0.0 + case .ended, .cancelled: + self.snapTool.rotationReset() default: break } + + updatedRotation = self.snapTool.update(entityView: entityView, velocity: velocity, delta: rotation, updatedRotation: updatedRotation) + entity.rotation = updatedRotation + entityView.update() + + entityView.onPositionUpdated(entity.position) } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { diff --git a/submodules/DrawingUI/Sources/DrawingEntitiesView.swift b/submodules/DrawingUI/Sources/DrawingEntitiesView.swift index 196e05ab87..d13efe89b4 100644 --- a/submodules/DrawingUI/Sources/DrawingEntitiesView.swift +++ b/submodules/DrawingUI/Sources/DrawingEntitiesView.swift @@ -143,6 +143,7 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView { private let xAxisView = UIView() private let yAxisView = UIView() + private let angleLayer = SimpleShapeLayer() private let hapticFeedback = HapticFeedback() public init(context: AccountContext, size: CGSize) { @@ -163,8 +164,13 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView { self.yAxisView.backgroundColor = UIColor(rgb: 0x5fc1f0) self.yAxisView.isUserInteractionEnabled = false + self.angleLayer.strokeColor = UIColor(rgb: 0xffd70a).cgColor + self.angleLayer.opacity = 0.0 + self.angleLayer.lineDashPattern = [12, 12] as [NSNumber] + self.addSubview(self.xAxisView) self.addSubview(self.yAxisView) + self.layer.addSublayer(self.angleLayer) } required init?(coder: NSCoder) { @@ -179,13 +185,20 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView { super.layoutSubviews() let point = self.getEntityCenterPosition() - self.xAxisView.bounds = CGRect(origin: .zero, size: CGSize(width: 10.0, height: 3000.0)) + self.xAxisView.bounds = CGRect(origin: .zero, size: CGSize(width: 6.0, height: 3000.0)) self.xAxisView.center = point self.xAxisView.transform = CGAffineTransform(rotationAngle: self.getEntityInitialRotation()) - self.yAxisView.bounds = CGRect(origin: .zero, size: CGSize(width: 3000.0, height: 10.0)) + self.yAxisView.bounds = CGRect(origin: .zero, size: CGSize(width: 3000.0, height: 6.0)) self.yAxisView.center = point self.yAxisView.transform = CGAffineTransform(rotationAngle: self.getEntityInitialRotation()) + + let anglePath = CGMutablePath() + anglePath.move(to: CGPoint(x: 0.0, y: 3.0)) + anglePath.addLine(to: CGPoint(x: 3000.0, y: 3.0)) + self.angleLayer.path = anglePath + self.angleLayer.lineWidth = 6.0 + self.angleLayer.bounds = CGRect(origin: .zero, size: CGSize(width: 3000.0, height: 6.0)) } var entities: [DrawingEntity] { @@ -359,6 +372,28 @@ public final class DrawingEntitiesView: UIView, TGPhotoDrawingEntitiesView { transition.updateAlpha(layer: strongSelf.yAxisView.layer, alpha: 0.0) } } + view.onSnapToAngle = { [weak self, weak view] snappedToAngle in + guard let strongSelf = self, let strongView = view else { + return + } + let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) + if let snappedToAngle { + strongSelf.layer.insertSublayer(strongSelf.angleLayer, below: strongView.layer) + strongSelf.angleLayer.transform = CATransform3DMakeRotation(snappedToAngle, 0.0, 0.0, 1.0) + if strongSelf.angleLayer.opacity < 1.0 { + strongSelf.hapticFeedback.impact(.light) + } + transition.updateAlpha(layer: strongSelf.angleLayer, alpha: 1.0) + } else { + transition.updateAlpha(layer: strongSelf.angleLayer, alpha: 0.0) + } + } + view.onPositionUpdated = { [weak self] position in + guard let strongSelf = self else { + return + } + strongSelf.angleLayer.position = position + } view.update() self.addSubview(view) @@ -598,6 +633,8 @@ public class DrawingEntityView: UIView { var onSnapToXAxis: (Bool) -> Void = { _ in } var onSnapToYAxis: (Bool) -> Void = { _ in } + var onSnapToAngle: (CGFloat?) -> Void = { _ in } + var onPositionUpdated: (CGPoint) -> Void = { _ in } init(context: AccountContext, entity: DrawingEntity) { self.context = context diff --git a/submodules/DrawingUI/Sources/DrawingGesture.swift b/submodules/DrawingUI/Sources/DrawingGesture.swift index 8ad353cc98..15cd4d354b 100644 --- a/submodules/DrawingUI/Sources/DrawingGesture.swift +++ b/submodules/DrawingUI/Sources/DrawingGesture.swift @@ -214,42 +214,17 @@ class DrawingGestureRecognizer: UIGestureRecognizer, UIGestureRecognizerDelegate var allTouches: [Touch] = [] - for touch in touches { - var coalesced = event?.coalescedTouches(for: touch) ?? [touch] - if "".isEmpty || coalesced.isEmpty { - coalesced = [touch] - } - - for coalescedTouch in coalesced { - allTouches.append( - Touch( - coalescedTouch: coalescedTouch, - touch: touch, - in: view, - isUpdate: isUpdate, - isPrediction: false, - transform: self.transform - ) - ) - } - - if self.usePredictedTouches { - let predicted = event?.predictedTouches(for: touch) ?? [] - for predictedTouch in predicted { - allTouches.append( - Touch( - coalescedTouch: predictedTouch, - touch: touch, - in: view, - isUpdate: isUpdate, - isPrediction: true, - transform: self.transform - ) - ) - } - } + if let touch = touches.first { + allTouches.append(Touch( + coalescedTouch: touch, + touch: touch, + in: view, + isUpdate: isUpdate, + isPrediction: false, + transform: self.transform + )) } - + self.onTouches(allTouches) } } @@ -300,15 +275,7 @@ class DrawingGesturePipeline { } } - var mode: Mode = .location { - didSet { - if [.location, .polyline].contains(self.mode) { - self.gestureRecognizer?.usePredictedTouches = false - } else { - self.gestureRecognizer?.usePredictedTouches = true - } - } - } + var mode: Mode = .location init(view: DrawingView) { let gestureRecognizer = DrawingGestureRecognizer(target: self, action: #selector(self.handleGesture(_:))) diff --git a/submodules/DrawingUI/Sources/DrawingScreen.swift b/submodules/DrawingUI/Sources/DrawingScreen.swift index dbded20f0d..e536939a50 100644 --- a/submodules/DrawingUI/Sources/DrawingScreen.swift +++ b/submodules/DrawingUI/Sources/DrawingScreen.swift @@ -393,7 +393,9 @@ private final class BlurredGradientComponent: Component { public func update(component: BlurredGradientComponent, availableSize: CGSize, transition: Transition) -> CGSize { self.component = component - self.updateColor(color: UIColor(rgb: 0x000000, alpha: 0.25), transition: transition.containedViewLayoutTransition) + self.isUserInteractionEnabled = false + + self.updateColor(color: UIColor(rgb: 0x000000, alpha: component.position == .top ? 0.15 : 0.25), transition: transition.containedViewLayoutTransition) if self.mask == nil { self.mask = self.gradientMask @@ -989,7 +991,7 @@ private final class DrawingScreenComponent: CombinedComponent { position: .top, tag: topGradientTag ), - availableSize: CGSize(width: context.availableSize.width, height: 111.0), + availableSize: CGSize(width: context.availableSize.width, height: topInset + 10.0), transition: .immediate ) context.add(topGradient @@ -2317,7 +2319,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { entityView.update() if let (layout, orientation) = strongSelf.validLayout { - strongSelf.containerLayoutUpdated(layout: layout, orientation: orientation, forceUpdate: true, transition: .immediate) + strongSelf.containerLayoutUpdated(layout: layout, orientation: orientation, forceUpdate: true, transition: .easeInOut(duration: 0.2)) } }))) } @@ -2464,7 +2466,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController { } let isFirstTime = self.validLayout == nil self.validLayout = (layout, orientation) - + let environment = ViewControllerComponentContainer.Environment( statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: 0.0, diff --git a/submodules/DrawingUI/Sources/DrawingSimpleShapeEntity.swift b/submodules/DrawingUI/Sources/DrawingSimpleShapeEntity.swift index 83a0d4f52b..7abc0bd201 100644 --- a/submodules/DrawingUI/Sources/DrawingSimpleShapeEntity.swift +++ b/submodules/DrawingUI/Sources/DrawingSimpleShapeEntity.swift @@ -310,6 +310,12 @@ final class DrawingSimpleShapeEntititySelectionView: DrawingEntitySelectionView, entityView.onSnapToYAxis(snapped) } } + + self.snapTool.onSnapRotationUpdated = { [weak self] snappedAngle in + if let strongSelf = self, let entityView = strongSelf.entityView { + entityView.onSnapToAngle(snappedAngle) + } + } } required init?(coder: NSCoder) { @@ -460,6 +466,8 @@ final class DrawingSimpleShapeEntititySelectionView: DrawingEntitySelectionView, default: break } + + entityView.onPositionUpdated(entity.position) } override func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) { @@ -484,16 +492,29 @@ final class DrawingSimpleShapeEntititySelectionView: DrawingEntitySelectionView, return } + let velocity = gestureRecognizer.velocity + var updatedRotation = entity.rotation + var rotation: CGFloat = 0.0 + switch gestureRecognizer.state { - case .began, .changed: - let rotation = gestureRecognizer.rotation - entity.rotation += rotation - entityView.update() + case .began: + self.snapTool.maybeSkipFromStart(entityView: entityView, rotation: entity.rotation) + case .changed: + rotation = gestureRecognizer.rotation + updatedRotation += rotation gestureRecognizer.rotation = 0.0 + case .ended, .cancelled: + self.snapTool.rotationReset() default: break } + + updatedRotation = self.snapTool.update(entityView: entityView, velocity: velocity, delta: rotation, updatedRotation: updatedRotation) + entity.rotation = updatedRotation + entityView.update() + + entityView.onPositionUpdated(entity.position) } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { diff --git a/submodules/DrawingUI/Sources/DrawingStickerEntity.swift b/submodules/DrawingUI/Sources/DrawingStickerEntity.swift index 4d5935a2bf..71ed7a3c96 100644 --- a/submodules/DrawingUI/Sources/DrawingStickerEntity.swift +++ b/submodules/DrawingUI/Sources/DrawingStickerEntity.swift @@ -373,6 +373,12 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG entityView.onSnapToYAxis(snapped) } } + + self.snapTool.onSnapRotationUpdated = { [weak self] snappedAngle in + if let strongSelf = self, let entityView = strongSelf.entityView { + entityView.onSnapToAngle(snappedAngle) + } + } } required init?(coder: NSCoder) { @@ -402,7 +408,6 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG } let location = gestureRecognizer.location(in: self) - switch gestureRecognizer.state { case .began: self.snapTool.maybeSkipFromStart(entityView: entityView, position: entity.position) @@ -411,6 +416,7 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG for layer in sublayers { if layer.frame.contains(location) { self.currentHandle = layer + self.snapTool.maybeSkipFromStart(entityView: entityView, rotation: entity.rotation) return } } @@ -432,13 +438,15 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG let scaleDelta = (self.bounds.size.width + deltaX * 2.0) / self.bounds.size.width updatedScale *= scaleDelta - let deltaAngle: CGFloat + let newAngle: CGFloat if self.currentHandle === self.leftHandle { - deltaAngle = atan2(self.center.y - parentLocation.y, self.center.x - parentLocation.x) + newAngle = atan2(self.center.y - parentLocation.y, self.center.x - parentLocation.x) } else { - deltaAngle = atan2(parentLocation.y - self.center.y, parentLocation.x - self.center.x) + newAngle = atan2(parentLocation.y - self.center.y, parentLocation.x - self.center.x) } - updatedRotation = deltaAngle + + // let delta = newAngle - updatedRotation + updatedRotation = newAngle// self.snapTool.update(entityView: entityView, velocity: 0.0, delta: delta, updatedRotation: newAngle) } else if self.currentHandle === self.layer { updatedPosition.x += delta.x updatedPosition.y += delta.y @@ -452,13 +460,16 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG entityView.update() gestureRecognizer.setTranslation(.zero, in: entityView) - case .ended: - self.snapTool.reset() - case .cancelled: + case .ended, .cancelled: self.snapTool.reset() + if self.currentHandle != nil { + self.snapTool.rotationReset() + } default: break } + + entityView.onPositionUpdated(entity.position) } override func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) { @@ -483,16 +494,29 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG return } + let velocity = gestureRecognizer.velocity + var updatedRotation = entity.rotation + var rotation: CGFloat = 0.0 + switch gestureRecognizer.state { - case .began, .changed: - let rotation = gestureRecognizer.rotation - entity.rotation += rotation - entityView.update() + case .began: + self.snapTool.maybeSkipFromStart(entityView: entityView, rotation: entity.rotation) + case .changed: + rotation = gestureRecognizer.rotation + updatedRotation += rotation gestureRecognizer.rotation = 0.0 + case .ended, .cancelled: + self.snapTool.rotationReset() default: break } + + updatedRotation = self.snapTool.update(entityView: entityView, velocity: velocity, delta: rotation, updatedRotation: updatedRotation) + entity.rotation = updatedRotation + entityView.update() + + entityView.onPositionUpdated(entity.position) } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { @@ -534,23 +558,31 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView, UIG } } +private let snapTimeout = 1.0 + class DrawingEntitySnapTool { private var xState: (skipped: CGFloat, waitForLeave: Bool)? private var yState: (skipped: CGFloat, waitForLeave: Bool)? - - private var rotationState: (skipped: CGFloat, waitForLeave: Bool)? + private var rotationState: (angle: CGFloat, skipped: CGFloat, waitForLeave: Bool)? var onSnapXUpdated: (Bool) -> Void = { _ in } var onSnapYUpdated: (Bool) -> Void = { _ in } var onSnapRotationUpdated: (CGFloat?) -> Void = { _ in } + var previousXSnapTimestamp: Double? + var previousYSnapTimestamp: Double? + var previousRotationSnapTimestamp: Double? + func reset() { self.xState = nil self.yState = nil - self.rotationState = nil - + self.onSnapXUpdated(false) self.onSnapYUpdated(false) + } + + func rotationReset() { + self.rotationState = nil self.onSnapRotationUpdated(nil) } @@ -575,6 +607,8 @@ class DrawingEntitySnapTool { func update(entityView: DrawingEntityView, velocity: CGPoint, delta: CGPoint, updatedPosition: CGPoint) -> CGPoint { var updatedPosition = updatedPosition + let currentTimestamp = CACurrentMediaTime() + let snapXDelta: CGFloat = (entityView.superview?.frame.width ?? 0.0) * 0.02 let snapXVelocity: CGFloat = snapXDelta * 12.0 let snapXSkipTranslation: CGFloat = snapXDelta * 2.0 @@ -597,9 +631,14 @@ class DrawingEntitySnapTool { } } else { if updatedPosition.x > snapLocation.x - snapXDelta && updatedPosition.x < snapLocation.x + snapXDelta { - self.xState = (0.0, false) - updatedPosition.x = snapLocation.x - self.onSnapXUpdated(true) + if let previousXSnapTimestamp, currentTimestamp - previousXSnapTimestamp < snapTimeout { + + } else { + self.previousXSnapTimestamp = currentTimestamp + self.xState = (0.0, false) + updatedPosition.x = snapLocation.x + self.onSnapXUpdated(true) + } } } } @@ -630,9 +669,14 @@ class DrawingEntitySnapTool { } } else { if updatedPosition.y > snapLocation.y - snapYDelta && updatedPosition.y < snapLocation.y + snapYDelta { - self.yState = (0.0, false) - updatedPosition.y = snapLocation.y - self.onSnapYUpdated(true) + if let previousYSnapTimestamp, currentTimestamp - previousYSnapTimestamp < snapTimeout { + + } else { + self.previousYSnapTimestamp = currentTimestamp + self.yState = (0.0, false) + updatedPosition.y = snapLocation.y + self.onSnapYUpdated(true) + } } } } @@ -644,16 +688,72 @@ class DrawingEntitySnapTool { return updatedPosition } - private let snapRotations: [CGFloat] = [0.0, .pi / 4.0, .pi / 2.0, .pi * 1.5,] + private let snapRotations: [CGFloat] = [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0] func maybeSkipFromStart(entityView: DrawingEntityView, rotation: CGFloat) { self.rotationState = nil - let snapDelta: CGFloat = 0.087 + let snapDelta: CGFloat = 0.25 for snapRotation in self.snapRotations { + let snapRotation = snapRotation * .pi if rotation > snapRotation - snapDelta && rotation < snapRotation + snapDelta { - self.rotationState = (0.0, true) + self.rotationState = (snapRotation, 0.0, true) break } } } + + func update(entityView: DrawingEntityView, velocity: CGFloat, delta: CGFloat, updatedRotation: CGFloat) -> CGFloat { + var updatedRotation = updatedRotation + if updatedRotation < 0.0 { + updatedRotation = 2.0 * .pi + updatedRotation + } else if updatedRotation > 2.0 * .pi { + while updatedRotation > 2.0 * .pi { + updatedRotation -= 2.0 * .pi + } + } + + let currentTimestamp = CACurrentMediaTime() + + let snapDelta: CGFloat = 0.1 + let snapVelocity: CGFloat = snapDelta * 5.0 + let snapSkipRotation: CGFloat = snapDelta * 2.0 + + if abs(velocity) < snapVelocity || self.rotationState?.waitForLeave == true { + if let (snapRotation, skipped, waitForLeave) = self.rotationState { + if waitForLeave { + if updatedRotation > snapRotation - snapDelta * 2.0 && updatedRotation < snapRotation + snapDelta { + + } else { + self.rotationState = nil + } + } else if abs(skipped) < snapSkipRotation { + self.rotationState = (snapRotation, skipped + delta, false) + updatedRotation = snapRotation + } else { + self.rotationState = (snapRotation, snapSkipRotation, true) + self.onSnapRotationUpdated(nil) + } + } else { + for snapRotation in self.snapRotations { + let snapRotation = snapRotation * .pi + if updatedRotation > snapRotation - snapDelta && updatedRotation < snapRotation + snapDelta { + if let previousRotationSnapTimestamp, currentTimestamp - previousRotationSnapTimestamp < snapTimeout { + + } else { + self.previousRotationSnapTimestamp = currentTimestamp + self.rotationState = (snapRotation, 0.0, false) + updatedRotation = snapRotation + self.onSnapRotationUpdated(snapRotation) + } + break + } + } + } + } else { + self.rotationState = nil + self.onSnapRotationUpdated(nil) + } + + return updatedRotation + } } diff --git a/submodules/DrawingUI/Sources/DrawingTextEntity.swift b/submodules/DrawingUI/Sources/DrawingTextEntity.swift index 0e6a8799e5..c803f803c4 100644 --- a/submodules/DrawingUI/Sources/DrawingTextEntity.swift +++ b/submodules/DrawingUI/Sources/DrawingTextEntity.swift @@ -258,7 +258,7 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { self.textView.minimumZoomScale = 1.0 self.textView.maximumZoomScale = 1.0 self.textView.keyboardAppearance = .dark - self.textView.autocorrectionType = .no + self.textView.autocorrectionType = .default self.textView.spellCheckingType = .no super.init(context: context, entity: entity) @@ -482,7 +482,7 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { self.textEntity.text = updatedText self.sizeToFit() - self.update() + self.update(afterAppendingEmoji: true) } func insertText(_ text: NSAttributedString) { @@ -493,11 +493,15 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { updatedText.removeAttribute(.font, range: range) updatedText.removeAttribute(.paragraphStyle, range: range) updatedText.removeAttribute(.foregroundColor, range: range) + + let previousSelectedRange = self.textView.selectedRange updatedText.replaceCharacters(in: self.textView.selectedRange, with: text) self.textEntity.text = updatedText - self.update() + self.update(animated: false, afterAppendingEmoji: true) + + self.textView.selectedRange = NSMakeRange(previousSelectedRange.location + previousSelectedRange.length + text.length, 0) } override func sizeThatFits(_ size: CGSize) -> CGSize { @@ -531,7 +535,7 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { return fontSize } - private func updateText() { + private func updateText(keepSelectedRange: Bool = false) { guard let text = self.textEntity.text.mutableCopy() as? NSMutableAttributedString else { return } @@ -581,10 +585,18 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { paragraphStyle.alignment = self.textEntity.alignment.alignment text.addAttribute(.paragraphStyle, value: paragraphStyle, range: range) + let previousRange = self.textView.selectedRange self.textView.attributedText = text + if keepSelectedRange { + self.textView.selectedRange = previousRange + } } override func update(animated: Bool = false) { + self.update(animated: animated, afterAppendingEmoji: false) + } + + func update(animated: Bool = false, afterAppendingEmoji: Bool = false) { if !self.isEditing { self.center = self.textEntity.position self.transform = CGAffineTransformScale(CGAffineTransformMakeRotation(self.textEntity.rotation), self.textEntity.scale, self.textEntity.scale) @@ -622,11 +634,11 @@ final class DrawingTextEntityView: DrawingEntityView, UITextViewDelegate { self.textView.layer.shadowRadius = 0.0 } - self.updateText() + self.updateText(keepSelectedRange: afterAppendingEmoji) self.sizeToFit() - Queue.mainQueue().after(0.001) { + Queue.mainQueue().after(afterAppendingEmoji ? 0.01 : 0.001) { self.updateEntities() } @@ -749,6 +761,12 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest entityView.onSnapToYAxis(snapped) } } + + self.snapTool.onSnapRotationUpdated = { [weak self] snappedAngle in + if let strongSelf = self, let entityView = strongSelf.entityView { + entityView.onSnapToAngle(snappedAngle) + } + } } required init?(coder: NSCoder) { @@ -789,6 +807,7 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest for layer in sublayers { if layer.frame.contains(location) { self.currentHandle = layer + self.snapTool.maybeSkipFromStart(entityView: entityView, rotation: entity.rotation) return } } @@ -811,13 +830,15 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest let scaleDelta = (self.bounds.size.width + deltaX * 2.0) / self.bounds.size.width updatedScale = max(0.01, updatedScale * scaleDelta) - let deltaAngle: CGFloat + let newAngle: CGFloat if self.currentHandle === self.leftHandle { - deltaAngle = atan2(self.center.y - parentLocation.y, self.center.x - parentLocation.x) + newAngle = atan2(self.center.y - parentLocation.y, self.center.x - parentLocation.x) } else { - deltaAngle = atan2(parentLocation.y - self.center.y, parentLocation.x - self.center.x) + newAngle = atan2(parentLocation.y - self.center.y, parentLocation.x - self.center.x) } - updatedRotation = deltaAngle + + //let delta = newAngle - updatedRotation + updatedRotation = newAngle //" self.snapTool.update(entityView: entityView, velocity: 0.0, delta: delta, updatedRotation: newAngle) } else if self.currentHandle === self.layer { updatedPosition.x += delta.x updatedPosition.y += delta.y @@ -831,13 +852,16 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest entityView.update() gestureRecognizer.setTranslation(.zero, in: entityView) - case .ended: - self.snapTool.reset() - case .cancelled: + case .ended, .cancelled: self.snapTool.reset() + if self.currentHandle != nil { + self.snapTool.rotationReset() + } default: break } + + entityView.onPositionUpdated(entity.position) } override func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) { @@ -862,16 +886,29 @@ final class DrawingTextEntititySelectionView: DrawingEntitySelectionView, UIGest return } + let velocity = gestureRecognizer.velocity + var updatedRotation = entity.rotation + var rotation: CGFloat = 0.0 + switch gestureRecognizer.state { - case .began, .changed: - let rotation = gestureRecognizer.rotation - entity.rotation += rotation - entityView.update() + case .began: + self.snapTool.maybeSkipFromStart(entityView: entityView, rotation: entity.rotation) + case .changed: + rotation = gestureRecognizer.rotation + updatedRotation += rotation gestureRecognizer.rotation = 0.0 + case .ended, .cancelled: + self.snapTool.rotationReset() default: break } + + updatedRotation = self.snapTool.update(entityView: entityView, velocity: velocity, delta: rotation, updatedRotation: updatedRotation) + entity.rotation = updatedRotation + entityView.update() + + entityView.onPositionUpdated(entity.position) } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { diff --git a/submodules/DrawingUI/Sources/DrawingTools.swift b/submodules/DrawingUI/Sources/DrawingTools.swift index 7121ca9704..8a64ce99a2 100644 --- a/submodules/DrawingUI/Sources/DrawingTools.swift +++ b/submodules/DrawingUI/Sources/DrawingTools.swift @@ -19,6 +19,10 @@ final class MarkerTool: DrawingElement, Codable { var isValid: Bool { return !self.points.isEmpty } + + var bounds: CGRect { + return CGRect(origin: .zero, size: self.drawingSize) + } required init(drawingSize: CGSize, color: DrawingColor, lineWidth: CGFloat) { self.uuid = UUID() @@ -170,6 +174,10 @@ final class NeonTool: DrawingElement, Codable { var isValid: Bool { return self.renderPath != nil } + + var bounds: CGRect { + return CGRect(origin: .zero, size: self.drawingSize) + } required init(drawingSize: CGSize, color: DrawingColor, lineWidth: CGFloat) { self.uuid = UUID() @@ -292,6 +300,10 @@ final class FillTool: DrawingElement, Codable { return true } + var bounds: CGRect { + return CGRect(origin: .zero, size: self.drawingSize) + } + required init(drawingSize: CGSize, color: DrawingColor, blur: Bool, blurredImage: UIImage?) { self.uuid = UUID() self.drawingSize = drawingSize diff --git a/submodules/DrawingUI/Sources/DrawingView.swift b/submodules/DrawingUI/Sources/DrawingView.swift index 43052de0c9..e2411dbaa9 100644 --- a/submodules/DrawingUI/Sources/DrawingView.swift +++ b/submodules/DrawingUI/Sources/DrawingView.swift @@ -19,6 +19,7 @@ protocol DrawingElement: AnyObject { var uuid: UUID { get } var translation: CGPoint { get set } var isValid: Bool { get } + var bounds: CGRect { get } func setupRenderView(screenSize: CGSize) -> DrawingRenderView? func setupRenderLayer() -> DrawingRenderLayer? @@ -27,8 +28,9 @@ protocol DrawingElement: AnyObject { func draw(in: CGContext, size: CGSize) } -enum DrawingOperation { - case element(DrawingElement) +private enum DrawingOperation { + case clearAll(CGRect) + case slice(DrawingSlice) case addEntity(UUID) case removeEntity(DrawingEntity) } @@ -69,7 +71,6 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw var shouldBegin: (CGPoint) -> Bool = { _ in return true } var getFullImage: () -> UIImage? = { return nil } - private var elements: [DrawingElement] = [] private var undoStack: [DrawingOperation] = [] private var redoStack: [DrawingOperation] = [] fileprivate var uncommitedElement: DrawingElement? @@ -126,11 +127,18 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw private let hapticFeedback = HapticFeedback() + public var screenSize: CGSize + init(size: CGSize) { self.imageSize = size + self.screenSize = size let format = UIGraphicsImageRendererFormat() format.scale = 1.0 + if #available(iOS 12.0, *) { + format.preferredRange = .standard + } + format.opaque = false self.renderer = UIGraphicsImageRenderer(size: size, format: format) self.currentDrawingViewContainer = UIImageView() @@ -170,7 +178,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.isExclusiveTouch = true self.addSubview(self.currentDrawingViewContainer) - //self.addSubview(self.metalView) + self.addSubview(self.metalView) self.layer.addSublayer(self.brushSizePreviewLayer) @@ -180,7 +188,10 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw if !strongSelf.shouldBegin(point) { return false } - if strongSelf.elements.isEmpty && !strongSelf.hasOpaqueData && strongSelf.tool == .eraser { + if strongSelf.undoStack.isEmpty && !strongSelf.hasOpaqueData && strongSelf.tool == .eraser { + return false + } + if strongSelf.tool == .blur, strongSelf.preparedBlurredImage == nil { return false } if let uncommitedElement = strongSelf.uncommitedElement as? PenTool, uncommitedElement.isFinishingArrow { @@ -202,7 +213,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw strongSelf.drawingGestureStartTimestamp = CACurrentMediaTime() if strongSelf.uncommitedElement != nil { - strongSelf.finishDrawing() + strongSelf.finishDrawing(rect: CGRect(origin: .zero, size: strongSelf.imageSize), synchronous: true) } guard let newElement = strongSelf.prepareNewElement() else { @@ -213,7 +224,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw strongSelf.metalView.isHidden = false } - if let renderView = newElement.setupRenderView(screenSize: CGSize(width: 414.0, height: 414.0)) { + if let renderView = newElement.setupRenderView(screenSize: strongSelf.screenSize) { if let currentDrawingView = strongSelf.currentDrawingRenderView { strongSelf.currentDrawingRenderView = nil currentDrawingView.removeFromSuperview() @@ -334,8 +345,12 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw strongSelf.strokeRecognitionTimer?.invalidate() strongSelf.strokeRecognitionTimer = nil strongSelf.uncommitedElement?.updatePath(path, state: state) + + let bounds = strongSelf.uncommitedElement?.bounds Queue.mainQueue().after(0.05) { - strongSelf.finishDrawing() + if let bounds = bounds { + strongSelf.finishDrawing(rect: bounds, synchronous: true) + } } strongSelf.updateInternalState() case .cancelled: @@ -368,16 +383,25 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw public func setup(withDrawing drawingData: Data?) { if let drawingData = drawingData, let image = UIImage(data: drawingData) { self.hasOpaqueData = true - self.drawingImage = image + + if let context = DrawingContext(size: image.size, scale: 1.0, opaque: false) { + context.withFlippedContext { context in + if let cgImage = image.cgImage { + context.draw(cgImage, in: CGRect(origin: .zero, size: image.size)) + } + } + self.drawingImage = context.generateImage() ?? image + } else { + self.drawingImage = image + } self.layer.contents = image.cgImage - self.updateInternalState() } } var hasOpaqueData = false var drawingData: Data? { - guard !self.elements.isEmpty || self.hasOpaqueData else { + guard !self.undoStack.isEmpty || self.hasOpaqueData else { return nil } return self.drawingImage?.pngData() @@ -411,6 +435,8 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw blurredImage = self.preparedBlurredImage } + self.hapticFeedback.prepareImpact(.medium) + let fillCircleLayer = SimpleShapeLayer() self.longPressTimer = SwiftSignalKit.Timer(timeout: 0.25, repeat: false, completion: { [weak self, weak fillCircleLayer] in if let strongSelf = self { @@ -419,7 +445,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw let action = { let newElement = FillTool(drawingSize: strongSelf.imageSize, color: toolColor, blur: blurredImage != nil, blurredImage: blurredImage) strongSelf.uncommitedElement = newElement - strongSelf.finishDrawing(synchronous: true) + strongSelf.finishDrawing(rect: CGRect(origin: .zero, size: strongSelf.imageSize), synchronous: true) } if [.eraser, .blur].contains(strongSelf.tool) { UIView.transition(with: strongSelf, duration: 0.2, options: .transitionCrossDissolve) { @@ -473,30 +499,21 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } private let queue = Queue() - private var skipDrawing = Set() - private func commit(reset: Bool = false, interactive: Bool = false, synchronous: Bool = true, completion: @escaping () -> Void = {}) { + private func commit(interactive: Bool = false, synchronous: Bool = true, completion: @escaping () -> Void = {}) { let currentImage = self.drawingImage let uncommitedElement = self.uncommitedElement let imageSize = self.imageSize - let skipDrawing = self.skipDrawing let action = { let updatedImage = self.renderer.image { context in - if !reset { - context.cgContext.clear(CGRect(origin: .zero, size: imageSize)) - if let image = currentImage { - image.draw(at: .zero) - } - if let uncommitedElement = uncommitedElement { - uncommitedElement.draw(in: context.cgContext, size: imageSize) - } - } else { - context.cgContext.clear(CGRect(origin: .zero, size: imageSize)) - for element in self.elements { - if !skipDrawing.contains(element.uuid) { - element.draw(in: context.cgContext, size: imageSize) - } - } + context.cgContext.setBlendMode(.copy) + context.cgContext.clear(CGRect(origin: .zero, size: imageSize)) + if let image = currentImage { + image.draw(at: .zero) + } + if let uncommitedElement = uncommitedElement { + context.cgContext.setBlendMode(.normal) + uncommitedElement.draw(in: context.cgContext, size: imageSize) } } Queue.mainQueue().async { @@ -547,18 +564,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } } } - - private func updateSelectionContent() { - let selectionImage = self.renderer.image { context in - for element in self.elements { - if self.skipDrawing.contains(element.uuid) { - element.draw(in: context.cgContext, size: self.imageSize) - } - } - } - self.pannedSelectionView.layer.contents = selectionImage.cgImage - } - + fileprivate func cancelDrawing() { self.uncommitedElement = nil @@ -591,20 +597,29 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.currentDrawingLayer = nil } } + + private func slice(for rect: CGRect) -> DrawingSlice? { + if let subImage = self.drawingImage?.cgImage?.cropping(to: rect) { + return DrawingSlice(image: subImage, rect: rect) + } + return nil + } - fileprivate func finishDrawing(synchronous: Bool = false) { + fileprivate func finishDrawing(rect: CGRect, synchronous: Bool = false) { let complete: (Bool) -> Void = { synchronous in if let uncommitedElement = self.uncommitedElement, !uncommitedElement.isValid { self.uncommitedElement = nil } + if !self.undoStack.isEmpty || self.hasOpaqueData, let slice = self.slice(for: rect) { + self.undoStack.append(.slice(slice)) + } else { + self.undoStack.append(.clearAll(rect)) + } + self.commit(interactive: true, synchronous: synchronous) self.redoStack.removeAll() - if let uncommitedElement = self.uncommitedElement { - self.elements.append(uncommitedElement) - self.undoStack.append(.element(uncommitedElement)) - self.uncommitedElement = nil - } + self.uncommitedElement = nil self.updateInternalState() } @@ -622,7 +637,6 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.entitiesView?.removeAll() self.uncommitedElement = nil - self.elements.removeAll() self.undoStack.removeAll() self.redoStack.removeAll() self.hasOpaqueData = false @@ -632,7 +646,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.addSubview(snapshotView) self.drawingImage = nil - self.commit(reset: true) + self.layer.contents = nil Queue.mainQueue().justDispatch { snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in @@ -645,6 +659,25 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.updateBlurredImage() } + private func applySlice(_ slice: DrawingSlice) { + let updatedImage = self.renderer.image { context in + context.cgContext.clear(CGRect(origin: .zero, size: imageSize)) + context.cgContext.setBlendMode(.copy) + if let image = self.drawingImage { + image.draw(at: .zero) + } + if let image = slice.image { + context.cgContext.translateBy(x: imageSize.width / 2.0, y: imageSize.height / 2.0) + context.cgContext.scaleBy(x: 1.0, y: -1.0) + context.cgContext.translateBy(x: -imageSize.width / 2.0, y: -imageSize.height / 2.0) + context.cgContext.translateBy(x: slice.rect.minX, y: imageSize.height - slice.rect.maxY) + context.cgContext.draw(image, in: CGRect(origin: .zero, size: slice.rect.size)) + } + } + self.drawingImage = updatedImage + self.layer.contents = updatedImage.cgImage + } + var canUndo: Bool { return !self.undoStack.isEmpty } @@ -654,15 +687,22 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw return } switch lastOperation { - case let .element(element): - self.uncommitedElement = nil - self.redoStack.append(.element(element)) - self.elements.removeAll(where: { $0.uuid == element.uuid }) - - UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) { - self.commit(reset: true) + case let .clearAll(rect): + if let slice = self.slice(for: rect) { + self.redoStack.append(.slice(slice)) + } + UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) { + self.drawingImage = nil + self.layer.contents = nil + } + self.updateBlurredImage() + case let .slice(slice): + if let slice = self.slice(for: slice.rect) { + self.redoStack.append(.slice(slice)) + } + UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) { + self.applySlice(slice) } - self.updateBlurredImage() case let .addEntity(uuid): if let entityView = self.entitiesView?.getView(for: uuid) { @@ -690,17 +730,17 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } switch lastOperation { - case let .element(element): - self.uncommitedElement = nil - self.elements.append(element) - self.undoStack.append(.element(element)) - self.uncommitedElement = element - - UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) { - self.commit(reset: false) + case .clearAll: + break + case let .slice(slice): + if !self.undoStack.isEmpty || self.hasOpaqueData, let slice = self.slice(for: slice.rect) { + self.undoStack.append(.slice(slice)) + } else { + self.undoStack.append(.clearAll(slice.rect)) + } + UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) { + self.applySlice(slice) } - self.uncommitedElement = nil - self.updateBlurredImage() case let .addEntity(uuid): if let entityView = self.entitiesView?.getView(for: uuid) { @@ -807,7 +847,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw self.stateUpdated(NavigationState( canUndo: !self.undoStack.isEmpty, canRedo: !self.redoStack.isEmpty, - canClear: !self.elements.isEmpty || self.hasOpaqueData || !(self.entitiesView?.entities.isEmpty ?? true), + canClear: !self.undoStack.isEmpty || self.hasOpaqueData || !(self.entitiesView?.entities.isEmpty ?? true), canZoomOut: self.zoomScale > 1.0 + .ulpOfOne, isDrawing: self.isDrawing )) @@ -885,16 +925,6 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw return element } - func removeElement(_ element: DrawingElement) { - self.elements.removeAll(where: { $0 === element }) - self.commit(reset: true) - } - - func removeElements(_ elements: [UUID]) { - self.elements.removeAll(where: { elements.contains($0.uuid) }) - self.commit(reset: true) - } - func setBrushSizePreview(_ size: CGFloat?) { let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut)) if let size = size { @@ -929,7 +959,7 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } public var isEmpty: Bool { - return self.elements.isEmpty && !self.hasOpaqueData + return self.undoStack.isEmpty && !self.hasOpaqueData } public var scale: CGFloat { @@ -941,18 +971,40 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw } } -private class UndoSlice { +private class DrawingSlice { + private static let queue = Queue() + + var _image: CGImage? + let uuid: UUID - -// let data: Data -// let bounds: CGRect - + var image: CGImage? { + if let image = self._image { + return image + } else if let data = try? Data(contentsOf: URL(fileURLWithPath: self.path)) { + return UIImage(data: data)?.cgImage + } else { + return nil + } + } + let rect: CGRect let path: String - init(context: DrawingContext, bounds: CGRect) { + init(image: CGImage, rect: CGRect) { self.uuid = UUID() + self._image = image + self.rect = rect self.path = NSTemporaryDirectory() + "/drawing_\(uuid.hashValue).slice" + + DrawingSlice.queue.async { + let image = UIImage(cgImage: image) + if let data = image.pngData() as? NSData { + try? data.write(toFile: self.path) + Queue.mainQueue().async { + self._image = nil + } + } + } } deinit { diff --git a/submodules/DrawingUI/Sources/PenTool.swift b/submodules/DrawingUI/Sources/PenTool.swift index e970051755..998ca5c89d 100644 --- a/submodules/DrawingUI/Sources/PenTool.swift +++ b/submodules/DrawingUI/Sources/PenTool.swift @@ -13,7 +13,7 @@ final class PenTool: DrawingElement { private var start = 0 private var segmentsCount = 0 - private var displayScale: CGFloat = 1.0 + private var drawScale = CGSize(width: 1.0, height: 1.0) func setup(size: CGSize, screenSize: CGSize, isEraser: Bool) { self.isEraser = isEraser @@ -22,15 +22,20 @@ final class PenTool: DrawingElement { self.isOpaque = false self.contentMode = .redraw - let viewSize = size.aspectFilled(screenSize) + //let scale = CGSize(width: screenSize.width / max(1.0, size.width), height: screenSize.height / max(1.0, size.height)) - self.displayScale = size.width / viewSize.width + let scale = CGSize(width: 0.33, height: 0.33) + let viewSize = CGSize(width: size.width * scale.width, height: size.height * scale.height) + + self.drawScale = CGSize(width: size.width / viewSize.width, height: size.height / viewSize.height) self.bounds = CGRect(origin: .zero, size: viewSize) - self.transform = CGAffineTransform(scaleX: self.displayScale, y: self.displayScale) + self.transform = CGAffineTransform(scaleX: self.drawScale.width, y: self.drawScale.height) self.frame = CGRect(origin: .zero, size: size) - - let activeView = ActiveView(frame: CGRect(origin: .zero, size: viewSize)) + + self.drawScale.height = self.drawScale.width + + let activeView = ActiveView(frame: CGRect(origin: .zero, size: self.bounds.size)) activeView.backgroundColor = .clear activeView.contentMode = .redraw activeView.isOpaque = false @@ -40,18 +45,20 @@ final class PenTool: DrawingElement { } func animateArrowPaths(start: CGPoint, direction: CGFloat, length: CGFloat, lineWidth: CGFloat, completion: @escaping () -> Void) { - let arrowStart = CGPoint(x: start.x / self.displayScale, y: start.y / self.displayScale) + let scale = min(self.drawScale.width, self.drawScale.height) + + let arrowStart = CGPoint(x: start.x / scale, y: start.y / scale) let arrowLeftPath = UIBezierPath() arrowLeftPath.move(to: arrowStart) - arrowLeftPath.addLine(to: arrowStart.pointAt(distance: length / self.displayScale, angle: direction - 0.45)) + arrowLeftPath.addLine(to: arrowStart.pointAt(distance: length / scale, angle: direction - 0.45)) let arrowRightPath = UIBezierPath() arrowRightPath.move(to: arrowStart) - arrowRightPath.addLine(to: arrowStart.pointAt(distance: length / self.displayScale, angle: direction + 0.45)) + arrowRightPath.addLine(to: arrowStart.pointAt(distance: length / scale, angle: direction + 0.45)) let leftArrowShape = CAShapeLayer() leftArrowShape.path = arrowLeftPath.cgPath - leftArrowShape.lineWidth = lineWidth / self.displayScale + leftArrowShape.lineWidth = lineWidth / scale leftArrowShape.strokeColor = self.element?.color.toCGColor() leftArrowShape.lineCap = .round leftArrowShape.frame = self.bounds @@ -59,7 +66,7 @@ final class PenTool: DrawingElement { let rightArrowShape = CAShapeLayer() rightArrowShape.path = arrowRightPath.cgPath - rightArrowShape.lineWidth = lineWidth / self.displayScale + rightArrowShape.lineWidth = lineWidth / scale rightArrowShape.strokeColor = self.element?.color.toCGColor() rightArrowShape.lineCap = .round rightArrowShape.frame = self.bounds @@ -74,6 +81,7 @@ final class PenTool: DrawingElement { }) } + var displaySize: CGSize? fileprivate func draw(element: PenTool, rect: CGRect) { self.element = element @@ -90,7 +98,8 @@ final class PenTool: DrawingElement { if activeCount > limit { rect = nil let newStart = self.start + limit - let image = generateImage(self.bounds.size, contextGenerator: { size, context in + let displaySize = self.displaySize ?? CGSize(width: round(self.bounds.size.width), height: round(self.bounds.size.height)) + let image = generateImage(displaySize, contextGenerator: { size, context in context.clear(CGRect(origin: .zero, size: size)) if let accumulationImage = self.accumulationImage, let cgImage = accumulationImage.cgImage { @@ -101,7 +110,7 @@ final class PenTool: DrawingElement { context.scaleBy(x: 1.0, y: -1.0) context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0) - context.scaleBy(x: 1.0 / self.displayScale, y: 1.0 / self.displayScale) + context.scaleBy(x: 1.0 / self.drawScale.width, y: 1.0 / self.drawScale.height) context.setBlendMode(.copy) element.drawSegments(in: context, from: self.start, to: newStart) @@ -115,7 +124,7 @@ final class PenTool: DrawingElement { self.segmentsCount = element.segments.count if let rect = rect { - self.activeView?.setNeedsDisplay(rect.insetBy(dx: -10.0, dy: -10.0).applying(CGAffineTransform(scaleX: 1.0 / self.displayScale, y: 1.0 / self.displayScale))) + self.activeView?.setNeedsDisplay(rect.insetBy(dx: -10.0, dy: -10.0).applying(CGAffineTransform(scaleX: 1.0 / self.drawScale.width, y: 1.0 / self.drawScale.height))) } else { self.activeView?.setNeedsDisplay() } @@ -127,7 +136,9 @@ final class PenTool: DrawingElement { guard let context = UIGraphicsGetCurrentContext(), let parent = self.parent, let element = parent.element else { return } - context.scaleBy(x: 1.0 / parent.displayScale, y: 1.0 / parent.displayScale) + + parent.displaySize = rect.size + context.scaleBy(x: 1.0 / parent.drawScale.width, y: 1.0 / parent.drawScale.height) element.drawSegments(in: context, from: parent.start, to: parent.segmentsCount) } } @@ -167,6 +178,10 @@ final class PenTool: DrawingElement { } } + var bounds: CGRect { + return boundingRect(from: 0, to: self.segments.count).insetBy(dx: -20.0, dy: -20.0) + } + required init(drawingSize: CGSize, color: DrawingColor, lineWidth: CGFloat, hasArrow: Bool, isEraser: Bool, isBlur: Bool, blurredImage: UIImage?) { self.uuid = UUID() self.drawingSize = drawingSize @@ -220,11 +235,11 @@ final class PenTool: DrawingElement { return } - var filterDistance: CGFloat + let filterDistance: CGFloat if point.velocity > 1200.0 { - filterDistance = 70.0 + filterDistance = 25.0 } else { - filterDistance = 5.0 + filterDistance = 15.0 } if let previousPoint, point.location.distance(to: previousPoint) < filterDistance, state == .changed, self.segments.count > 1 { @@ -237,7 +252,7 @@ final class PenTool: DrawingElement { velocity = 1000.0 } - var effectiveRenderLineWidth = max(self.renderMinLineWidth, min(self.renderLineWidth + 1.0 - (velocity / 220.0), self.renderLineWidth)) + var effectiveRenderLineWidth = max(self.renderMinLineWidth, min(self.renderLineWidth - (velocity / 150.0), self.renderLineWidth)) if let previousRenderLineWidth = self.previousRenderLineWidth { effectiveRenderLineWidth = effectiveRenderLineWidth * 0.2 + previousRenderLineWidth * 0.8 } @@ -307,6 +322,8 @@ final class PenTool: DrawingElement { if self.isEraser { context.setBlendMode(.clear) + } else if self.isBlur { + context.setBlendMode(.normal) } else { context.setAlpha(self.color.alpha) context.setBlendMode(.copy) @@ -448,12 +465,11 @@ final class PenTool: DrawingElement { let step = 1.0 / numberOfSegments for t in stride(from: 0, to: 1, by: step) { - let pX = midPoint1.x * pow(1 - t, 2) + point1.position.x * 2.0 * (1 - t) * t + midPoint2.x * t * t - let pY = midPoint1.y * pow(1 - t, 2) + point1.position.y * 2.0 * (1 - t) * t + midPoint2.y * t * t - + let x = midPoint1.x * pow(1 - t, 2) + point1.position.x * 2.0 * (1 - t) * t + midPoint2.x * t * t + let y = midPoint1.y * pow(1 - t, 2) + point1.position.y * 2.0 * (1 - t) * t + midPoint2.y * t * t let w = midWidth1 * pow(1 - t, 2) + point1.width * 2.0 * (1 - t) * t + midWidth2 * t * t - smoothPoints.append(Point(position: CGPoint(x: pX, y: pY), width: w)) + smoothPoints.append(Point(position: CGPoint(x: x, y: y), width: w)) } smoothPoints.append(Point(position: midPoint2, width: midWidth2)) diff --git a/submodules/DrawingUI/Sources/TextSettingsComponent.swift b/submodules/DrawingUI/Sources/TextSettingsComponent.swift index be7ca71f5f..05ca72c6d5 100644 --- a/submodules/DrawingUI/Sources/TextSettingsComponent.swift +++ b/submodules/DrawingUI/Sources/TextSettingsComponent.swift @@ -183,7 +183,8 @@ final class TextFontComponent: Component { final class View: UIView, ComponentTaggedView { private var button = HighlightableButton() - + private let icon = SimpleLayer() + private var component: TextFontComponent? public func matches(tag: Any) -> Bool { @@ -200,6 +201,7 @@ final class TextFontComponent: Component { super.init(frame: frame) self.addSubview(self.button) + self.button.layer.addSublayer(self.icon) } required init?(coder: NSCoder) { @@ -215,17 +217,48 @@ final class TextFontComponent: Component { func update(component: TextFontComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.component = component + if self.icon.contents == nil { + self.icon.contents = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/FontArrow"), color: UIColor(rgb: 0xffffff, alpha: 0.5))?.cgImage + } + let value = component.selectedValue + var disappearingSnapshotView: UIView? + let previousTitle = self.button.title(for: .normal) + if previousTitle != value.title { + if let snapshotView = self.button.titleLabel?.snapshotView(afterScreenUpdates: false) { + snapshotView.center = self.button.titleLabel?.center ?? snapshotView.center + self.button.addSubview(snapshotView) + snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in + snapshotView?.removeFromSuperview() + }) + self.button.titleLabel?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + disappearingSnapshotView = snapshotView + } + } + + self.button.clipsToBounds = true self.button.setTitle(value.title, for: .normal) self.button.titleLabel?.font = value.uiFont(size: 13.0) - self.button.sizeToFit() - self.button.frame = CGRect(origin: .zero, size: CGSize(width: self.button.frame.width + 16.0, height: 30.0)) + self.button.contentEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 26.0) + var buttonSize = self.button.sizeThatFits(availableSize) + buttonSize.width += 39.0 - 13.0 + buttonSize.height = 30.0 + transition.setFrame(view: self.button, frame: CGRect(origin: .zero, size: buttonSize)) self.button.layer.cornerRadius = 11.0 self.button.layer.borderWidth = 1.0 - UIScreenPixel self.button.layer.borderColor = UIColor.white.cgColor self.button.addTarget(self, action: #selector(self.pressed(_:)), for: .touchUpInside) + let iconSize = CGSize(width: 16.0, height: 16.0) + let iconFrame = CGRect(origin: CGPoint(x: buttonSize.width - iconSize.width - 8.0, y: floorToScreenPixels((buttonSize.height - iconSize.height) / 2.0)), size: iconSize) + transition.setFrame(layer: self.icon, frame: iconFrame) + + if let disappearingSnapshotView, let titleLabel = self.button.titleLabel { + disappearingSnapshotView.layer.animatePosition(from: disappearingSnapshotView.center, to: titleLabel.center, duration: 0.2, removeOnCompletion: false) + self.button.titleLabel?.layer.animatePosition(from: disappearingSnapshotView.center, to: titleLabel.center, duration: 0.2) + } + return CGSize(width: self.button.frame.width, height: availableSize.height) } } diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h index 9ced702203..6a96f9b9ec 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/LegacyComponents.h @@ -211,7 +211,6 @@ #import #import #import -#import #import #import #import @@ -228,10 +227,6 @@ #import #import #import -#import -#import -#import -#import #import #import #import diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintUndoManager.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintUndoManager.h deleted file mode 100644 index ee49b47eba..0000000000 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintUndoManager.h +++ /dev/null @@ -1,21 +0,0 @@ -#import - -@class TGPainting; -@class TGPhotoEntitiesContainerView; - -@interface TGPaintUndoManager : NSObject - -@property (nonatomic, weak) TGPainting *painting; -@property (nonatomic, weak) TGPhotoEntitiesContainerView *entitiesContainer; - -@property (nonatomic, copy) void (^historyChanged)(void); - -@property (nonatomic, readonly) bool canUndo; -- (void)registerUndoWithUUID:(NSInteger)uuid block:(void (^)(TGPainting *, TGPhotoEntitiesContainerView *, NSInteger))block; -- (void)unregisterUndoWithUUID:(NSInteger)uuid; - -- (void)undo; - -- (void)reset; - -@end diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintingData.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintingData.h index 62e1d434d9..f3cf8161ef 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintingData.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPaintingData.h @@ -1,7 +1,6 @@ #import #import -@class TGPaintUndoManager; @class TGMediaEditingContext; @protocol TGMediaEditableItem; diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintEntityView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintEntityView.h index 49601b8e27..828132bc33 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintEntityView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintEntityView.h @@ -2,7 +2,6 @@ @class TGPhotoPaintEntity; @class TGPhotoPaintEntitySelectionView; -@class TGPaintUndoManager; @interface UIView (PixelColor) diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h index 0316dc02bb..0f2952b6ca 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoPaintStickersContext.h @@ -39,6 +39,7 @@ @protocol TGPhotoDrawingView @property (nonatomic, readonly) BOOL isTracking; +@property (nonatomic, assign) CGSize screenSize; @property (nonatomic, copy) void(^ _Nonnull zoomOut)(void); diff --git a/submodules/LegacyComponents/Sources/PGPhotoCustomFilterPass.m b/submodules/LegacyComponents/Sources/PGPhotoCustomFilterPass.m index bd47f4a682..1c614e3b53 100644 --- a/submodules/LegacyComponents/Sources/PGPhotoCustomFilterPass.m +++ b/submodules/LegacyComponents/Sources/PGPhotoCustomFilterPass.m @@ -98,7 +98,6 @@ NSString *const PGPhotoFilterMainShaderString = PGShaderString GLubyte *imageData = NULL; CFDataRef dataFromImageDataProvider = NULL; - GLenum format = GL_BGRA; if (!redrawNeeded) { @@ -136,10 +135,6 @@ NSString *const PGPhotoFilterMainShaderString = PGShaderString alphaInfo != kCGImageAlphaNoneSkipLast) { redrawNeeded = true; - } else - { - /* Can access directly using GL_RGBA pixel format */ - format = GL_RGBA; } } } diff --git a/submodules/LegacyComponents/Sources/TGPaintArrowBrush.h b/submodules/LegacyComponents/Sources/TGPaintArrowBrush.h deleted file mode 100644 index 36b1c0e563..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintArrowBrush.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGPaintBrush.h" - -@interface TGPaintArrowBrush : TGPaintBrush - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintArrowBrush.m b/submodules/LegacyComponents/Sources/TGPaintArrowBrush.m deleted file mode 100644 index cc36638983..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintArrowBrush.m +++ /dev/null @@ -1,90 +0,0 @@ -#import "TGPaintArrowBrush.h" - -const CGFloat TGPaintArrowBrushHardness = 0.92f; - -@implementation TGPaintArrowBrush - -- (CGFloat)spacing -{ - return 0.15f; -} - -- (CGFloat)alpha -{ - return 0.85f; -} - -- (CGFloat)angle -{ - return 0.0f; -} - -//- (CGFloat)dynamic -//{ -// return 0.75f; -//} - -- (bool)arrow -{ - return true; -} - -- (CGImageRef)generateRadialStampForSize:(CGSize)size hardness:(CGFloat)hardness -{ - CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray(); - CGContextRef ctx = CGBitmapContextCreate(NULL, (NSInteger)size.width, (NSInteger)size.height, 8, (NSInteger)size.width, colorspace, kCGImageAlphaNone); - - CGContextSetGrayFillColor(ctx, 0.0f, 1.0f); - CGContextFillRect(ctx, CGRectMake(0, 0, size.width, size.height)); - - NSArray *colors = @[(__bridge id) [UIColor whiteColor].CGColor, (__bridge id) [UIColor blackColor].CGColor]; - const CGFloat locations[] = {0.0, 1.0}; - - CGGradientRef gradientRef = CGGradientCreateWithColors(colorspace, (__bridge CFArrayRef) colors, locations); - CGPoint center = CGPointMake(size.width / 2, size.height / 2); - - CGFloat maxRadius = size.width / 2; - CGFloat hFactor = hardness * 0.99; - CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation |kCGGradientDrawsAfterEndLocation; - CGContextDrawRadialGradient(ctx, gradientRef, center, hFactor * maxRadius, center, maxRadius, options); - - CGImageRef image = CGBitmapContextCreateImage(ctx); - - CGContextRelease(ctx); - CGColorSpaceRelease(colorspace); - CGGradientRelease(gradientRef); - - return image; -} - -- (CGImageRef)stampRef -{ - static CGImageRef image = NULL; - - if (image == NULL) - image = [self generateRadialStampForSize:TGPaintBrushTextureSize hardness:TGPaintArrowBrushHardness]; - - return image; -} - -- (CGImageRef)previewStampRef -{ - if (_previewStampRef == NULL) - _previewStampRef = [self generateRadialStampForSize:TGPaintBrushPreviewTextureSize hardness:TGPaintArrowBrushHardness]; - - return _previewStampRef; -} - -static UIImage *radialBrushPreviewImage = nil; - -- (UIImage *)previewImage -{ - return radialBrushPreviewImage; -} - -- (void)setPreviewImage:(UIImage *)previewImage -{ - radialBrushPreviewImage = previewImage; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintBrush.h b/submodules/LegacyComponents/Sources/TGPaintBrush.h deleted file mode 100644 index 84c6987a72..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintBrush.h +++ /dev/null @@ -1,25 +0,0 @@ -#import -#import - -@interface TGPaintBrush : NSObject -{ - CGImageRef _previewStampRef; -} - -@property (nonatomic, readonly) CGFloat spacing; -@property (nonatomic, readonly) CGFloat alpha; -@property (nonatomic, readonly) CGFloat angle; -@property (nonatomic, readonly) CGFloat scale; -@property (nonatomic, readonly) CGFloat dynamic; -@property (nonatomic, readonly) bool lightSaber; -@property (nonatomic, readonly) bool arrow; - -@property (nonatomic, readonly) CGImageRef stampRef; -@property (nonatomic, readonly) CGImageRef previewStampRef; - -@property (nonatomic, strong) UIImage *previewImage; - -@end - -extern const CGSize TGPaintBrushTextureSize; -extern const CGSize TGPaintBrushPreviewTextureSize; diff --git a/submodules/LegacyComponents/Sources/TGPaintBrush.m b/submodules/LegacyComponents/Sources/TGPaintBrush.m deleted file mode 100644 index 6ae5cad0ba..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintBrush.m +++ /dev/null @@ -1,91 +0,0 @@ -#import "TGPaintBrush.h" - -#import - -const CGSize TGPaintBrushTextureSize = { 384.0f, 384.0f }; -const CGSize TGPaintBrushPreviewTextureSize = { 64.0f, 64.0f }; - -@interface TGPaintBrush () -{ - NSInteger _uuid; -} -@end - -@implementation TGPaintBrush - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - arc4random_buf(&_uuid, sizeof(NSInteger)); - } - return self; -} - -- (void)dealloc -{ - if (_previewStampRef != NULL) - CGImageRelease(_previewStampRef); -} - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return true; - - if (!object || ![object isKindOfClass:[self class]]) - return false; - - TGPaintBrush *brush = (TGPaintBrush *)object; - return (_uuid == brush->_uuid); -} - -- (CGFloat)spacing -{ - return 1.0f; -} - -- (CGFloat)alpha -{ - return 1.0f; -} - -- (CGFloat)angle -{ - return 0.0f; -} - -- (CGFloat)scale -{ - return 1.0f; -} - -- (CGFloat)dynamic -{ - return 0.0f; -} - -- (bool)lightSaber -{ - return false; -} - -- (CGImageRef)stampRef -{ - return NULL; -} - -- (CGImageRef)previewStampRef -{ - if (_previewStampRef == NULL) - { - UIImage *image = TGScaleImageToPixelSize([UIImage imageWithCGImage:self.stampRef], TGPaintBrushPreviewTextureSize); - _previewStampRef = image.CGImage; - CGImageRetain(_previewStampRef); - } - - return _previewStampRef; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintBrushPreview.h b/submodules/LegacyComponents/Sources/TGPaintBrushPreview.h deleted file mode 100644 index 533cf1ce10..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintBrushPreview.h +++ /dev/null @@ -1,11 +0,0 @@ -#import -#import - -@class TGPainting; -@class TGPaintBrush; - -@interface TGPaintBrushPreview : NSObject - -- (UIImage *)imageForBrush:(TGPaintBrush *)brush size:(CGSize)size; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintBrushPreview.m b/submodules/LegacyComponents/Sources/TGPaintBrushPreview.m deleted file mode 100644 index ed39c11790..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintBrushPreview.m +++ /dev/null @@ -1,366 +0,0 @@ -#import "TGPaintBrushPreview.h" - -#import - -#import - -#import "matrix.h" - -#import "TGPainting.h" -#import "TGPaintBrush.h" -#import "TGPaintPath.h" -#import "TGPaintRender.h" -#import "TGPaintShader.h" -#import "TGPaintShaderSet.h" -#import "TGPaintTexture.h" -#import - -const NSUInteger TGPaintBrushPreviewSegmentsCount = 100; - -@interface TGPaintBrushPreview () -{ - EAGLContext *_context; - - TGPaintBrush *_brush; - TGPaintShader *_brushShader; - TGPaintShader *_brushLightShader; - TGPaintShader *_blitLightShader; - TGPaintTexture *_brushTexture; - TGPaintRenderState *_renderState; - - GLuint _quadVAO; - GLuint _quadVBO; - - TGPaintPath *_path; - - GLubyte *_data; - CGContextRef _cgContext; - - GLuint _framebuffer; - GLuint _maskTextureName; - - GLuint _lightFramebuffer; - GLuint _lightTextureName; - - GLfloat _projection[16]; - GLint _width; - GLint _height; - - GLenum _format; - GLenum _type; -} -@end - -@implementation TGPaintBrushPreview - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - - _format = GL_RGBA; - _type = GL_UNSIGNED_BYTE; - - if (_context == nil || ![EAGLContext setCurrentContext:_context]) - return nil; - - glEnable(GL_BLEND); - glDisable(GL_DITHER); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glGenFramebuffers(1, &_framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); - - glGenFramebuffers(1, &_lightFramebuffer); - - NSDictionary *availableShaders = [TGPaintShaderSet availableShaders]; - - NSDictionary *shader = availableShaders[@"brush"]; - _brushShader = [[TGPaintShader alloc] initWithVertexShader:shader[@"vertex"] fragmentShader:shader[@"fragment"] attributes:shader[@"attributes"] uniforms:shader[@"uniforms"]]; - - shader = availableShaders[@"brushLight"]; - _brushLightShader = [[TGPaintShader alloc] initWithVertexShader:shader[@"vertex"] fragmentShader:shader[@"fragment"] attributes:shader[@"attributes"] uniforms:shader[@"uniforms"]]; - - shader = availableShaders[@"brushLightPreview"]; - _blitLightShader = [[TGPaintShader alloc] initWithVertexShader:shader[@"vertex"] fragmentShader:shader[@"fragment"] attributes:shader[@"attributes"] uniforms:shader[@"uniforms"]]; - - _renderState = [[TGPaintRenderState alloc] init]; - - TGPaintHasGLError(); - } - return self; -} - -- (void)dealloc -{ - if (_context == nil) - return; - - [EAGLContext setCurrentContext:_context]; - - if (_cgContext != NULL) - CGContextRelease(_cgContext); - - _brush = nil; - - glDeleteBuffers(1, &_quadVBO); - glDeleteVertexArraysOES(1, &_quadVAO); - - if (_framebuffer != 0) - { - glDeleteFramebuffers(1, &_framebuffer); - _framebuffer = 0; - } - - if (_maskTextureName != 0) - { - glDeleteTextures(1, &_maskTextureName); - _maskTextureName = 0; - } - - if (_lightFramebuffer != 0) - { - glDeleteFramebuffers(1, &_lightFramebuffer); - _lightFramebuffer = 0; - } - - if (_lightTextureName != 0) - { - glDeleteTextures(1, &_lightTextureName); - _lightTextureName = 0; - } - - [EAGLContext setCurrentContext:nil]; -} - -- (void)setSize:(CGSize)size -{ - if (_width == size.width && _height == size.height) - return; - - _width = (GLint)size.width; - _height = (GLint)size.height; - - if (_data != NULL) - free(_data); - - _data = malloc(_width * _height * 4); - - if (_cgContext != NULL) - CGContextRelease(_cgContext); - - CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); - _cgContext = CGBitmapContextCreate(_data, _width, _height, 8, _width * 4, colorSpaceRef, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast); - - CGColorSpaceRelease(colorSpaceRef); - - if (_path != nil) - _path = nil; - - [self _generateBrushPath]; - - GLfloat mProj[16], mScale[16]; - mat4f_LoadOrtho(0, _width, 0, _height, -1.0f, 1.0f, mProj); - - CGFloat scale = MIN(2.0f, TGScreenScaling()); - CGAffineTransform tX = CGAffineTransformMakeScale(scale, scale); - mat4f_LoadCGAffineTransform(mScale, tX); - - mat4f_MultiplyMat4f(mProj, mScale, _projection); - - glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); - - glGenTextures(1, &_maskTextureName); - glBindTexture(GL_TEXTURE_2D, _maskTextureName); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glBindTexture(GL_TEXTURE_2D, _maskTextureName); - glTexImage2D(GL_TEXTURE_2D, 0, _format, _width, _height, 0, _format, _type, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _maskTextureName, 0); - - - glBindFramebuffer(GL_FRAMEBUFFER, _lightFramebuffer); - - glGenTextures(1, &_lightTextureName); - glBindTexture(GL_TEXTURE_2D, _lightTextureName); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glBindTexture(GL_TEXTURE_2D, _lightTextureName); - glTexImage2D(GL_TEXTURE_2D, 0, _format, _width, _height, 0, _format, _type, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _lightTextureName, 0); - - TGPaintHasGLError(); -} - -- (void)_generateBrushPath -{ - if (_path != nil) - return; - - CGFloat scale = MIN(2.0f, TGScreenScaling()); - - CGPoint start = CGPointMake(15.0f, _height / (2.0f * scale)); - CGFloat width = (_width / scale) - 2.0f * 15.0f; - CGFloat amplitude = 6.0f; - - NSMutableArray *points = [[NSMutableArray alloc] init]; - for (NSUInteger i = 0; i < TGPaintBrushPreviewSegmentsCount; i++) - { - CGFloat fraction = (CGFloat)i / (TGPaintBrushPreviewSegmentsCount - 1); - CGPoint pt = CGPointMake(start.x + width * fraction, start.y + sin(-fraction * 2 * M_PI) * amplitude); - - TGPaintPoint *point = [TGPaintPoint pointWithX:pt.x y:pt.y z:fraction]; - [points addObject:point]; - - if (i == 0 || i == TGPaintBrushPreviewSegmentsCount - 1) - point.edge = true; - } - - _path = [[TGPaintPath alloc] initWithPoints:points]; - _path.baseWeight = 12.0f; - _path.color = [UIColor redColor]; -} - -- (void)_setupBrush -{ - TGPaintShader *shader = _brush.lightSaber ? _brushLightShader : _brushShader; - glUseProgram(shader.program); - glActiveTexture(GL_TEXTURE0); - - if (_brushTexture == nil) - _brushTexture = [[TGPaintTexture alloc] initWithCGImage:_brush.previewStampRef forceRGB:false]; - - glBindTexture(GL_TEXTURE_2D, _brushTexture.textureName); - - glUniform1i([shader uniformForKey:@"texture"], 0); - glUniformMatrix4fv([shader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, _projection); -} - -- (void)_cleanBrushResources -{ - if (_brushTexture == nil) - return; - - [EAGLContext setCurrentContext:_context]; - [_brushTexture cleanResources]; - _brushTexture = nil; -} - -- (UIImage *)imageForBrush:(TGPaintBrush *)brush size:(CGSize)size -{ - if (![brush isEqual:_brush]) - [self _cleanBrushResources]; - - _brush = brush; - - CGFloat scale = MIN(2.0f, TGScreenScaling()); - size = TGPaintMultiplySizeScalar(size, scale); - - [EAGLContext setCurrentContext:_context]; - [self setSize:size]; - - glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); - glViewport(0, 0, _width, _height); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - TGPaintHasGLError(); - - [self _setupBrush]; - [_renderState reset]; - _path.remainder = 0.0f; - _path.pressureRemainder = 0.0f; - _path.brush = brush; - - [TGPaintRender renderPath:_path renderState:_renderState]; - - if (_brush.lightSaber) - { - glBindFramebuffer(GL_FRAMEBUFFER, _lightFramebuffer); - glViewport(0, 0, _width, _height); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - TGPaintShader *shader = _blitLightShader; - glUseProgram(shader.program); - - glUniformMatrix4fv([shader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, _projection); - glUniform1i([shader uniformForKey:@"mask"], 0); - TGSetupColorUniform([shader uniformForKey:@"color"], [UIColor blackColor]); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, _maskTextureName); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArrayOES([self _quad]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glBindVertexArrayOES(0); - } - - glReadPixels(0, 0, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, _data); - CGImageRef imageRef = CGBitmapContextCreateImage(_cgContext); - UIImage *result = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]; - CGImageRelease(imageRef); - - return result; -} - -- (GLuint)_quad -{ - if (_quadVAO == 0) - { - [EAGLContext setCurrentContext:_context]; - CGFloat scale = MIN(2.0f, TGScreenScaling()); - CGRect rect = CGRectMake(0, 0, _width / scale, _height / scale); - - CGPoint corners[4]; - corners[0] = rect.origin; - corners[1] = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect)); - corners[2] = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)); - corners[3] = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect)); - - const GLfloat vertices[] = - { - (GLfloat)corners[0].x, (GLfloat)corners[0].y, 0.0, 0.0, - (GLfloat)corners[1].x, (GLfloat)corners[1].y, 1.0, 0.0, - (GLfloat)corners[3].x, (GLfloat)corners[3].y, 0.0, 1.0, - (GLfloat)corners[2].x, (GLfloat)corners[2].y, 1.0, 1.0, - }; - - glGenVertexArraysOES(1, &_quadVAO); - glBindVertexArrayOES(_quadVAO); - - glGenBuffers(1, &_quadVBO); - glBindBuffer(GL_ARRAY_BUFFER, _quadVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, vertices, GL_STATIC_DRAW); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)8); - glEnableVertexAttribArray(1); - - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArrayOES(0); - } - - return _quadVAO; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintBuffers.h b/submodules/LegacyComponents/Sources/TGPaintBuffers.h deleted file mode 100644 index 6ff06bd88f..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintBuffers.h +++ /dev/null @@ -1,20 +0,0 @@ -#import -#import -#import - -@interface TGPaintBuffers : NSObject - -@property (nonatomic, weak) EAGLContext *context; -@property (nonatomic, readonly) CAEAGLLayer *layer; -@property (nonatomic, readonly) GLuint renderbuffer; -@property (nonatomic, readonly) GLuint framebuffer; -@property (nonatomic, readonly) GLuint stencilBuffer; -@property (nonatomic, readonly) GLint width; -@property (nonatomic, readonly) GLint height; - -- (bool)update; -- (void)present; - -+ (instancetype)buffersWithGLContext:(EAGLContext *)context layer:(CAEAGLLayer *)layer; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintBuffers.m b/submodules/LegacyComponents/Sources/TGPaintBuffers.m deleted file mode 100644 index 087367928d..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintBuffers.m +++ /dev/null @@ -1,102 +0,0 @@ -#import "TGPaintBuffers.h" -#import - -#import "LegacyComponentsInternal.h" - -@implementation TGPaintBuffers - -+ (instancetype)buffersWithGLContext:(EAGLContext *)context layer:(CAEAGLLayer *)layer -{ - TGPaintBuffers *c = [[TGPaintBuffers alloc] init]; - - c->_layer = layer; - layer.opaque = false; - layer.drawableProperties = @ - { - kEAGLDrawablePropertyRetainedBacking: @true, - kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8 - }; - - c.context = context; - [EAGLContext setCurrentContext:context]; - - glGenFramebuffers(1, &c->_framebuffer); - glGenRenderbuffers(1, &c->_renderbuffer); - glBindFramebuffer(GL_FRAMEBUFFER, c->_framebuffer); - glBindRenderbuffer(GL_RENDERBUFFER, c->_renderbuffer); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, c->_renderbuffer); - - glGenRenderbuffers(1, &c->_stencilBuffer); - glBindRenderbuffer(GL_RENDERBUFFER, c->_stencilBuffer); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, c->_stencilBuffer); - - TGPaintHasGLError(); - - return c; -} - -- (void)dealloc -{ - [self cleanResources]; -} - -- (void)cleanResources -{ - [EAGLContext setCurrentContext:_context]; - - if (_framebuffer != 0) - { - glDeleteFramebuffers(1, &_framebuffer); - _framebuffer = 0; - } - - if (_renderbuffer != 0) - { - glDeleteRenderbuffers(1, &_renderbuffer); - _renderbuffer = 0; - } - - if (_stencilBuffer) - { - glDeleteBuffers(1, &_stencilBuffer); - _stencilBuffer = 0; - } - - TGPaintHasGLError(); -} - -- (bool)update -{ - [EAGLContext setCurrentContext:_context]; - TGPaintHasGLError(); - - glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); - glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); - - [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_layer]; - - glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_width); - glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_height); - - glBindRenderbuffer(GL_RENDERBUFFER, _stencilBuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, _width, _height); - - TGPaintHasGLError(); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - TGLegacyLog(@"Failed to create complete framebuffer %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); - return false; - } - - return true; -} - -- (void)present -{ - glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer); - glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer); - [_context presentRenderbuffer:GL_RENDERBUFFER]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintCanvas.h b/submodules/LegacyComponents/Sources/TGPaintCanvas.h deleted file mode 100644 index 11bd547e0a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintCanvas.h +++ /dev/null @@ -1,33 +0,0 @@ -#import - -@class TGPainting; -@class TGPaintBrush; -@class TGPaintState; - -@interface TGPaintCanvas : UIView - -@property (nonatomic, strong) TGPainting *painting; -@property (nonatomic, readonly) TGPaintState *state; - -@property (nonatomic, assign) CGRect cropRect; -@property (nonatomic, assign) UIImageOrientation cropOrientation; -@property (nonatomic, assign) CGSize originalSize; - -@property (nonatomic, copy) bool (^shouldDrawOnSingleTap)(void); - -@property (nonatomic, copy) bool (^shouldDraw)(void); -@property (nonatomic, copy) void (^strokeBegan)(void); -@property (nonatomic, copy) void (^strokeCommited)(void); -@property (nonatomic, copy) UIView *(^hitTest)(CGPoint point, UIEvent *event); -@property (nonatomic, copy) bool (^pointInsideContainer)(CGPoint point); - -@property (nonatomic, readonly) bool isTracking; - -- (void)draw; - -- (void)setBrush:(TGPaintBrush *)brush; -- (void)setBrushWeight:(CGFloat)brushWeight; -- (void)setBrushColor:(UIColor *)color; -- (void)setEraser:(bool)eraser; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintCanvas.m b/submodules/LegacyComponents/Sources/TGPaintCanvas.m deleted file mode 100644 index c750b4208e..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintCanvas.m +++ /dev/null @@ -1,335 +0,0 @@ -#import "TGPaintCanvas.h" - -#import -#import -#import -#import "matrix.h" - -#import "TGPainting.h" -#import "TGPaintBuffers.h" -#import "TGPaintInput.h" -#import "TGPaintState.h" -#import "TGPaintShader.h" -#import -#import - -#import "TGPaintPanGestureRecognizer.h" - -@interface TGPaintCanvas () -{ - TGPaintBuffers *_buffers; - CGFloat _screenScale; - CGAffineTransform _canvasTransform; - CGRect _dirtyRect; - - CGRect _visibleRect; - - TGPaintInput *_input; - TGPaintPanGestureRecognizer *_gestureRecognizer; - bool _beganDrawing; - - __weak dispatch_cancelable_block_t _redrawBlock; -} -@end - -@implementation TGPaintCanvas - -- (instancetype)initWithFrame:(CGRect)frame -{ - _screenScale = MIN(2.0f, [UIScreen mainScreen].scale); - - self = [super initWithFrame:frame]; - if (self != nil) - { - self.contentScaleFactor = _screenScale; - self.multipleTouchEnabled = true; - self.exclusiveTouch = true; - - _state = [[TGPaintState alloc] init]; - - [self _setupGestureRecognizers]; - } - return self; -} - -#pragma mark - Painting - -- (void)setPainting:(TGPainting *)painting -{ - _painting = painting; - - __weak TGPaintCanvas *weakSelf = self; - painting.contentChanged = ^(CGRect rect) - { - __strong TGPaintCanvas *strongSelf = weakSelf; - if (strongSelf == nil) - return; - - if (!CGRectEqualToRect(rect, CGRectZero)) - strongSelf->_dirtyRect = TGPaintUnionRect(strongSelf->_dirtyRect, rect); - else - strongSelf->_dirtyRect = [strongSelf visibleRect]; - - [strongSelf _scheduleRedraw]; - }; - painting.strokeCommited = ^ - { - __strong TGPaintCanvas *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf.strokeCommited != nil) - strongSelf.strokeCommited(); - }; - - [self setContext:painting.context]; - [self _updateTransform]; -} - -- (void)setFrame:(CGRect)frame -{ - [super setFrame:frame]; - _visibleRect = self.bounds; - - [self _updateTransform]; -} - -- (void)setBounds:(CGRect)bounds -{ - [super setBounds:bounds]; - - _visibleRect = bounds; -} - -- (void)_updateTransform -{ - CGAffineTransform transform = CGAffineTransformIdentity; - - CGPoint center = TGPaintCenterOfRect(self.bounds); - CGFloat scale = _painting ? self.bounds.size.width / _painting.size.width : 1.0f; - if (scale < FLT_EPSILON) - scale = 1.0f; - - transform = CGAffineTransformTranslate(transform, center.x, center.y); - transform = CGAffineTransformScale(transform, scale, -scale); - transform = CGAffineTransformTranslate(transform, -self.painting.size.width / 2, -self.painting.size.height / 2); - - _canvasTransform = transform; - _input.transform = transform; -} - -#pragma mark - Gesture - -- (void)_setupGestureRecognizers -{ - _input = [[TGPaintInput alloc] init]; - - _gestureRecognizer = [[TGPaintPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _gestureRecognizer.delegate = self; - _gestureRecognizer.minimumNumberOfTouches = 1; - _gestureRecognizer.maximumNumberOfTouches = 2; - - __weak TGPaintCanvas *weakSelf = self; - _gestureRecognizer.shouldRecognizeTap = ^bool - { - __strong TGPaintCanvas *strongSelf = weakSelf; - if (strongSelf == nil) - return false; - - if (strongSelf.shouldDrawOnSingleTap != nil) - { - bool drawOnTap = strongSelf.shouldDrawOnSingleTap(); - bool draw = strongSelf.shouldDraw(); - - return draw && drawOnTap; - } - - return false; - }; - [self addGestureRecognizer:_gestureRecognizer]; -} - -- (void)handlePan:(TGPaintPanGestureRecognizer *)gestureRecognizer -{ - if (gestureRecognizer.state == UIGestureRecognizerStateBegan || gestureRecognizer.state == UIGestureRecognizerStateChanged) - { - if (!_beganDrawing) - { - [_input gestureBegan:gestureRecognizer]; - if (self.strokeBegan != nil) - self.strokeBegan(); - _beganDrawing = true; - } - else - { - [_input gestureMoved:gestureRecognizer]; - } - } - else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) - { - [_input gestureEnded:gestureRecognizer]; - _beganDrawing = false; - } - else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled) - { - [_input gestureCanceled:gestureRecognizer]; - _beganDrawing = false; - } -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - if (self.shouldDraw != nil) - return self.shouldDraw(); - - return true; -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer -{ -// if (gestureRecognizer == _gestureRecognizer && ([otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]])) -// return false; -// - return true; -} - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - UIView *view = [super hitTest:point withEvent:event]; - - if (self.hitTest != nil) - { - UIView *maybeHitView = self.hitTest(point, event); - if (maybeHitView != nil) - view = maybeHitView; - } - - return view; -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)__unused event -{ - return self.pointInsideContainer(point); -} - -- (bool)isTracking -{ - return (_gestureRecognizer.state == UIGestureRecognizerStateBegan || _gestureRecognizer.state == UIGestureRecognizerStateChanged); -} - -#pragma mark - Draw - -- (void)draw -{ - [self drawInRect:[self visibleRect]]; -} - -- (void)drawInRect:(CGRect)__unused rect -{ - [EAGLContext setCurrentContext:_buffers.context]; - - glBindFramebuffer(GL_FRAMEBUFFER, _buffers.framebuffer); - glViewport(0, 0, _buffers.width, _buffers.height); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - GLfloat proj[16], effectiveProj[16], final[16]; - mat4f_LoadOrtho(0, (GLfloat)(_buffers.width / _screenScale), 0, (GLfloat)(_buffers.height / _screenScale), -1.0f, 1.0f, proj); - mat4f_LoadCGAffineTransform(effectiveProj, _canvasTransform); - mat4f_MultiplyMat4f(proj, effectiveProj, final); - - [_painting renderWithProjection:final]; - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - [_buffers present]; - - TGPaintHasGLError(); - - _dirtyRect = CGRectZero; -} - -- (void)redrawIfNeeded -{ - if (CGRectEqualToRect(_dirtyRect, CGRectZero)) - return; - - [self drawInRect:_dirtyRect]; -} - -- (void)_scheduleRedraw -{ - if (_redrawBlock != nil) - { - cancel_block(_redrawBlock); - _redrawBlock = nil; - } - - __weak TGPaintCanvas *weakSelf = self; - _redrawBlock = dispatch_after_delay(0.0, [_painting _queue], ^ - { - __strong TGPaintCanvas *strongSelf = weakSelf; - if (strongSelf != nil) - [strongSelf redrawIfNeeded]; - }); -} - -#pragma mark - - -- (CGRect)visibleRect -{ - return _visibleRect; -} - -- (void)layoutSubviews -{ - [super layoutSubviews]; - - [self.painting performSynchronouslyInContext:^{ - [_buffers update]; - - [self draw]; - }]; -} - -#pragma mark - GL Setup - -- (void)setContext:(EAGLContext *)context -{ - if (context == _buffers.context) - return; - - if (context != nil) - { - _buffers = [TGPaintBuffers buffersWithGLContext:context layer:(CAEAGLLayer *)self.layer]; - [_buffers update]; - } -} - -+ (Class)layerClass -{ - return [CAEAGLLayer class]; -} - -#pragma mark - - -- (void)setBrush:(TGPaintBrush *)brush -{ - _state.brush = brush; - [_painting setBrush:brush]; -} - -- (void)setBrushWeight:(CGFloat)brushWeight -{ - _state.weight = brushWeight; -} - -- (void)setBrushColor:(UIColor *)color -{ - _state.color = color; -} - -- (void)setEraser:(bool)eraser -{ - _state.eraser = eraser; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintEllipticalBrush.h b/submodules/LegacyComponents/Sources/TGPaintEllipticalBrush.h deleted file mode 100644 index 97dcb23157..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintEllipticalBrush.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGPaintBrush.h" - -@interface TGPaintEllipticalBrush : TGPaintBrush - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintEllipticalBrush.m b/submodules/LegacyComponents/Sources/TGPaintEllipticalBrush.m deleted file mode 100644 index 6fada1d626..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintEllipticalBrush.m +++ /dev/null @@ -1,94 +0,0 @@ -#import "TGPaintEllipticalBrush.h" -#import - -const CGFloat TGPaintEllipticalBrushHardness = 0.89f; -const CGFloat TGPaintEllipticalBrushAngle = 110.0f; -const CGFloat TGPaintEllipticalBrushRoundness = 0.35f; - -@implementation TGPaintEllipticalBrush - -- (CGFloat)spacing -{ - return 0.075f; -} - -- (CGFloat)alpha -{ - return 0.17f; -} - -- (CGFloat)angle -{ - return TGDegreesToRadians(TGPaintEllipticalBrushAngle); -} - -- (CGFloat)scale -{ - return 1.5f; -} - -- (CGImageRef)generateEllipticalStampForSize:(CGSize)size hardness:(CGFloat)hardness roundness:(CGFloat)roundness -{ - CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray(); - CGContextRef ctx = CGBitmapContextCreate(NULL, (NSInteger)size.width, (NSInteger)size.height, 8, (NSInteger)size.width, colorspace, kCGImageAlphaNone); - - CGContextSetGrayFillColor(ctx, 0.4f, 1.0f); - CGContextFillRect(ctx, CGRectMake(0, 0, size.width, size.height)); - - CGContextTranslateCTM(ctx, 0.5f * size.width, 0.5f * size.height); - CGContextScaleCTM(ctx, roundness, 1.0f); - CGContextTranslateCTM(ctx, -0.5f * size.width, -0.5f * size.height); - - NSArray *colors = @[(__bridge id) [UIColor whiteColor].CGColor, (__bridge id) [UIColor blackColor].CGColor]; - const CGFloat locations[] = {0.0, 1.0}; - - CGGradientRef gradientRef = CGGradientCreateWithColors(colorspace, (__bridge CFArrayRef) colors, locations); - CGPoint center = CGPointMake(size.width / 2, size.height / 2); - - CGFloat maxRadius = size.width / 2; - CGFloat hFactor = hardness * 0.99; - CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation |kCGGradientDrawsAfterEndLocation; - CGContextDrawRadialGradient(ctx, gradientRef, center, hFactor * maxRadius, center, maxRadius, options); - - CGImageRef image = CGBitmapContextCreateImage(ctx); - - CGContextRelease(ctx); - CGColorSpaceRelease(colorspace); - CGGradientRelease(gradientRef); - - return image; -} - -- (CGImageRef)stampRef -{ - static CGImageRef image = NULL; - - if (image == NULL) - image = [self generateEllipticalStampForSize:TGPaintBrushTextureSize hardness:TGPaintEllipticalBrushHardness roundness:TGPaintEllipticalBrushRoundness]; - - return image; -} - -- (CGImageRef)previewStampRef -{ - if (_previewStampRef == NULL) - { - _previewStampRef = [self generateEllipticalStampForSize:TGPaintBrushPreviewTextureSize hardness:TGPaintEllipticalBrushHardness roundness:TGPaintEllipticalBrushRoundness]; - } - - return _previewStampRef; -} - -static UIImage *ellipticalBrushPreviewImage = nil; - -- (UIImage *)previewImage -{ - return ellipticalBrushPreviewImage; -} - -- (void)setPreviewImage:(UIImage *)previewImage -{ - ellipticalBrushPreviewImage = previewImage; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintFaceDebugView.h b/submodules/LegacyComponents/Sources/TGPaintFaceDebugView.h deleted file mode 100644 index 64778ccbd6..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintFaceDebugView.h +++ /dev/null @@ -1,7 +0,0 @@ -#import - -@interface TGPaintFaceDebugView : UIView - -- (void)setFaces:(NSArray *)faces paintingSize:(CGSize)paintingSize originalSize:(CGSize)originalSize; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintFaceDebugView.m b/submodules/LegacyComponents/Sources/TGPaintFaceDebugView.m deleted file mode 100644 index aa55bd3c8a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintFaceDebugView.m +++ /dev/null @@ -1,65 +0,0 @@ -#import "TGPaintFaceDebugView.h" - -#import "LegacyComponentsInternal.h" - -#import "TGPaintFaceDetector.h" - -@interface TGPaintFaceView : UIView - -- (instancetype)initWithFace:(TGPaintFace *)face paintingSize:(CGSize)paintingSize originalSize:(CGSize)originalSize; - -@end - -@implementation TGPaintFaceDebugView - -- (void)setFaces:(NSArray *)faces paintingSize:(CGSize)paintingSize originalSize:(CGSize)originalSize -{ - self.backgroundColor = UIColorRGBA(0x00ff00, 0.2f); - - for (UIView *view in self.subviews) - [view removeFromSuperview]; - - for (TGPaintFace *face in faces) - { - TGPaintFaceView *view = [[TGPaintFaceView alloc] initWithFace:face paintingSize:paintingSize originalSize:originalSize]; - [self addSubview:view]; - } -} - -@end - - -@implementation TGPaintFaceView - -- (instancetype)initWithFace:(TGPaintFace *)face paintingSize:(CGSize)paintingSize originalSize:(CGSize)originalSize -{ - CGRect bounds = [TGPaintFaceUtils transposeRect:face.bounds paintingSize:paintingSize originalSize:originalSize]; - self = [super initWithFrame:bounds]; - if (self != nil) - { - UIView *background = [[UIView alloc] initWithFrame:self.bounds]; - background.backgroundColor = UIColorRGBA(0xff0000, 0.4f); - [self addSubview:background]; - - void (^createViewForFeature)(TGPaintFaceFeature *) = ^(TGPaintFaceFeature *feature) - { - if (feature == nil) - return; - - CGPoint position = [TGPaintFaceUtils transposePoint:feature.position paintingSize:paintingSize originalSize:originalSize]; - - UIView *view = [[UIView alloc] initWithFrame:CGRectMake(position.x - 10.0f - self.frame.origin.x, position.y - 10.0f - self.frame.origin.y, 20, 20)]; - view.backgroundColor = UIColorRGBA(0x0000ff, 0.5f); - [self addSubview:view]; - }; - - createViewForFeature(face.leftEye); - createViewForFeature(face.rightEye); - createViewForFeature(face.mouth); - - background.transform = CGAffineTransformMakeRotation(face.angle); - } - return self; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintInput.h b/submodules/LegacyComponents/Sources/TGPaintInput.h deleted file mode 100644 index 11ba035669..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintInput.h +++ /dev/null @@ -1,16 +0,0 @@ -#import -#import - -@class TGPaintState; -@class TGPaintPanGestureRecognizer; - -@interface TGPaintInput : NSObject - -@property (nonatomic, assign) CGAffineTransform transform; - -- (void)gestureBegan:(TGPaintPanGestureRecognizer *)recognizer; -- (void)gestureMoved:(TGPaintPanGestureRecognizer *)recognizer; -- (void)gestureEnded:(TGPaintPanGestureRecognizer *)recognizer; -- (void)gestureCanceled:(TGPaintPanGestureRecognizer *)recognizer; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintInput.m b/submodules/LegacyComponents/Sources/TGPaintInput.m deleted file mode 100644 index 53ba273bf0..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintInput.m +++ /dev/null @@ -1,225 +0,0 @@ -#import "TGPaintInput.h" -#import - -#import "LegacyComponentsInternal.h" - -#import "TGPaintPanGestureRecognizer.h" - -#import "TGPainting.h" -#import "TGPaintPath.h" -#import "TGPaintState.h" -#import "TGPaintCanvas.h" -#import "TGPaintBrush.h" -#import - -@interface TGPaintInput () -{ - bool _first; - bool _moved; - bool _clearBuffer; - - CGPoint _lastLocation; - CGFloat _lastRemainder; - CGFloat _lastPressureRemainder; - CGFloat _lastAngle; - - TGPaintPoint *_points[3]; - NSInteger _pointsCount; -} -@end - -@implementation TGPaintInput - -- (CGPoint)_location:(CGPoint)location inView:(UIView *)view -{ - location.y = view.bounds.size.height - location.y; - - CGAffineTransform inverted = CGAffineTransformInvert(_transform); - CGPoint transformed = CGPointApplyAffineTransform(location, inverted); - - return transformed; -} - -- (void)smoothenAndPaintPoints:(TGPaintCanvas *)canvas ended:(bool)ended -{ - NSMutableArray *points = [[NSMutableArray alloc] init]; - - TGPaintPoint *prev2 = _points[0]; - TGPaintPoint *prev1 = _points[1]; - TGPaintPoint *cur = _points[2]; - - CGPoint midPoint1 = TGPaintMultiplyPoint(TGPaintAddPoints(prev1.CGPoint, prev2.CGPoint), 0.5f); - CGFloat midPressure1 = (prev1.z + prev2.z) * 0.5f; - CGPoint midPoint2 = TGPaintMultiplyPoint(TGPaintAddPoints(cur.CGPoint, prev1.CGPoint), 0.5f); - CGFloat midPressure2 = (cur.z + prev1.z) * 0.5f; - - NSInteger segmentDistance = 2; - CGFloat distance = TGPaintDistance(midPoint1, midPoint2); - NSInteger numberOfSegments = (NSInteger)MIN(72, MAX(floor(distance / segmentDistance), 36)); - - CGFloat t = 0.0f; - CGFloat step = 1.0f / numberOfSegments; - for (NSInteger j = 0; j < numberOfSegments; j++) - { - CGFloat f1 = pow(1 - t, 2); - CGFloat f2 = 2.0 * (1 - t) * t; - CGFloat f3 = t * t; - - CGPoint pos = TGPaintAddPoints(TGPaintAddPoints(TGPaintMultiplyPoint(midPoint1, f1), TGPaintMultiplyPoint(prev1.CGPoint, f2)), TGPaintMultiplyPoint(midPoint2, f3)); - CGFloat pressure = (midPressure1 * f1 + prev1.z * f2) + (midPressure2 * f3); - TGPaintPoint *newPoint = [TGPaintPoint pointWithCGPoint:pos z:pressure]; - if (_first) - { - newPoint.edge = true; - _first = false; - } - [points addObject:newPoint]; - t += step; - } - - TGPaintPoint *finalPoint = [TGPaintPoint pointWithCGPoint:midPoint2 z:midPressure2]; - if (ended) - finalPoint.edge = true; - [points addObject:finalPoint]; - - TGPaintPath *path = [[TGPaintPath alloc] initWithPoints:points]; - [self paintPath:path inCanvas:canvas]; - - for (int i = 0; i < 2; i++) - { - _points[i] = _points[i + 1]; - } - - if (ended) - _pointsCount = 0; - else - _pointsCount = 2; -} - -- (void)gestureBegan:(TGPaintPanGestureRecognizer *)recognizer -{ - _moved = false; - _first = true; - - CGPoint location = [self _location:[recognizer locationInView:recognizer.view] inView:recognizer.view]; - _lastLocation = location; - - TGPaintPoint *point = [TGPaintPoint pointWithX:location.x y:location.y z:1.0f]; - _points[0] = point; - _pointsCount = 1; - - _clearBuffer = true; -} - -- (void)gestureMoved:(TGPaintPanGestureRecognizer *)recognizer -{ - TGPaintCanvas *canvas = (TGPaintCanvas *)recognizer.view; - CGPoint location = [self _location:[recognizer locationInView:recognizer.view] inView:recognizer.view]; - CGFloat distanceMoved = TGPaintDistance(location, _lastLocation); - - if (distanceMoved < 8.0f) - return; - - const CGFloat speedFactor = 3.0f; - CGPoint velocity = [recognizer velocityInView:recognizer.view]; - CGFloat speed = TGPaintDistance(CGPointZero, velocity) / 1000.0f; - CGFloat pressure = TGPaintSineCurve(1.0f - MIN(speedFactor, speed) / speedFactor); - pressure = 1.0f - pressure; - - if (_pointsCount != 0) - pressure = (pressure + _points[_pointsCount - 1].z) / 2.0f; - - TGPaintPoint *point = [TGPaintPoint pointWithX:location.x y:location.y z:pressure]; - _points[_pointsCount++] = point; - - if (_pointsCount == 3) - { - CGPoint prev = _points[1].CGPoint; - CGPoint cur = _points[2].CGPoint; - _lastAngle = atan2(cur.y - prev.y, cur.x - prev.x); - - [self smoothenAndPaintPoints:canvas ended:false]; - _moved = true; - } - - _lastLocation = location; -} - -- (void)gestureEnded:(TGPaintPanGestureRecognizer *)recognizer -{ - TGPaintCanvas *canvas = (TGPaintCanvas *)recognizer.view; - TGPainting *painting = canvas.painting; - - CGPoint location = [self _location:[recognizer locationInView:recognizer.view] inView:recognizer.view]; - if (!_moved) - { - TGPaintPoint *point = [TGPaintPoint pointWithX:location.x y:location.y z:1.0]; - point.edge = true; - - TGPaintPath *path = [[TGPaintPath alloc] initWithPoint:point]; - [self paintPath:path inCanvas:canvas]; - } - else - { - [self smoothenAndPaintPoints:canvas ended:true]; - - if (canvas.state.brush.arrow) { - CGFloat arrowLength = canvas.state.weight * 4.5; - CGFloat angle = _lastAngle; - - TGPaintPoint *tip = [TGPaintPoint pointWithX:location.x y:location.y z:0.8]; - TGPaintPoint *leftTip = [TGPaintPoint pointWithX:location.x + cos(angle - M_PI_4 * 3) * arrowLength y:location.y + sin(angle - M_PI_4 * 3.2) * arrowLength z:1.0]; - leftTip.edge = true; - TGPaintPath *left = [[TGPaintPath alloc] initWithPoints:@[tip, leftTip]]; - [self paintPath:left inCanvas:canvas]; - - TGPaintPoint *rightTip = [TGPaintPoint pointWithX:location.x + cos(angle + M_PI_4 * 3) * arrowLength y:location.y + sin(angle + M_PI_4 * 3.2) * arrowLength z:1.0]; - rightTip.edge = true; - TGPaintPath *right = [[TGPaintPath alloc] initWithPoints:@[tip, rightTip]]; - [self paintPath:right inCanvas:canvas]; - } - } - - _pointsCount = 0; - - [painting commitStrokeWithColor:canvas.state.color erase:canvas.state.isEraser]; -} - -- (void)gestureCanceled:(UIGestureRecognizer *)recognizer -{ - TGPaintCanvas *canvas = (TGPaintCanvas *) recognizer.view; - TGPainting *painting = canvas.painting; - - [painting performAsynchronouslyInContext:^{ - painting.activePath = nil; - [canvas draw]; - }]; -} - -- (void)paintPath:(TGPaintPath *)path inCanvas:(TGPaintCanvas *)canvas -{ - path.color = canvas.state.color; - path.action = canvas.state.isEraser ? TGPaintActionErase : TGPaintActionDraw; - path.brush = canvas.state.brush; - path.baseWeight = canvas.state.weight; - - if (_clearBuffer) { - _lastRemainder = 0.0f; - _lastPressureRemainder = 0.0f; - } - - path.remainder = _lastRemainder; - path.pressureRemainder = _lastPressureRemainder; - - [canvas.painting paintStroke:path clearBuffer:_clearBuffer completion:^ - { - TGDispatchOnMainThread(^ - { - _lastRemainder = path.remainder; - _lastPressureRemainder = path.pressureRemainder; - _clearBuffer = false; - }); - }]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintNeonBrush.h b/submodules/LegacyComponents/Sources/TGPaintNeonBrush.h deleted file mode 100644 index d902dc245c..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintNeonBrush.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGPaintBrush.h" - -@interface TGPaintNeonBrush : TGPaintBrush - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintNeonBrush.m b/submodules/LegacyComponents/Sources/TGPaintNeonBrush.m deleted file mode 100644 index 83232780f1..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintNeonBrush.m +++ /dev/null @@ -1,113 +0,0 @@ -#import "TGPaintNeonBrush.h" - -#import "LegacyComponentsInternal.h" - -const CGFloat TGPaintNeonBrushSolidFraction = 0.41f; -const CGFloat TGPaintNeonBrushBorderFraction = 0.036f; - -@implementation TGPaintNeonBrush - -- (CGFloat)spacing -{ - return 0.07f; -} - -- (CGFloat)alpha -{ - return 0.7f; -} - -- (CGFloat)angle -{ - return 0.0f; -} - -- (CGFloat)scale -{ - return 1.45f; -} - -- (bool)lightSaber -{ - return true; -} - -- (CGImageRef)generateNeonStampForSize:(CGSize)size -{ - CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); - CGContextRef ctx = CGBitmapContextCreate(NULL, (NSInteger)size.width, (NSInteger)size.height, 8, (NSInteger)size.width * 4, colorspace, kCGImageAlphaPremultipliedLast); - - CGPoint center = CGPointMake(size.width / 2, size.height / 2); - - NSArray *redColors = @ - [ - (__bridge id)UIColorRGB(0x440000).CGColor, - (__bridge id)UIColorRGB(0x440000).CGColor, - (__bridge id)[UIColor blackColor].CGColor - ]; - const CGFloat redLocations[] = { 0.0f, 0.54f, 1.0f }; - CGGradientRef gradientRef = CGGradientCreateWithColors(colorspace, (__bridge CFArrayRef)redColors, redLocations); - CGFloat redMaxRadius = size.width / 2; - CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; - - CGContextDrawRadialGradient(ctx, gradientRef, center, 0, center, redMaxRadius, options); - CGGradientRelease(gradientRef); - - CGContextSetBlendMode(ctx, kCGBlendModeScreen); - - CGFloat border = floor(size.width / 2 * TGPaintNeonBrushBorderFraction); - - CGFloat blueRadius = floor(size.width / 2 * TGPaintNeonBrushSolidFraction - border); - CGContextSetFillColorWithColor(ctx, [UIColor blueColor].CGColor); - CGContextAddEllipseInRect(ctx, CGRectMake(size.width / 2.0f - blueRadius, size.height / 2.0f - blueRadius, blueRadius * 2, blueRadius * 2)); - CGContextFillPath(ctx); - - CGFloat greenRadius = blueRadius + border + 1; - CGContextSetLineWidth(ctx, border * 3); - CGContextSetStrokeColorWithColor(ctx, [UIColor greenColor].CGColor); - CGContextAddEllipseInRect(ctx, CGRectMake(size.width / 2.0f - greenRadius, size.height / 2.0f - greenRadius, greenRadius * 2, greenRadius * 2)); - CGContextStrokePath(ctx); - - CGImageRef image = CGBitmapContextCreateImage(ctx); - - CGContextRelease(ctx); - CGColorSpaceRelease(colorspace); - - return image; -} - -- (CGImageRef)stampRef -{ - static CGImageRef image = NULL; - - if (image == NULL) - { - image = [self generateNeonStampForSize:TGPaintBrushTextureSize]; - } - - return image; -} - -- (CGImageRef)previewStampRef -{ - if (_previewStampRef == NULL) - { - _previewStampRef = [self generateNeonStampForSize:TGPaintBrushPreviewTextureSize]; - } - - return _previewStampRef; -} - -static UIImage *neonBrushPreviewImage = nil; - -- (UIImage *)previewImage -{ - return neonBrushPreviewImage; -} - -- (void)setPreviewImage:(UIImage *)previewImage -{ - neonBrushPreviewImage = previewImage; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintPanGestureRecognizer.h b/submodules/LegacyComponents/Sources/TGPaintPanGestureRecognizer.h deleted file mode 100644 index be917f7891..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintPanGestureRecognizer.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface TGPaintPanGestureRecognizer : UIPanGestureRecognizer - -@property (nonatomic, copy) bool (^shouldRecognizeTap)(void); -@property (nonatomic) NSSet *touches; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintPanGestureRecognizer.m b/submodules/LegacyComponents/Sources/TGPaintPanGestureRecognizer.m deleted file mode 100644 index 15fb86a144..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintPanGestureRecognizer.m +++ /dev/null @@ -1,38 +0,0 @@ -#import "TGPaintPanGestureRecognizer.h" - -#import - -@implementation TGPaintPanGestureRecognizer - -- (void)touchesBegan:(NSSet *)inTouches withEvent:(UIEvent *)event -{ - _touches = [inTouches copy]; - [super touchesBegan:inTouches withEvent:event]; - - if (inTouches.count == 1 && self.shouldRecognizeTap != nil && self.shouldRecognizeTap()) - self.state = UIGestureRecognizerStateBegan; -} - -- (void)touchesMoved:(NSSet *)inTouches withEvent:(UIEvent *)event -{ - _touches = [inTouches copy]; - if (inTouches.count > 1) { - self.state = UIGestureRecognizerStateCancelled; - } else { - [super touchesMoved:inTouches withEvent:event]; - } -} - -- (void)touchesEnded:(NSSet *)inTouches withEvent:(UIEvent *)event -{ - _touches = [inTouches copy]; - [super touchesEnded:inTouches withEvent:event]; -} - -- (void)touchesCancelled:(NSSet *)inTouches withEvent:(UIEvent *)event -{ - _touches = [inTouches copy]; - [super touchesCancelled:inTouches withEvent:event]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintPath.h b/submodules/LegacyComponents/Sources/TGPaintPath.h deleted file mode 100644 index 953112369a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintPath.h +++ /dev/null @@ -1,53 +0,0 @@ -#import -#import -#import - -@interface TGPaintPoint : NSObject - -@property (nonatomic, assign) CGFloat x; -@property (nonatomic, assign) CGFloat y; -@property (nonatomic, assign) CGFloat z; - -@property (nonatomic, assign) bool edge; - -- (TGPaintPoint *)add:(TGPaintPoint *)point; -- (TGPaintPoint *)subtract:(TGPaintPoint *)point; -- (TGPaintPoint *)multiplyByScalar:(CGFloat)scalar; - -- (CGFloat)distanceTo:(TGPaintPoint *)point; -- (TGPaintPoint *)normalize; - -- (CGPoint)CGPoint; - -+ (instancetype)pointWithX:(CGFloat)x y:(CGFloat)y z:(CGFloat)z; -+ (instancetype)pointWithCGPoint:(CGPoint)point z:(CGFloat)z; - -@end - - -typedef enum -{ - TGPaintActionDraw, - TGPaintActionErase -} TGPaintAction; - -@class TGPaintBrush; - -@interface TGPaintPath : NSObject - -@property (nonatomic, strong) NSArray *points; - -@property (nonatomic, strong) UIColor *color; -@property (nonatomic, assign) TGPaintAction action; -@property (nonatomic, assign) CGFloat baseWeight; -@property (nonatomic, strong) TGPaintBrush *brush; - -@property (nonatomic, assign) CGFloat remainder; -@property (nonatomic, assign) CGFloat pressureRemainder; - -- (instancetype)initWithPoint:(TGPaintPoint *)point; -- (instancetype)initWithPoints:(NSArray *)points; -- (void)addPoint:(TGPaintPoint *)point; - -@end - diff --git a/submodules/LegacyComponents/Sources/TGPaintPath.m b/submodules/LegacyComponents/Sources/TGPaintPath.m deleted file mode 100644 index 3c28de7b3c..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintPath.m +++ /dev/null @@ -1,130 +0,0 @@ -#import "TGPaintPath.h" - -@implementation TGPaintPoint - -+ (instancetype)pointWithX:(CGFloat)x y:(CGFloat)y z:(CGFloat)z -{ - TGPaintPoint *point = [[TGPaintPoint alloc] init]; - point.x = x; - point.y = y; - point.z = z; - return point; -} - -+ (instancetype)pointWithCGPoint:(CGPoint)inPoint z:(CGFloat)z -{ - TGPaintPoint *point = [[TGPaintPoint alloc] init]; - point.x = inPoint.x; - point.y = inPoint.y; - point.z = z; - return point; -} - -- (instancetype)copyWithZone:(NSZone *)__unused zone -{ - return [TGPaintPoint pointWithX:_x y:_y z:_z]; -} - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return true; - - if (!object || ![object isKindOfClass:[self class]]) - return false; - - TGPaintPoint *point = (TGPaintPoint *)object; - return (_x == point.x && _y == point.y && _z == point.z); -} - -- (CGPoint)CGPoint -{ - return CGPointMake(_x, _y); -} - -- (TGPaintPoint *)add:(TGPaintPoint *)point -{ - return [TGPaintPoint pointWithX:_x + point.x y:_y + point.y z:_z + point.z]; -} - -- (TGPaintPoint *)subtract:(TGPaintPoint *)point -{ - return [TGPaintPoint pointWithX:_x - point.x y:_y - point.y z:_z - point.z]; -} - -- (TGPaintPoint *)multiplyByScalar:(CGFloat)scalar -{ - return [TGPaintPoint pointWithX:_x * scalar y:_y * scalar z:_z * scalar]; -} - -- (TGPaintPoint *)normalize -{ - return [self multiplyByScalar:1.0f / [self magnitude]]; -} - -- (CGFloat)magnitude -{ - return sqrt(_x * _x + _y * _y + _z * _z); -} - -- (CGFloat)distanceTo:(TGPaintPoint *)point -{ - CGFloat xD = _x - point.x; - CGFloat yD = _y - point.y; - CGFloat zD = _z - point.z; - - return sqrt(xD * xD + yD * yD + zD * zD); -} - -@end - - -@interface TGPaintPath () -{ - NSMutableArray *_points; -} -@end - -@implementation TGPaintPath - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - _points = [[NSMutableArray alloc] init]; - } - return self; -} - -- (instancetype)initWithPoint:(TGPaintPoint *)point -{ - self = [self init]; - if (self != nil) - { - [_points addObject:point]; - } - return self; -} - -- (instancetype)initWithPoints:(NSArray *)points -{ - self = [self init]; - if (self != nil) - { - [_points addObjectsFromArray:points]; - } - return self; -} - -- (NSArray *)points -{ - return [_points copy]; -} - -- (void)addPoint:(TGPaintPoint *)point -{ - [_points addObject:point]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintRadialBrush.h b/submodules/LegacyComponents/Sources/TGPaintRadialBrush.h deleted file mode 100644 index ac63275ce2..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintRadialBrush.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGPaintBrush.h" - -@interface TGPaintRadialBrush : TGPaintBrush - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintRadialBrush.m b/submodules/LegacyComponents/Sources/TGPaintRadialBrush.m deleted file mode 100644 index 2bf80678af..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintRadialBrush.m +++ /dev/null @@ -1,85 +0,0 @@ -#import "TGPaintRadialBrush.h" - -const CGFloat TGPaintRadialBrushHardness = 0.92f; - -@implementation TGPaintRadialBrush - -- (CGFloat)spacing -{ - return 0.15f; -} - -- (CGFloat)alpha -{ - return 0.85f; -} - -- (CGFloat)angle -{ - return 0.0f; -} - -//- (CGFloat)dynamic -//{ -// return 0.75f; -//} - -- (CGImageRef)generateRadialStampForSize:(CGSize)size hardness:(CGFloat)hardness -{ - CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray(); - CGContextRef ctx = CGBitmapContextCreate(NULL, (NSInteger)size.width, (NSInteger)size.height, 8, (NSInteger)size.width, colorspace, kCGImageAlphaNone); - - CGContextSetGrayFillColor(ctx, 0.0f, 1.0f); - CGContextFillRect(ctx, CGRectMake(0, 0, size.width, size.height)); - - NSArray *colors = @[(__bridge id) [UIColor whiteColor].CGColor, (__bridge id) [UIColor blackColor].CGColor]; - const CGFloat locations[] = {0.0, 1.0}; - - CGGradientRef gradientRef = CGGradientCreateWithColors(colorspace, (__bridge CFArrayRef) colors, locations); - CGPoint center = CGPointMake(size.width / 2, size.height / 2); - - CGFloat maxRadius = size.width / 2; - CGFloat hFactor = hardness * 0.99; - CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation |kCGGradientDrawsAfterEndLocation; - CGContextDrawRadialGradient(ctx, gradientRef, center, hFactor * maxRadius, center, maxRadius, options); - - CGImageRef image = CGBitmapContextCreateImage(ctx); - - CGContextRelease(ctx); - CGColorSpaceRelease(colorspace); - CGGradientRelease(gradientRef); - - return image; -} - -- (CGImageRef)stampRef -{ - static CGImageRef image = NULL; - - if (image == NULL) - image = [self generateRadialStampForSize:TGPaintBrushTextureSize hardness:TGPaintRadialBrushHardness]; - - return image; -} - -- (CGImageRef)previewStampRef -{ - if (_previewStampRef == NULL) - _previewStampRef = [self generateRadialStampForSize:TGPaintBrushPreviewTextureSize hardness:TGPaintRadialBrushHardness]; - - return _previewStampRef; -} - -static UIImage *radialBrushPreviewImage = nil; - -- (UIImage *)previewImage -{ - return radialBrushPreviewImage; -} - -- (void)setPreviewImage:(UIImage *)previewImage -{ - radialBrushPreviewImage = previewImage; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintRender.h b/submodules/LegacyComponents/Sources/TGPaintRender.h deleted file mode 100644 index 5c91d9b87c..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintRender.h +++ /dev/null @@ -1,16 +0,0 @@ -#import -#import - -@class TGPaintPath; - -@interface TGPaintRenderState : NSObject - -- (void)reset; - -@end - -@interface TGPaintRender : NSObject - -+ (CGRect)renderPath:(TGPaintPath *)path renderState:(TGPaintRenderState *)renderState; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintRender.m b/submodules/LegacyComponents/Sources/TGPaintRender.m deleted file mode 100644 index 4f95a87887..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintRender.m +++ /dev/null @@ -1,325 +0,0 @@ -#import "TGPaintRender.h" - -#include - -#import "TGPaintBrush.h" -#import "TGPaintPath.h" -#import - -const NSInteger TGPaintRenderStateDefaultSize = 256; - -@interface TGPaintRenderState () -{ - NSUInteger _allocatedCount; -} - -@property (nonatomic, assign) CGFloat brushWeight; -@property (nonatomic, assign) CGFloat brushDynamic; -@property (nonatomic, assign) CGFloat spacing; -@property (nonatomic, assign) CGFloat alpha; -@property (nonatomic, assign) CGFloat angle; -@property (nonatomic, assign) CGFloat scale; - -@property (nonatomic, readonly) CGFloat *values; -@property (nonatomic, readonly) NSUInteger count; - -@property (nonatomic, assign) CGFloat remainder; -@property (nonatomic, assign) CGFloat pressureRemainder; - -- (void)reset; - -@end - -@implementation TGPaintRenderState - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - _values = NULL; - } - return self; -} - -- (void)dealloc -{ - if (_values != NULL) - { - free(_values); - _values = NULL; - } -} - -- (void)prepare -{ - if (_values != NULL) - { - free(_values); - _values = NULL; - } - - _count = 0; - _allocatedCount = TGPaintRenderStateDefaultSize; - _values = malloc(sizeof(CGFloat) * TGPaintRenderStateDefaultSize * 5); -} - -- (void)appendValuesCount:(NSUInteger)count -{ - NSUInteger newTotalCount = _count + count; - - if (newTotalCount > _allocatedCount || _values == NULL) - { - if (_values != NULL) - { - free(_values); - _values = NULL; - } - - NSInteger newCount = MAX(_allocatedCount * 2, TGPaintRenderStateDefaultSize); - _values = malloc(sizeof(CGFloat) * newCount * 5); - _allocatedCount = newCount; - } - - _count = newTotalCount; -} - -- (void)addPoint:(CGPoint)point size:(CGFloat)size angle:(CGFloat)angle alpha:(CGFloat)alpha index:(NSInteger)index -{ - NSInteger column = index * 5; - _values[column] = point.x; - _values[column + 1] = point.y; - _values[column + 2] = size; - _values[column + 3] = angle; - _values[column + 4] = alpha; -} - -- (void)reset -{ - _count = 0; - _allocatedCount = 0; - if (_values != NULL) - { - free(_values); - _values = NULL; - } - - _remainder = 0; - _pressureRemainder = 0; -} - -@end - -@implementation TGPaintRender - -typedef struct -{ - GLfloat x; - GLfloat y; - GLfloat s; - GLfloat t; - GLfloat a; -} vertexData; - -+ (void)_paintStamp:(TGPaintPoint *)point state:(TGPaintRenderState *)state -{ - CGFloat brushSize = state.brushWeight * state.scale; - CGFloat angleOffset = fabs(state.angle) > FLT_EPSILON ? state.angle : 0.0f; - CGFloat alpha = MIN(1.0f, state.alpha * 1.55f); - - [state prepare]; - [state appendValuesCount:4]; - for (NSInteger i = 0; i < 4; i++) { - [state addPoint:point.CGPoint size:brushSize angle:angleOffset alpha:alpha index:i]; - } -} - -+ (void)_paintFromPoint:(TGPaintPoint *)lastLocation toPoint:(TGPaintPoint *)location state:(TGPaintRenderState *)state -{ - CGFloat lastP = lastLocation.z; - CGFloat p = location.z; - CGFloat pDelta = p - lastP; - CGFloat pChange = 0.0f; - - CGFloat f, distance = TGPaintDistance(lastLocation.CGPoint, location.CGPoint); - CGPoint vector = TGPaintSubtractPoints(location.CGPoint, lastLocation.CGPoint); - CGPoint unitVector = CGPointMake(1.0f, 1.0f); - CGFloat vectorAngle = fabs(state.angle) > FLT_EPSILON ? state.angle : atan2(vector.y, vector.x); - - CGFloat brushWeight = state.brushWeight * state.scale; - CGFloat step = MAX(1.0f, state.spacing * brushWeight); - - CGFloat pressure = lastP + state.pressureRemainder; - CGFloat pressureStep = pressureStep = pDelta / ((distance - state.remainder) / step); - - if (distance > 0.0f) - unitVector = TGPaintMultiplyPoint(vector, 1.0f / distance); - - CGPoint start = TGPaintAddPoints(lastLocation.CGPoint, TGPaintMultiplyPoint(unitVector, state.remainder)); - - NSInteger i = state.count; - NSInteger count = (NSInteger)(ceil((distance - state.remainder) / step)); - - CGFloat boldenedAlpha = MIN(1.0f, state.alpha * 1.15f); - bool boldenFirst = lastLocation.edge; - bool boldenLast = location.edge; - - [state appendValuesCount:count]; - - for (f = state.remainder; f <= distance; f += step, pressure += pressureStep) - { - CGFloat alpha = boldenFirst ? boldenedAlpha : state.alpha; - CGFloat brushSize = MAX(1.0, brushWeight - state.brushDynamic * pressure * brushWeight); -// CGFloat brushSize = brushWeight; - [state addPoint:start size:brushSize angle:vectorAngle alpha:alpha index:i]; - - start = TGPaintAddPoints(start, TGPaintMultiplyPoint(unitVector, step)); - - boldenFirst = false; - - pChange += pressureStep; - - i++; - } -// NSLog(@"final pressure %f", pressure); - - if (boldenLast) - { - [state appendValuesCount:1]; - CGFloat brushSize = MAX(1.0, brushWeight - state.brushDynamic * pressure * brushWeight); - [state addPoint:location.CGPoint size:brushSize angle:vectorAngle alpha:boldenedAlpha index:i]; - } - - state.remainder = f - distance; - state.pressureRemainder = pChange - pDelta; -} - -+ (CGRect)_drawWithState:(TGPaintRenderState *)state -{ - vertexData *vertexD = calloc(sizeof(vertexData), state.count * 4 + (state.count - 1) * 2); - CGRect dataBounds = CGRectZero; - - int n = 0; - for (NSUInteger i = 0; i < state.count; i++) - { - NSInteger column = i * 5; - - CGPoint result = CGPointMake(state.values[column], state.values[column + 1]); - CGFloat size = state.values[column + 2] / 2; - CGFloat angle = state.values[column + 3]; - CGFloat alpha = state.values[column + 4]; - - CGRect rect = CGRectMake(result.x - size, result.y - size, size*2, size*2); - CGPoint a = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect)); - CGPoint b = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect)); - CGPoint c = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect)); - CGPoint d = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)); - - CGPoint center = TGPaintCenterOfRect(rect); - CGAffineTransform t = CGAffineTransformMakeTranslation(center.x, center.y); - t = CGAffineTransformRotate(t, angle); - t = CGAffineTransformTranslate(t, -center.x, -center.y); - - a = CGPointApplyAffineTransform(a, t); - b = CGPointApplyAffineTransform(b, t); - c = CGPointApplyAffineTransform(c, t); - d = CGPointApplyAffineTransform(d, t); - - CGRect boxBounds = CGRectApplyAffineTransform(rect, t); - dataBounds = TGPaintUnionRect(dataBounds, CGRectIntegral(boxBounds)); - - if (n != 0) - { - vertexD[n].x = (GLfloat)a.x; - vertexD[n].y = (GLfloat)a.y; - vertexD[n].s = (GLfloat)0; - vertexD[n].t = (GLfloat)0; - vertexD[n].a = (GLfloat)alpha; - n++; - } - - vertexD[n].x = (GLfloat)a.x; - vertexD[n].y = (GLfloat)a.y; - vertexD[n].s = (GLfloat)0; - vertexD[n].t = (GLfloat)0; - vertexD[n].a = (GLfloat)alpha; - n++; - - vertexD[n].x = (GLfloat)b.x; - vertexD[n].y = (GLfloat)b.y; - vertexD[n].s = (GLfloat)1; - vertexD[n].t = (GLfloat)0; - vertexD[n].a = (GLfloat)alpha; - n++; - - vertexD[n].x = (GLfloat)c.x; - vertexD[n].y = (GLfloat)c.y; - vertexD[n].s = (GLfloat)0; - vertexD[n].t = (GLfloat)1; - vertexD[n].a = (GLfloat)alpha; - n++; - - vertexD[n].x = (GLfloat)d.x; - vertexD[n].y = (GLfloat)d.y; - vertexD[n].s = (GLfloat)1; - vertexD[n].t = (GLfloat)1; - vertexD[n].a = (GLfloat)alpha; - n++; - - if (i != (state.count - 1)) - { - vertexD[n].x = (GLfloat)d.x; - vertexD[n].y = (GLfloat)d.y; - vertexD[n].s = (GLfloat)1; - vertexD[n].t = (GLfloat)1; - vertexD[n].a = (GLfloat)alpha; - n++; - } - } - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(vertexData), &vertexD[0].x); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_TRUE, sizeof(vertexData), &vertexD[0].s); - glEnableVertexAttribArray(1); - glVertexAttribPointer(2, 1, GL_FLOAT, GL_TRUE, sizeof(vertexData), &vertexD[0].a); - glEnableVertexAttribArray(2); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, n); - - free(vertexD); - TGPaintHasGLError(); - - return dataBounds; -} - -+ (CGRect)renderPath:(TGPaintPath *)path renderState:(TGPaintRenderState *)renderState -{ - renderState.brushWeight = path.baseWeight; - renderState.brushDynamic = path.brush.dynamic; - renderState.spacing = path.brush.spacing; - renderState.alpha = path.brush.alpha; - renderState.angle = path.brush.angle; - renderState.scale = path.brush.scale; - - if (path.points.count == 1) - { - [self _paintStamp:path.points.lastObject state:renderState]; - } - else - { - NSArray *points = path.points; - [renderState prepare]; - - for (NSUInteger i = 0; i < points.count - 1; i++) - { - [self _paintFromPoint:points[i] toPoint:points[i + 1] state:renderState]; - } - } - - path.remainder = renderState.remainder; - path.pressureRemainder = renderState.pressureRemainder; - - return [self _drawWithState:renderState]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintShaderSet.h b/submodules/LegacyComponents/Sources/TGPaintShaderSet.h deleted file mode 100644 index 2d58ffd9c2..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintShaderSet.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface TGPaintShaderSet : NSObject - -+ (NSDictionary *)availableShaders; -+ (NSDictionary *)setup; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintShaderSet.m b/submodules/LegacyComponents/Sources/TGPaintShaderSet.m deleted file mode 100644 index be6e103daf..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintShaderSet.m +++ /dev/null @@ -1,124 +0,0 @@ -#import "TGPaintShaderSet.h" - -#import "TGPaintShader.h" -#import - -@implementation TGPaintShaderSet - -+ (NSDictionary *)availableShaders -{ - return @ - { - @"brush": @ - { - @"vertex": @"Paint_Brush", - @"fragment": @"Paint_Brush", - @"attributes": @[ @"inPosition", @"inTexcoord", @"alpha" ], - @"uniforms" : @[ @"mvpMatrix", @"texture" ] - }, - - @"brushLight": @ - { - @"vertex": @"Paint_Brush", - @"fragment": @"Paint_BrushLight", - @"attributes": @[ @"inPosition", @"inTexcoord", @"alpha" ], - @"uniforms" : @[ @"mvpMatrix", @"texture" ] - }, - - @"brushLightPreview": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_BrushLightPreview", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"mask", @"color" ] - }, - - @"blit": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_Blit", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture" ] - }, - - @"blitWithMaskLight": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_BlitWithMaskLight", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture", @"mask", @"color" ] - }, - - @"blitWithMask": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_BlitWithMask", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture", @"mask", @"color" ] - }, - - @"blitWithEraseMask": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_BlitWithEraseMask", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture", @"mask"] - }, - - @"compositeWithMask": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_CompositeWithMask", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture", @"mask", @"color" ] - }, - - @"compositeWithMaskLight": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_CompositeWithMaskLight", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture", @"mask", @"color" ] - }, - - @"compositeWithEraseMask": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_CompositeWithEraseMask", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture", @"mask" ] - }, - - @"nonPremultipliedBlit": @ - { - @"vertex": @"Paint_Blit", - @"fragment": @"Paint_NonPremultipliedBlit", - @"attributes": @[ @"inPosition", @"inTexcoord" ], - @"uniforms": @[ @"mvpMatrix", @"texture" ] - } - }; -} - -+ (NSDictionary *)setup -{ - NSDictionary *shaderSet = [self availableShaders]; - - NSMutableDictionary *shaders = [NSMutableDictionary dictionary]; - for (NSString *key in shaderSet.keyEnumerator) - { - NSDictionary *desc = shaderSet[key]; - NSString *vertex = desc[@"vertex"]; - NSString *fragment = desc[@"fragment"]; - NSArray *attributes = desc[@"attributes"]; - NSArray *uniforms = desc[@"uniforms"]; - - TGPaintShader *shader = [[TGPaintShader alloc] initWithVertexShader:vertex fragmentShader:fragment attributes:attributes uniforms:uniforms]; - shaders[key] = shader; - } - - TGPaintHasGLError(); - - return shaders; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintSlice.h b/submodules/LegacyComponents/Sources/TGPaintSlice.h deleted file mode 100644 index b63c71018e..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintSlice.h +++ /dev/null @@ -1,15 +0,0 @@ -#import -#import - -@class TGPainting; - -@interface TGPaintSlice : NSObject - -@property (nonatomic, readonly) CGRect bounds; -@property (nonatomic, readonly) NSData *data; - -- (instancetype)initWithData:(NSData *)data bounds:(CGRect)bounds; - -- (instancetype)swappedSliceForPainting:(TGPainting *)painting; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintSlice.m b/submodules/LegacyComponents/Sources/TGPaintSlice.m deleted file mode 100644 index 2bcc290dcc..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintSlice.m +++ /dev/null @@ -1,78 +0,0 @@ -#import "TGPaintSlice.h" - -#import - -#import "TGPainting.h" -#import - -@interface TGPaintSlice () -{ - NSData *_data; - NSString *_fileName; -} -@end - -@implementation TGPaintSlice - -- (instancetype)initWithData:(NSData *)data bounds:(CGRect)bounds -{ - self = [super init]; - if (self != nil) - { - _bounds = bounds; - _data = data; - _fileName = [self _generatefileName]; - - [[TGPaintSlice queue] dispatch:^ - { - [TGPaintGZipDeflate(_data) writeToFile:_fileName atomically:true]; - [[SQueue mainQueue] dispatch:^ - { - _data = nil; - }]; - }]; - } - return self; -} - -- (void)dealloc -{ - if (_fileName != nil) - [[NSFileManager defaultManager] removeItemAtPath:_fileName error:NULL]; -} - -- (instancetype)swappedSliceForPainting:(TGPainting *)painting -{ - NSData *paintingData = nil; - [painting imageDataForRect:self.bounds resultPaintingData:&paintingData]; - return [[TGPaintSlice alloc] initWithData:paintingData bounds:self.bounds]; -} - -- (NSData *)data -{ - if (_data != nil) - return _data; - else if (_fileName != nil) - return TGPaintGZipInflate([[NSData alloc] initWithContentsOfFile:_fileName]); - else - return nil; -} - -- (NSString *)_generatefileName -{ - static uint32_t identifier = 0; - return [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%u.slice", identifier++]]; -} - -+ (SQueue *)queue -{ - static dispatch_once_t onceToken; - static SQueue *queue; - dispatch_once(&onceToken, ^ - { - queue = [SQueue wrapConcurrentNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)]; - }); - return queue; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintState.h b/submodules/LegacyComponents/Sources/TGPaintState.h deleted file mode 100644 index 1df427cb0b..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintState.h +++ /dev/null @@ -1,13 +0,0 @@ -#import -#import - -@class TGPaintBrush; - -@interface TGPaintState : NSObject - -@property (nonatomic, strong) UIColor *color; -@property (nonatomic, assign, getter=isEraser) bool eraser; -@property (nonatomic, assign) CGFloat weight; -@property (nonatomic, strong) TGPaintBrush *brush; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintState.m b/submodules/LegacyComponents/Sources/TGPaintState.m deleted file mode 100644 index 74a129c6be..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintState.m +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGPaintState.h" - -@implementation TGPaintState - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintSwatch.h b/submodules/LegacyComponents/Sources/TGPaintSwatch.h deleted file mode 100644 index c98faa1d98..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintSwatch.h +++ /dev/null @@ -1,12 +0,0 @@ -#import -#import - -@interface TGPaintSwatch : NSObject - -@property (nonatomic, readonly) UIColor *color; -@property (nonatomic, readonly) CGFloat colorLocation; -@property (nonatomic, readonly) CGFloat brushWeight; - -+ (instancetype)swatchWithColor:(UIColor *)color colorLocation:(CGFloat)colorLocation brushWeight:(CGFloat)brushWeight; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintSwatch.m b/submodules/LegacyComponents/Sources/TGPaintSwatch.m deleted file mode 100644 index 3cb8fb3e4b..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintSwatch.m +++ /dev/null @@ -1,27 +0,0 @@ -#import "TGPaintSwatch.h" - -@implementation TGPaintSwatch - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return true; - - if (!object || ![object isKindOfClass:[self class]]) - return false; - - TGPaintSwatch *swatch = (TGPaintSwatch *)object; - return [swatch.color isEqual:self.color] && fabs(swatch.colorLocation - self.colorLocation) < FLT_EPSILON && fabs(swatch.brushWeight - self.brushWeight) < FLT_EPSILON; -} - -+ (instancetype)swatchWithColor:(UIColor *)color colorLocation:(CGFloat)colorLocation brushWeight:(CGFloat)brushWeight -{ - TGPaintSwatch *swatch = [[TGPaintSwatch alloc] init]; - swatch->_color = color; - swatch->_colorLocation = colorLocation; - swatch->_brushWeight = brushWeight; - - return swatch; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintTexture.h b/submodules/LegacyComponents/Sources/TGPaintTexture.h deleted file mode 100644 index b26ef2d70e..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintTexture.h +++ /dev/null @@ -1,14 +0,0 @@ -#import -#import -#import - -@interface TGPaintTexture : NSObject - -@property (nonatomic, readonly) GLuint textureName; - -+ (instancetype)textureWithImage:(UIImage *)image forceRGB:(bool)forceRGB; - -- (instancetype)initWithCGImage:(CGImageRef)imageRef forceRGB:(bool)forceRGB; -- (void)cleanResources; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintTexture.m b/submodules/LegacyComponents/Sources/TGPaintTexture.m deleted file mode 100644 index 4265332f1e..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintTexture.m +++ /dev/null @@ -1,110 +0,0 @@ -#import "TGPaintTexture.h" - -#import - -@interface TGPaintTexture () -{ - GLuint _textureName; - - GLubyte *_data; - GLsizei _size; - GLuint _width; - GLuint _height; - GLenum _type; - GLenum _format; - GLuint _rowByteSize; - GLuint _unpackAlign; -} -@end - -@implementation TGPaintTexture - -+ (instancetype)textureWithImage:(UIImage *)image forceRGB:(bool)forceRGB -{ - return [[TGPaintTexture alloc] initWithCGImage:image.CGImage forceRGB:forceRGB]; -} - -- (instancetype)initWithCGImage:(CGImageRef)imageRef forceRGB:(bool)forceRGB -{ - self = [super init]; - if (self != nil) - { - [self _loadTextureFromCGImage:imageRef forceRGB:forceRGB]; - } - return self; -} - -- (void)dealloc -{ - if (_data != NULL) - free(_data); - - TGPaintHasGLError(); -} - -- (void)cleanResources -{ - if (_textureName == 0) - return; - - glDeleteTextures(1, &_textureName); - _textureName = 0; -} - -- (void)_loadTextureFromCGImage:(CGImageRef)image forceRGB:(bool)forceRGB -{ - bool isAlpha = forceRGB ? false : CGImageGetBitsPerPixel(image) == 8; - - _width = (GLuint) CGImageGetWidth(image); - _height = (GLuint) CGImageGetHeight(image); - _unpackAlign = isAlpha ? 1 : 4; - _rowByteSize = _width * _unpackAlign; - _data = malloc(_height * _rowByteSize); - _type = GL_UNSIGNED_BYTE; - _format = isAlpha ? GL_ALPHA : GL_RGBA; - - CGColorSpaceRef colorSpaceRef = isAlpha ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate(_data, _width, _height, 8, _rowByteSize, colorSpaceRef, (isAlpha ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast)); - CGContextSetBlendMode(context, kCGBlendModeCopy); - CGContextDrawImage(context, CGRectMake(0.0, 0.0, _width, _height), image); - CGContextRelease(context); - - CGColorSpaceRelease(colorSpaceRef); -} - -static bool isPOT(int x) -{ - return (x & (x - 1)) == 0; -} - -- (GLuint)textureName -{ - if (_textureName == 0) - { - TGPaintHasGLError(); - - glGenTextures(1, &_textureName); - glBindTexture(GL_TEXTURE_2D, _textureName); - - bool mipMappable = isPOT(_width) && isPOT(_height); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipMappable ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); - - glPixelStorei(GL_UNPACK_ALIGNMENT, _unpackAlign); - - glTexImage2D(GL_TEXTURE_2D, 0, _format, _width, _height, 0, _format, _type, _data); - TGPaintHasGLError(); - - if (mipMappable) - { - glGenerateMipmap(GL_TEXTURE_2D); - TGPaintHasGLError(); - } - } - - return _textureName; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintUndoManager.m b/submodules/LegacyComponents/Sources/TGPaintUndoManager.m deleted file mode 100644 index 7fd2a1beb3..0000000000 --- a/submodules/LegacyComponents/Sources/TGPaintUndoManager.m +++ /dev/null @@ -1,158 +0,0 @@ -#import "TGPaintUndoManager.h" - -#import "LegacyComponentsInternal.h" - -#import - -@interface TGPaintUndoOperation : NSObject - -@property (nonatomic, readonly) NSInteger uuid; -@property (nonatomic, readonly) void (^block)(TGPaintUndoManager *); - -- (void)performWithManager:(TGPaintUndoManager *)manager; - -+ (instancetype)operationWithUUID:(NSInteger)uuid block:(void (^)(TGPaintUndoManager *manager))block; - -@end - -@interface TGPaintUndoManager () -{ - SQueue *_queue; - NSMutableArray *_operations; - NSMutableDictionary *_uuidToOperationMap; -} -@end - -@implementation TGPaintUndoManager - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - _queue = [[SQueue alloc] init]; - _operations = [[NSMutableArray alloc] init]; - _uuidToOperationMap = [[NSMutableDictionary alloc] init]; - } - return self; -} - -- (id)copyWithZone:(NSZone *)__unused zone -{ - TGPaintUndoManager *undoManager = [[TGPaintUndoManager alloc] init]; - undoManager->_operations = [[NSMutableArray alloc] initWithArray:_operations copyItems:true]; - undoManager->_uuidToOperationMap = [[NSMutableDictionary alloc] initWithDictionary:_uuidToOperationMap copyItems:true]; - return undoManager; -} - -- (bool)canUndo -{ - return _operations.count > 0; -} - -- (void)undo -{ - [_queue dispatch:^ - { - if (_operations.count == 0) - return; - - NSNumber *key = _operations.lastObject; - TGPaintUndoOperation *operation = _uuidToOperationMap[key]; - [_uuidToOperationMap removeObjectForKey:key]; - [_operations removeLastObject]; - - TGDispatchOnMainThread(^ - { - [operation performWithManager:self]; - - if (self.historyChanged != nil) - self.historyChanged(); - }); - }]; -} - -- (void)registerUndoWithUUID:(NSInteger)uuid block:(void (^)(TGPainting *, TGPhotoEntitiesContainerView *, NSInteger))block -{ - [_queue dispatch:^ - { - TGPaintUndoOperation *operation = [TGPaintUndoOperation operationWithUUID:uuid block:^(TGPaintUndoManager *manager) - { - [manager _performBlock:block uuid:uuid]; - }]; - - NSNumber *key = @(uuid); - _uuidToOperationMap[key] = operation; - [_operations addObject:key]; - - [self _notifyOfHistoryChanges]; - }]; -} - -- (void)unregisterUndoWithUUID:(NSInteger)uuid -{ - [_queue dispatch:^ - { - NSNumber *key = @(uuid); - [_uuidToOperationMap removeObjectForKey:key]; - [_operations removeObject:key]; - - [self _notifyOfHistoryChanges]; - }]; -} - -- (void)_performBlock:(void (^)(TGPainting *, TGPhotoEntitiesContainerView *, NSInteger))block uuid:(NSInteger)uuid -{ - block(self.painting, self.entitiesContainer, uuid); -} - -- (void)reset -{ - [_queue dispatch:^ - { - [_operations removeAllObjects]; - [_uuidToOperationMap removeAllObjects]; - - [self _notifyOfHistoryChanges]; - }]; -} - -- (void)_notifyOfHistoryChanges -{ - TGDispatchOnMainThread(^ - { - if (self.historyChanged != nil) - self.historyChanged(); - }); -} - -@end - - -@implementation TGPaintUndoOperation - -- (id)copyWithZone:(NSZone *)__unused zone -{ - TGPaintUndoOperation *operation = [[TGPaintUndoOperation alloc] init]; - operation->_uuid = _uuid; - operation->_block = [_block copy]; - return operation; -} - -- (void)performWithManager:(TGPaintUndoManager *)manager -{ - self.block(manager); -} - -+ (instancetype)operationWithUUID:(NSInteger)uuid block:(void (^)(TGPaintUndoManager *manager))block -{ - if (uuid == 0 || block == nil) - return nil; - - TGPaintUndoOperation *operation = [[TGPaintUndoOperation alloc] init]; - operation->_uuid = uuid; - operation->_block = [block copy]; - return operation; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPainting.h b/submodules/LegacyComponents/Sources/TGPainting.h deleted file mode 100644 index b2834dc781..0000000000 --- a/submodules/LegacyComponents/Sources/TGPainting.h +++ /dev/null @@ -1,50 +0,0 @@ -#import -#import -#import -#import -#import - -@class TGPaintBrush; -@class TGPaintShader; -@class TGPaintPath; -@class TGPaintUndoManager; - -@interface TGPainting : NSObject - -@property (nonatomic, readonly) EAGLContext *context; -@property (nonatomic, readonly) GLuint textureName; - -@property (nonatomic, readonly) bool isEmpty; - -@property (nonatomic, readonly) CGSize size; -@property (nonatomic, readonly) CGRect bounds; - -@property (nonatomic, strong) TGPaintBrush *brush; -@property (nonatomic, strong) TGPaintPath *activePath; - -@property (nonatomic, copy) void (^contentChanged)(CGRect rect); -@property (nonatomic, copy) void (^strokeCommited)(void); - -- (instancetype)initWithSize:(CGSize)size undoManager:(TGPaintUndoManager *)undoManager imageData:(NSData *)imageData; - -- (void)performSynchronouslyInContext:(void (^)(void))block; -- (void)performAsynchronouslyInContext:(void (^)(void))block; - -- (void)paintStroke:(TGPaintPath *)path clearBuffer:(bool)clearBuffer completion:(void (^)(void))completion; -- (void)commitStrokeWithColor:(UIColor *)color erase:(bool)erase; - -- (void)renderWithProjection:(GLfloat *)projection; -- (NSData *)imageDataForRect:(CGRect)rect resultPaintingData:(NSData **)resultPaintingData; - -- (UIImage *)imageWithSize:(CGSize)size andData:(NSData *__autoreleasing *)outData; - -- (TGPaintShader *)shaderForKey:(NSString *)key; - -- (void)clear; - -- (GLuint)_quad; -- (GLfloat *)_projection; - -- (dispatch_queue_t)_queue; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPainting.m b/submodules/LegacyComponents/Sources/TGPainting.m deleted file mode 100644 index 3eeb728aaf..0000000000 --- a/submodules/LegacyComponents/Sources/TGPainting.m +++ /dev/null @@ -1,723 +0,0 @@ -#import "TGPainting.h" - -#import "LegacyComponentsInternal.h" - -#import -#import -#import -#import "matrix.h" - -#import "TGPaintBrush.h" -#import "TGPaintPath.h" -#import "TGPaintRender.h" -#import "TGPaintSlice.h" -#import "TGPaintShader.h" -#import "TGPaintShaderSet.h" -#import "TGPaintTexture.h" -#import -#import - -@interface TGPainting () -{ - EAGLContext *_context; - NSDictionary *_shaders; - - NSData *_initialImageData; - - GLuint _textureName; - GLuint _quadVAO; - GLuint _quadVBO; - GLfloat _projection[16]; - - CGRect _activeStrokeBounds; - - GLuint _reusableFramebuffer; - GLuint _paintTextureName; - - TGPaintTexture *_brushTexture; - - TGPaintRenderState *_renderState; - NSInteger _suppressChangesCounter; - - SQueue *_queue; - - __weak TGPaintUndoManager *_undoManager; - NSUInteger _strokeCount; -} -@end - -@implementation TGPainting - -- (instancetype)initWithSize:(CGSize)size undoManager:(TGPaintUndoManager *)undoManager imageData:(NSData *)imageData -{ - self = [super init]; - if (self != nil) - { - _queue = [[SQueue alloc] init]; - _undoManager = undoManager; - - _initialImageData = imageData; - _renderState = [[TGPaintRenderState alloc] init]; - - if (_initialImageData.length > 0) - _strokeCount++; - - [self setSize:size]; - } - return self; -} - -- (void)dealloc -{ - if (_context == nil) - return; - - [self performSynchronouslyInContext:^{ - [EAGLContext setCurrentContext:_context]; - if (_paintTextureName != 0) - glDeleteTextures(1, &_paintTextureName); - - glDeleteBuffers(1, &_quadVBO); - glDeleteVertexArraysOES(1, &_quadVAO); - - if (_reusableFramebuffer != 0) - glDeleteFramebuffers(1, &_reusableFramebuffer); - - if (_textureName != 0) - glDeleteTextures(1, &_textureName); - - [_brushTexture cleanResources]; - - TGPaintHasGLError(); - [EAGLContext setCurrentContext:nil]; - }]; -} - -- (void)setSize:(CGSize)size -{ - _size = size; - mat4f_LoadOrtho(0, (GLint)size.width, 0, (GLint)size.height, -1.0f, 1.0f, _projection); -} - -- (EAGLContext *)context -{ - if (_context == nil) - { - _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - - if (_context != nil && [EAGLContext setCurrentContext:_context]) - { - glEnable(GL_BLEND); - glDisable(GL_DITHER); - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - } - [self _setupShaders]; - } - - return _context; -} - -- (bool)isEmpty -{ - return (_strokeCount == 0); -} - -- (CGRect)bounds -{ - return CGRectMake(0.0f, 0.0f, self.size.width, self.size.height); -} - -#pragma mark - - -- (void)beginSuppressingChanges -{ - _suppressChangesCounter++; -} - -- (void)endSuppressingChanges -{ - _suppressChangesCounter--; -} - -- (bool)isSuppressingChanges -{ - return _suppressChangesCounter > 0; -} - -#pragma mark - - -- (void)performSynchronouslyInContext:(void (^)(void))block -{ - [_queue dispatch:^ - { - [EAGLContext setCurrentContext:self.context]; - block(); - } synchronous:true]; -} - -- (void)performAsynchronouslyInContext:(void (^)(void))block -{ - [_queue dispatch:^ - { - [EAGLContext setCurrentContext:self.context]; - block(); - }]; -} - -- (void)paintStroke:(TGPaintPath *)path clearBuffer:(bool)clearBuffer completion:(void (^)(void))completion -{ - [self performAsynchronouslyInContext:^ - { - _activePath = path; - - CGRect bounds = CGRectZero; - glBindFramebuffer(GL_FRAMEBUFFER, [self _reusableFramebuffer]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, [self _paintTextureName], 0); - - GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status == GL_FRAMEBUFFER_COMPLETE) - { - glViewport(0, 0, (GLint)self.size.width, (GLint)self.size.height); - - if (clearBuffer) - { - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - } - - [self _setupBrush]; - bounds = [TGPaintRender renderPath:path renderState:_renderState]; - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - TGPaintHasGLError(); - - if (self.contentChanged != nil) - self.contentChanged(bounds); - - _activeStrokeBounds = TGPaintUnionRect(_activeStrokeBounds, bounds); - - if (completion != nil) - completion(); - }]; -} - -- (void)commitStrokeWithColor:(UIColor *)color erase:(bool)erase -{ - [self performAsynchronouslyInContext:^ - { - [self registerUndoInRect:_activeStrokeBounds]; - - [self beginSuppressingChanges]; - - [self updateWithBlock:^ - { - GLfloat proj[16]; - mat4f_LoadOrtho(0, (GLint)self.size.width, 0, (GLint)self.size.height, -1.0f, 1.0f, proj); - - TGPaintShader *shader = erase ? [self shaderForKey:@"compositeWithEraseMask"] : [self shaderForKey:@"compositeWithMask"]; - if (_brush.lightSaber) - shader = [self shaderForKey:@"compositeWithMaskLight"]; - glUseProgram(shader.program); - - glUniformMatrix4fv([shader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, proj); - glUniform1i([shader uniformForKey:@"texture"], 0); - glUniform1i([shader uniformForKey:@"mask"], 1); - if (!erase) - TGSetupColorUniform([shader uniformForKey:@"color"], color); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self.textureName); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, self._paintTextureName); - - glBlendFunc(GL_ONE, GL_ZERO); - - glBindVertexArrayOES([self _quad]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glBindVertexArrayOES(0); - - glBindTexture(GL_TEXTURE_2D, self.textureName); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } bounds:_activeStrokeBounds]; - - [self endSuppressingChanges]; - - [_renderState reset]; - - _activeStrokeBounds = CGRectZero; - - _activePath = nil; - - TGDispatchOnMainThread(^ - { - if (self.strokeCommited != nil) - self.strokeCommited(); - }); - }]; -} - -- (void)setBrush:(TGPaintBrush *)brush -{ - _brush = brush; - [self performAsynchronouslyInContext:^{ - if (_brushTexture != nil) - { -// [_brushTexture cleanResources]; - _brushTexture = nil; - } - }]; -} - -- (void)_setupBrush -{ - TGPaintShader *shader = [self shaderForKey:_brush.lightSaber ? @"brushLight" : @"brush"]; - glUseProgram(shader.program); - - glActiveTexture(GL_TEXTURE0); - - if (_brushTexture == nil) - _brushTexture = [[TGPaintTexture alloc] initWithCGImage:_brush.stampRef forceRGB:false]; - - glBindTexture(GL_TEXTURE_2D, _brushTexture.textureName); - - glUniformMatrix4fv([shader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, _projection); - glUniform1i([shader uniformForKey:@"texture"], 0); - TGPaintHasGLError(); -} - -#pragma mark - - -- (void)updateWithBlock:(void (^)(void))updateBlock bounds:(CGRect)bounds -{ - glBindFramebuffer(GL_FRAMEBUFFER, [self _reusableFramebuffer]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self.textureName, 0); - - GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status == GL_FRAMEBUFFER_COMPLETE) - { - glViewport(0, 0, (GLint)self.size.width, (GLint)self.size.height); - - TGPaintHasGLError(); - updateBlock(); - TGPaintHasGLError(); - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - if (![self isSuppressingChanges]) - { - if (self.contentChanged != nil) - self.contentChanged(bounds); - } -} - -- (void)clear -{ - _strokeCount = 0; - - [self performAsynchronouslyInContext:^ - { - [self updateWithBlock:^ - { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - } bounds:[self bounds]]; - }]; -} - -- (dispatch_queue_t)_queue -{ - return _queue._dispatch_queue; -} - -#pragma mark - - -- (void)renderWithProjection:(GLfloat *)projection -{ - if (_activePath != nil) - { - if (_activePath.action == TGPaintActionErase) - [self _renderWithProjection:projection mask:[self _paintTextureName] color:nil erase:true]; - else - [self _renderWithProjection:projection mask:[self _paintTextureName] color:_activePath.color erase:false]; - } - else - { - [self _renderWithProjection:projection]; - } -} - -- (void)_renderWithProjection:(GLfloat *)projection mask:(GLint)mask color:(UIColor *)color erase:(bool)erase -{ - TGPaintShader *shader = erase ? [self shaderForKey:@"blitWithEraseMask"] : [self shaderForKey:@"blitWithMask"]; - if (_brush.lightSaber) - shader = [self shaderForKey:@"blitWithMaskLight"]; - - glUseProgram(shader.program); - - glUniformMatrix4fv([shader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, projection); - glUniform1i([shader uniformForKey:@"texture"], 0); - glUniform1i([shader uniformForKey:@"mask"], 1); - if (!erase) - TGSetupColorUniform([shader uniformForKey:@"color"], color); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self.textureName); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mask); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArrayOES([self _quad]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glBindVertexArrayOES(0); -} - -- (void)_renderWithProjection:(GLfloat *)projection -{ - TGPaintShader *shader = [self shaderForKey:@"blit"]; - glUseProgram(shader.program); - - glUniformMatrix4fv([shader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, projection); - glUniform1i([shader uniformForKey:@"texture"], 0); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self.textureName); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArrayOES([self _quad]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - glBindVertexArrayOES(0); -} - -#pragma mark - - -- (NSData *)imageDataForRect:(CGRect)rect resultPaintingData:(NSData **)resultPaintingData -{ - [EAGLContext setCurrentContext:self.context]; - - TGPaintHasGLError(); - - GLint minX = (GLint) CGRectGetMinX(rect); - GLint minY = (GLint) CGRectGetMinY(rect); - GLint width = (GLint) CGRectGetWidth(rect); - GLint height = (GLint) CGRectGetHeight(rect); - - GLuint framebuffer; - glGenFramebuffers(1, &framebuffer); - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - - GLuint colorRenderbuffer; - glGenRenderbuffers(1, &colorRenderbuffer); - glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height); - - GLuint textureName; - GLenum format = GL_RGBA; - GLenum type = GL_UNSIGNED_BYTE; - - glGenTextures(1, &textureName); - glBindTexture(GL_TEXTURE_2D, textureName); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glBindTexture(GL_TEXTURE_2D, textureName); - - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); - - GLint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - TGLegacyLog(@"ERROR: imageAndData: - Incomplete Framebuffer!"); - TGPaintHasGLError(); - return nil; - } - - glViewport(0, 0, (GLint)self.size.width, (GLint)self.size.height); - - TGPaintShader *blitShader = [self shaderForKey:@"nonPremultipliedBlit"]; - glUseProgram(blitShader.program); - - GLfloat proj[16], effectiveProj[16],final[16]; - mat4f_LoadOrtho(0, (GLint)self.size.width, 0, (GLint)self.size.height, -1.0f, 1.0f, proj); - - CGAffineTransform translate = CGAffineTransformMakeTranslation(-minX, -minY); - mat4f_LoadCGAffineTransform(effectiveProj, translate); - mat4f_MultiplyMat4f(proj, effectiveProj, final); - - glUniformMatrix4fv([blitShader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, final); - glUniform1i([blitShader uniformForKey:@"texture"], (GLuint)0); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self.textureName); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArrayOES([self _quad]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArrayOES(0); - - NSUInteger length = width * 4 * height; - GLubyte *pixels = malloc(sizeof(GLubyte) * length); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - NSData *paintingResult = [NSData dataWithBytes:pixels length:length]; - - if (resultPaintingData != NULL) - *resultPaintingData = paintingResult; - - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer); - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - TGLegacyLog(@"ERROR: imageAndData: - Incomplete Framebuffer!"); - TGPaintHasGLError(); - return nil; - } - - blitShader = [self shaderForKey:@"blit"]; - glUseProgram(blitShader.program); - - glUniformMatrix4fv([blitShader uniformForKey:@"mvpMatrix"], 1, GL_FALSE, final); - glUniform1i([blitShader uniformForKey:@"texture"], (GLuint)0); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textureName); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - glBindVertexArrayOES([self _quad]); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - glBindVertexArrayOES(0); - - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - NSData *result = [NSData dataWithBytes:pixels length:length]; - free(pixels); - - glDeleteFramebuffers(1, &framebuffer); - glDeleteTextures(1, &textureName); - glDeleteRenderbuffers(1, &colorRenderbuffer); - - TGPaintHasGLError(); - return result; -} - -- (UIImage *)imageWithSize:(CGSize)size andData:(NSData *__autoreleasing *)outData -{ - NSData *paintingData = nil; - NSData *imageData = [self imageDataForRect:self.bounds resultPaintingData:&paintingData]; - UIImage *image = [self imageForData:imageData size:self.size outputSize:size]; - - if (outData != NULL) - *outData = paintingData; - - return image; -} - -- (UIImage *)imageForData:(NSData *)data size:(CGSize)size outputSize:(CGSize)outputSize -{ - size_t width = (size_t)size.width; - size_t height = (size_t)size.height; - - CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate((void *)data.bytes, width, height, 8, width * 4, colorSpaceRef, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast); - - CGImageRef imageRef = CGBitmapContextCreateImage(context); - CGContextRelease(context); - CGColorSpaceRelease(colorSpaceRef); - - UIGraphicsBeginImageContext(outputSize); - [[UIImage imageWithCGImage:imageRef] drawInRect:CGRectMake(0.0f, 0.0f, outputSize.width, outputSize.height)]; - CGImageRelease(imageRef); - - UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return result; -} - -#pragma mark - - -- (void)registerUndoInRect:(CGRect)rect -{ - rect = CGRectIntersection(rect, self.bounds); - - NSData *paintingData = nil; - [self imageDataForRect:rect resultPaintingData:&paintingData]; - - TGPaintSlice *slice = [[TGPaintSlice alloc] initWithData:paintingData bounds:rect]; - NSInteger uuid; - arc4random_buf(&uuid, sizeof(NSInteger)); - [_undoManager registerUndoWithUUID:uuid block:^(TGPainting *painting, __unused TGPhotoEntitiesContainerView *entitiesContainer, __unused NSInteger uuid) - { - [painting restoreSlice:slice redo:false]; - }]; - - _strokeCount++; -} - -- (void)restoreSlice:(TGPaintSlice *)slice redo:(bool)redo -{ - [self performAsynchronouslyInContext:^ - { - if (!redo) - _strokeCount--; - - NSData *data = slice.data; - - glBindTexture(GL_TEXTURE_2D, self.textureName); - glTexSubImage2D(GL_TEXTURE_2D, 0, (GLint)slice.bounds.origin.x, (GLint)slice.bounds.origin.y, (GLint)slice.bounds.size.width, (GLint)slice.bounds.size.height, GL_RGBA, GL_UNSIGNED_BYTE, data.bytes); - - if (![self isSuppressingChanges] && self.contentChanged != nil) - self.contentChanged(slice.bounds); - }]; -} - -#pragma mark - - -- (GLuint)textureName -{ - if (_textureName == 0) - { - _textureName = [self _generateTextureWithPixels:(GLubyte *)_initialImageData.bytes]; - _initialImageData = nil; - } - - return _textureName; -} - -- (GLuint)_paintTextureName -{ - if (_paintTextureName == 0) - _paintTextureName = [self _generateTextureWithPixels:nil]; - - return _paintTextureName; -} - -- (GLuint)_reusableFramebuffer -{ - if (_reusableFramebuffer == 0) - glGenFramebuffers(1, &_reusableFramebuffer); - - return _reusableFramebuffer; -} - -- (GLuint)_quad -{ - if (_quadVAO == 0) - { - [EAGLContext setCurrentContext:self.context]; - CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height); - - CGPoint corners[4]; - corners[0] = rect.origin; - corners[1] = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect)); - corners[2] = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)); - corners[3] = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect)); - - const GLfloat vertices[] = - { - (GLfloat)corners[0].x, (GLfloat)corners[0].y, 0.0, 0.0, - (GLfloat)corners[1].x, (GLfloat)corners[1].y, 1.0, 0.0, - (GLfloat)corners[3].x, (GLfloat)corners[3].y, 0.0, 1.0, - (GLfloat)corners[2].x, (GLfloat)corners[2].y, 1.0, 1.0, - }; - - glGenVertexArraysOES(1, &_quadVAO); - glBindVertexArrayOES(_quadVAO); - - glGenBuffers(1, &_quadVBO); - glBindBuffer(GL_ARRAY_BUFFER, _quadVBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 16, vertices, GL_STATIC_DRAW); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)0); - glEnableVertexAttribArray(0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 4, (void*)8); - glEnableVertexAttribArray(1); - - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArrayOES(0); - } - - return _quadVAO; -} - -- (GLfloat *)_projection -{ - return _projection; -} - -- (GLuint)_generateTextureWithPixels:(GLubyte *)pixels -{ - [EAGLContext setCurrentContext:self.context]; - TGPaintHasGLError(); - - GLuint textureName; - glGenTextures(1, &textureName); - glBindTexture(GL_TEXTURE_2D, textureName); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - GLuint width = (GLuint)self.size.width; - GLuint height = (GLuint)self.size.height; - GLenum format = GL_RGBA; - GLenum type = GL_UNSIGNED_BYTE; - NSUInteger bytesPerPixel = 4; - - if (pixels == NULL) - { - pixels = calloc((size_t) (self.size.width * bytesPerPixel * self.size.height), sizeof(GLubyte)); - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, pixels); - free(pixels); - } - else - { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, pixels); - } - - TGPaintHasGLError(); - return textureName; -} - -#pragma mark - Shaders - -- (void)_setupShaders -{ - if (_shaders != nil) - return; - - _shaders = [TGPaintShaderSet setup]; -} - -- (TGPaintShader *)shaderForKey:(NSString *)key -{ - return _shaders[key]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPaintingData.m b/submodules/LegacyComponents/Sources/TGPaintingData.m index 8b3800a901..59a89746c5 100644 --- a/submodules/LegacyComponents/Sources/TGPaintingData.m +++ b/submodules/LegacyComponents/Sources/TGPaintingData.m @@ -6,7 +6,6 @@ #import "TGPhotoPaintStickerEntity.h" #import "TGMediaEditingContext.h" -#import "TGPaintUndoManager.h" @interface TGPaintingData () { diff --git a/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.h b/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.h deleted file mode 100644 index 1db7d52971..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.h +++ /dev/null @@ -1,15 +0,0 @@ -#import -#import "TGPhotoPaintSettingsView.h" - -@class TGPaintBrush; -@class TGPaintBrushPreview; - -@interface TGPhotoBrushSettingsView : UIView - -@property (nonatomic, copy) void (^brushChanged)(TGPaintBrush *brush); - -@property (nonatomic, strong) TGPaintBrush *brush; - -- (instancetype)initWithBrushes:(NSArray *)brushes preview:(TGPaintBrushPreview *)preview; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m b/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m deleted file mode 100644 index 144cf5b68a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoBrushSettingsView.m +++ /dev/null @@ -1,205 +0,0 @@ -#import "TGPhotoBrushSettingsView.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -#import "TGPhotoEditorSliderView.h" - -#import - -#import "TGPaintBrush.h" -#import "TGPaintBrushPreview.h" - -const CGFloat TGPhotoBrushSettingsViewMargin = 10.0f; -const CGFloat TGPhotoBrushSettingsItemHeight = 44.0f; - -@interface TGPhotoBrushSettingsView () -{ - NSArray *_brushes; - - UIView *_wrapperView; - UIView *_contentView; - UIVisualEffectView *_effectView; - - NSArray *_brushViews; - NSArray *_brushIconViews; - NSArray *_brushSeparatorViews; -} -@end - -@implementation TGPhotoBrushSettingsView - -@synthesize interfaceOrientation = _interfaceOrientation; - -- (instancetype)initWithBrushes:(NSArray *)brushes preview:(TGPaintBrushPreview *)preview -{ - self = [super initWithFrame:CGRectZero]; - if (self != nil) - { - _brushes = brushes; - - _interfaceOrientation = UIInterfaceOrientationPortrait; - - _wrapperView = [[UIView alloc] init]; - _wrapperView.clipsToBounds = true; - _wrapperView.layer.cornerRadius = 12.0; - [self addSubview:_wrapperView]; - - _effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; - _effectView.alpha = 0.0f; - _effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [_wrapperView addSubview:_effectView]; - - _contentView = [[UIView alloc] init]; - _contentView.alpha = 0.0f; - _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [_wrapperView addSubview:_contentView]; - - UIFont *font = [UIFont systemFontOfSize:17]; - - NSMutableArray *brushViews = [[NSMutableArray alloc] init]; - NSMutableArray *brushIconViews = [[NSMutableArray alloc] init]; - NSMutableArray *separatorViews = [[NSMutableArray alloc] init]; - [brushes enumerateObjectsUsingBlock:^(__unused TGPaintBrush *brush, NSUInteger index, __unused BOOL *stop) - { - NSString *title; - UIImage *icon; - switch (index) { - case 0: - title = TGLocalized(@"Paint.Pen"); - icon = [UIImage imageNamed:@"Editor/BrushPen"]; - break; - case 1: - title = TGLocalized(@"Paint.Marker"); - icon = [UIImage imageNamed:@"Editor/BrushMarker"]; - break; - case 2: - title = TGLocalized(@"Paint.Neon"); - icon = [UIImage imageNamed:@"Editor/BrushNeon"]; - break; - case 3: - title = TGLocalized(@"Paint.Arrow"); - icon = [UIImage imageNamed:@"Editor/BrushArrow"]; - break; - default: - break; - } - - TGModernButton *button = [[TGModernButton alloc] initWithFrame:CGRectMake(0, index * TGPhotoBrushSettingsItemHeight, 0, 0)]; - button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; - button.titleLabel.font = font; - button.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f); - button.tag = index; - [button setTitle:title forState:UIControlStateNormal]; - [button setTitleColor:[UIColor whiteColor]]; - [button addTarget:self action:@selector(brushButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; - [_contentView addSubview:button]; - [brushViews addObject:button]; - - UIImageView *iconView = [[UIImageView alloc] initWithImage:TGTintedImage(icon, [UIColor whiteColor])]; - [button addSubview:iconView]; - [brushIconViews addObject:iconView]; - - if (index != brushes.count - 1) - { - UIView *separatorView = [[UIView alloc] init]; - separatorView.backgroundColor = UIColorRGBA(0xffffff, 0.2); - [_contentView addSubview:separatorView]; - - [separatorViews addObject:separatorView]; - } - }]; - - _brushViews = brushViews; - _brushIconViews = brushIconViews; - _brushSeparatorViews = separatorViews; - } - return self; -} - -- (void)brushButtonPressed:(TGModernButton *)sender -{ - if (self.brushChanged != nil) - self.brushChanged(_brushes[sender.tag]); -} - -- (void)present -{ - [UIView animateWithDuration:0.25 animations:^ - { - _effectView.alpha = 1.0f; - _contentView.alpha = 1.0f; - } completion:^(__unused BOOL finished) - { - - }]; -} - -- (void)dismissWithCompletion:(void (^)(void))completion -{ - [UIView animateWithDuration:0.2 animations:^ - { - _effectView.alpha = 0.0f; - _contentView.alpha = 0.0f; - } completion:^(__unused BOOL finished) - { - if (completion != nil) - completion(); - }]; -} - -- (CGSize)sizeThatFits:(CGSize)__unused size -{ - return CGSizeMake(220, _brushViews.count * TGPhotoBrushSettingsItemHeight + TGPhotoBrushSettingsViewMargin * 2); -} - -- (void)setInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - _interfaceOrientation = interfaceOrientation; - - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - CGFloat arrowSize = 0.0f; - switch (self.interfaceOrientation) - { - case UIInterfaceOrientationLandscapeLeft: - { - _wrapperView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin - arrowSize, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2); - } - break; - - case UIInterfaceOrientationLandscapeRight: - { - _wrapperView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2); - } - break; - - default: - { - _wrapperView.frame = CGRectMake(TGPhotoBrushSettingsViewMargin, TGPhotoBrushSettingsViewMargin, self.frame.size.width - TGPhotoBrushSettingsViewMargin * 2, self.frame.size.height - TGPhotoBrushSettingsViewMargin * 2 + arrowSize); - } - break; - } - - CGFloat thickness = TGScreenPixel; - - [_brushViews enumerateObjectsUsingBlock:^(TGModernButton *view, NSUInteger index, __unused BOOL *stop) - { - view.frame = CGRectMake(0.0f, TGPhotoBrushSettingsItemHeight * index, _contentView.frame.size.width, TGPhotoBrushSettingsItemHeight); - }]; - - [_brushIconViews enumerateObjectsUsingBlock:^(UIImageView *view, NSUInteger index, __unused BOOL *stop) - { - view.frame = CGRectMake(_contentView.frame.size.width - 42.0f, (TGPhotoBrushSettingsItemHeight - view.frame.size.height) / 2.0, view.frame.size.width, view.frame.size.height); - }]; - - [_brushSeparatorViews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger index, __unused BOOL *stop) - { - view.frame = CGRectMake(0.0f, TGPhotoBrushSettingsItemHeight * (index + 1), _contentView.frame.size.width, thickness); - }]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoDrawingController.m b/submodules/LegacyComponents/Sources/TGPhotoDrawingController.m index a15469abf7..6fc399a37c 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoDrawingController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoDrawingController.m @@ -24,8 +24,7 @@ #import "PGPhotoEditor.h" #import "TGPhotoEditorPreviewView.h" -#import "TGPaintCanvas.h" -#import "TGPainting.h" +#import const CGFloat TGPhotoPaintTopPanelSize = 44.0f; const CGFloat TGPhotoPaintBottomPanelSize = 79.0f; @@ -61,8 +60,6 @@ const CGSize TGPhotoPaintingMaxSize = { 1920.0f, 1920.0f }; CGFloat _keyboardHeight; TGObserverProxy *_keyboardWillChangeFrameProxy; - TGPainting *_painting; - bool _skipEntitiesSetup; bool _entitiesReady; @@ -833,6 +830,7 @@ const CGSize TGPhotoPaintingMaxSize = { 1920.0f, 1920.0f }; CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size); CGRect previewFrame = CGRectMake((containerFrame.size.width - fittedSize.width) / 2, (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); + _drawingView.screenSize = fittedSize; CGFloat topInset = [self controllerStatusBarHeight] + 31.0; CGFloat visibleArea = self.view.frame.size.height - _keyboardHeight - topInset; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorController.m b/submodules/LegacyComponents/Sources/TGPhotoEditorController.m index a935e011b2..8d2382620e 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorController.m @@ -1932,58 +1932,63 @@ strongSelf.didFinishEditing(nil, nil, nil, false, ^{}); }; + if ([_currentTabController isKindOfClass:[TGPhotoDrawingController class]]) { + dismiss(); + return; + } + TGPaintingData *paintingData = nil; if ([_currentTabController isKindOfClass:[TGPhotoDrawingController class]]) paintingData = [(TGPhotoDrawingController *)_currentTabController paintingData]; PGPhotoEditorValues *editorValues = paintingData == nil ? [_photoEditor exportAdjustments] : [_photoEditor exportAdjustmentsWithPaintingData:paintingData]; -// if ((_initialAdjustments == nil && (![editorValues isDefaultValuesForAvatar:[self presentedForAvatarCreation]] || editorValues.cropOrientation != UIImageOrientationUp)) || (_initialAdjustments != nil && ![editorValues isEqual:_initialAdjustments])) -// { -// TGMenuSheetController *controller = [[TGMenuSheetController alloc] initWithContext:_context dark:false]; -// controller.dismissesByOutsideTap = true; -// controller.narrowInLandscape = true; -// __weak TGMenuSheetController *weakController = controller; -// -// NSArray *items = @ -// [ -// [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"PhotoEditor.DiscardChanges") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ -// { -// __strong TGMenuSheetController *strongController = weakController; -// if (strongController == nil) -// return; -// -// [strongController dismissAnimated:true manual:false completion:^ -// { -// dismiss(); -// }]; -// }], -// [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Common.Cancel") type:TGMenuSheetButtonTypeCancel fontSize:20.0 action:^ -// { -// __strong TGMenuSheetController *strongController = weakController; -// if (strongController != nil) -// [strongController dismissAnimated:true]; -// }] -// ]; -// -// [controller setItemViews:items]; -// controller.sourceRect = ^ -// { -// __strong TGPhotoEditorController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return CGRectZero; -// -// if (UIInterfaceOrientationIsPortrait(strongSelf.effectiveOrientation)) -// return [strongSelf.view convertRect:strongSelf->_portraitToolbarView.cancelButtonFrame fromView:strongSelf->_portraitToolbarView]; -// else -// return [strongSelf.view convertRect:strongSelf->_landscapeToolbarView.cancelButtonFrame fromView:strongSelf->_landscapeToolbarView]; -// }; -// [controller presentInViewController:self sourceView:self.view animated:true]; -// } -// else -// { + if ((_initialAdjustments == nil && (![editorValues isDefaultValuesForAvatar:[self presentedForAvatarCreation]] || editorValues.cropOrientation != UIImageOrientationUp)) || (_initialAdjustments != nil && ![editorValues isEqual:_initialAdjustments])) + { + TGMenuSheetController *controller = [[TGMenuSheetController alloc] initWithContext:_context dark:false]; + controller.dismissesByOutsideTap = true; + controller.narrowInLandscape = true; + __weak TGMenuSheetController *weakController = controller; + + NSArray *items = @ + [ + [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"PhotoEditor.DiscardChanges") type:TGMenuSheetButtonTypeDefault fontSize:20.0 action:^ + { + __strong TGMenuSheetController *strongController = weakController; + if (strongController == nil) + return; + + [strongController dismissAnimated:true manual:false completion:^ + { + dismiss(); + }]; + }], + [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Common.Cancel") type:TGMenuSheetButtonTypeCancel fontSize:20.0 action:^ + { + __strong TGMenuSheetController *strongController = weakController; + if (strongController != nil) + [strongController dismissAnimated:true]; + }] + ]; + + [controller setItemViews:items]; + controller.sourceRect = ^ + { + __strong TGPhotoEditorController *strongSelf = weakSelf; + if (strongSelf == nil) + return CGRectZero; + + if (UIInterfaceOrientationIsPortrait(strongSelf.effectiveOrientation)) + return [strongSelf.view convertRect:strongSelf->_portraitToolbarView.cancelButtonFrame fromView:strongSelf->_portraitToolbarView]; + else + return [strongSelf.view convertRect:strongSelf->_landscapeToolbarView.cancelButtonFrame fromView:strongSelf->_landscapeToolbarView]; + }; + [controller presentInViewController:self sourceView:self.view animated:true]; + } + else + { dismiss(); -// } + } } - (void)doneButtonPressed diff --git a/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.h b/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.h deleted file mode 100644 index 00e2f53e88..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.h +++ /dev/null @@ -1,38 +0,0 @@ -#import "TGPhotoEditorSparseView.h" -#import "TGPhotoPaintStickersContext.h" - -@class TGPaintingData; -@class TGPhotoPaintEntity; -@class TGPhotoPaintEntityView; - -@interface TGPhotoEntitiesContainerView : TGPhotoEditorSparseView - -@property (nonatomic, strong) id stickersContext; - -@property (nonatomic, readonly) NSUInteger entitiesCount; -@property (nonatomic, copy) void (^entitySelected)(TGPhotoPaintEntityView *); -@property (nonatomic, copy) void (^entityRemoved)(TGPhotoPaintEntityView *); - -- (void)updateVisibility:(bool)visible; -- (void)seekTo:(double)timestamp; -- (void)play; -- (void)pause; -- (void)resetToStart; - -- (UIColor *)colorAtPoint:(CGPoint)point; - -- (void)setupWithPaintingData:(TGPaintingData *)paintingData; -- (TGPhotoPaintEntityView *)createEntityViewWithEntity:(TGPhotoPaintEntity *)entity; - -- (TGPhotoPaintEntityView *)viewForUUID:(NSInteger)uuid; -- (void)removeViewWithUUID:(NSInteger)uuid; -- (void)removeAll; - -- (void)handlePinch:(UIPinchGestureRecognizer *)gestureRecognizer; -- (void)handleRotate:(UIRotationGestureRecognizer *)gestureRecognizer; - -- (UIImage *)imageInRect:(CGRect)rect background:(UIImage *)background still:(bool)still; - -- (bool)isTrackingAnyEntityView; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m b/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m deleted file mode 100644 index 07f3839f8e..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoEntitiesContainerView.m +++ /dev/null @@ -1,453 +0,0 @@ -#import "TGPhotoEntitiesContainerView.h" -#import "TGPhotoPaintEntityView.h" -#import "TGPhotoStickerEntityView.h" -#import "TGPhotoTextEntityView.h" -#import "TGPaintingData.h" - -#import - -@interface TGPhotoEntitiesContainerView () -{ - TGPhotoPaintEntityView *_currentView; - UITapGestureRecognizer *_tapGestureRecognizer; -} -@end - -@implementation TGPhotoEntitiesContainerView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; - _tapGestureRecognizer.delegate = self; - [self addGestureRecognizer:_tapGestureRecognizer]; - } - return self; -} - -- (void)updateVisibility:(bool)visible -{ - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { - [(TGPhotoStickerEntityView *)view updateVisibility:visible]; - } - } -} - -- (void)seekTo:(double)timestamp { - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { - [(TGPhotoStickerEntityView *)view seekTo:timestamp]; - } - } -} - -- (void)play { - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { - [(TGPhotoStickerEntityView *)view play]; - } - } -} - -- (void)pause { - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { - [(TGPhotoStickerEntityView *)view pause]; - } - } -} - - -- (void)resetToStart { - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { - [(TGPhotoStickerEntityView *)view resetToStart]; - } - } -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)__unused gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)__unused otherGestureRecognizer -{ - return false; -} - -- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer -{ - CGPoint point = [gestureRecognizer locationInView:self]; - - NSMutableArray *intersectedViews = [[NSMutableArray alloc] init]; - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view pointInside:[view convertPoint:point fromView:self] withEvent:nil]) - [intersectedViews addObject:view]; - } - - TGPhotoPaintEntityView *result = nil; - if (intersectedViews.count > 1) - { - __block TGPhotoPaintEntityView *subresult = nil; - [intersectedViews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TGPhotoPaintEntityView *view, __unused NSUInteger index, BOOL *stop) - { - if ([view precisePointInside:[view convertPoint:point fromView:self]]) - { - subresult = view; - *stop = true; - } - }]; - - result = subresult ?: intersectedViews.lastObject; - } - else if (intersectedViews.count == 1) - { - result = intersectedViews.firstObject; - } - - if (self.entitySelected != nil) - self.entitySelected(result); -} - -- (UIColor *)colorAtPoint:(CGPoint)point { - NSMutableArray *intersectedViews = [[NSMutableArray alloc] init]; - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view pointInside:[view convertPoint:point fromView:self] withEvent:nil]) - [intersectedViews addObject:view]; - } - - TGPhotoPaintEntityView *result = nil; - if (intersectedViews.count > 1) - { - __block TGPhotoPaintEntityView *subresult = nil; - [intersectedViews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TGPhotoPaintEntityView *view, __unused NSUInteger index, BOOL *stop) - { - if ([view precisePointInside:[view convertPoint:point fromView:self]]) - { - subresult = view; - *stop = true; - } - }]; - - result = subresult ?: intersectedViews.lastObject; - } - else if (intersectedViews.count == 1) - { - result = intersectedViews.firstObject; - } - - return [result colorAtPoint:[result convertPoint:point fromView:self]]; -} - -- (NSUInteger)entitiesCount -{ - return MAX(0, (NSInteger)self.subviews.count - 1); -} - -- (void)setupWithPaintingData:(TGPaintingData *)paintingData { - [self removeAll]; -// for (TGPhotoPaintEntity *entity in paintingData.entities) { -// UIView * entityView = [self createEntityViewWithEntity:entity]; -// [self addSubview:entityView]; -// } -} - -- (TGPhotoPaintEntityView *)createEntityViewWithEntity:(TGPhotoPaintEntity *)entity { - if ([entity isKindOfClass:[TGPhotoPaintStickerEntity class]]) - return [self _createStickerViewWithEntity:(TGPhotoPaintStickerEntity *)entity]; - else if ([entity isKindOfClass:[TGPhotoPaintTextEntity class]]) - return [self _createTextViewWithEntity:(TGPhotoPaintTextEntity *)entity]; - - return nil; -} - -- (TGPhotoStickerEntityView *)_createStickerViewWithEntity:(TGPhotoPaintStickerEntity *)entity -{ - TGPhotoStickerEntityView *stickerView = [[TGPhotoStickerEntityView alloc] initWithEntity:entity context:self.stickersContext]; - [self _commonEntityViewSetup:stickerView entity:entity]; - - return stickerView; -} - -- (TGPhotoTextEntityView *)_createTextViewWithEntity:(TGPhotoPaintTextEntity *)entity -{ - TGPhotoTextEntityView *textView = [[TGPhotoTextEntityView alloc] initWithEntity:entity]; - [textView sizeToFit]; - - [self _commonEntityViewSetup:textView entity:entity]; - - return textView; -} - -- (void)_commonEntityViewSetup:(TGPhotoPaintEntityView *)entityView entity:(TGPhotoPaintEntity *)entity -{ - entityView.transform = CGAffineTransformRotate(CGAffineTransformMakeScale(entity.scale, entity.scale), entity.angle); - entityView.center = entity.position; -} - -- (TGPhotoPaintEntityView *)viewForUUID:(NSInteger)uuid -{ - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if (view.entityUUID == uuid) - return view; - } - - return nil; -} - -- (void)removeViewWithUUID:(NSInteger)uuid -{ - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if (view.entityUUID == uuid) - { - [view removeFromSuperview]; - - if (self.entityRemoved != nil) - self.entityRemoved(view); - break; - } - } -} - -- (void)removeAll -{ - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - [view removeFromSuperview]; - } -} - -- (void)handlePinch:(UIPinchGestureRecognizer *)gestureRecognizer -{ - CGPoint location = [gestureRecognizer locationInView:self]; - - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateBegan: - { - if (_currentView != nil) - return; - - _currentView = [self viewForLocation:location]; - } - break; - - case UIGestureRecognizerStateChanged: - { - if (_currentView == nil) - return; - - CGFloat scale = gestureRecognizer.scale; - [_currentView scale:scale absolute:false]; - - [gestureRecognizer setScale:1.0f]; - } - break; - - case UIGestureRecognizerStateEnded: - { - _currentView = nil; - } - break; - - case UIGestureRecognizerStateCancelled: - { - _currentView = nil; - } - break; - - default: - break; - } -} - -- (void)handleRotate:(UIRotationGestureRecognizer *)gestureRecognizer -{ - CGPoint location = [gestureRecognizer locationInView:self]; - - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateBegan: - { - if (_currentView != nil) - return; - - _currentView = [self viewForLocation:location]; - } - break; - - case UIGestureRecognizerStateChanged: - { - if (_currentView == nil) - return; - - CGFloat rotation = gestureRecognizer.rotation; - [_currentView rotate:rotation absolute:false]; - - [gestureRecognizer setRotation:0.0f]; - } - break; - - case UIGestureRecognizerStateEnded: - { - - } - break; - - case UIGestureRecognizerStateCancelled: - { - - } - break; - - default: - break; - } -} - -- (TGPhotoPaintEntityView *)viewForLocation:(CGPoint)__unused location -{ - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if (view.selectionView != nil) - return view; - } - - return nil; -} - -- (UIImage *)imageInRect:(CGRect)rect background:(UIImage *)background still:(bool)still -{ - if (self.subviews.count < 2) - return nil; - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(rect.size.width, rect.size.height), false, 1.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGRect bounds = CGRectMake(0, 0, rect.size.width, rect.size.height); - [background drawInRect:bounds]; - - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) - { - [self drawView:view inContext:context withBlock:^ - { - TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)view; - UIImage *image = stickerView.image; - if (image != nil) { - CGSize fittedSize = TGScaleToSize(image.size, view.bounds.size); - - CGContextTranslateCTM(context, view.bounds.size.width / 2.0f, view.bounds.size.height / 2.0f); - if (stickerView.isMirrored) - CGContextScaleCTM(context, -1, 1); - - [image drawInRect:CGRectMake(-fittedSize.width / 2.0f, -fittedSize.height / 2.0f, fittedSize.width, fittedSize.height)]; - } - }]; - } - else if ([view isKindOfClass:[TGPhotoTextEntityView class]]) - { - [self drawView:view inContext:context withBlock:^ - { - [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:false]; - }]; - } - } - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return image; -} - -- (void)drawView:(UIView *)view inContext:(CGContextRef)context withBlock:(void (^)(void))block -{ - CGContextSaveGState(context); - - CGContextTranslateCTM(context, view.center.x, view.center.y); - CGContextConcatCTM(context, view.transform); - CGContextTranslateCTM(context, -view.bounds.size.width / 2.0f, -view.bounds.size.height / 2.0f); - - block(); - - CGContextRestoreGState(context); -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ - bool pointInside = [super pointInside:point withEvent:event]; - if (!pointInside) - { - for (UIView *subview in self.subviews) - { - CGPoint convertedPoint = [self convertPoint:point toView:subview]; - if ([subview pointInside:convertedPoint withEvent:event]) - pointInside = true; - } - } - return pointInside; -} - -- (bool)isTrackingAnyEntityView -{ - bool tracking = false; - for (TGPhotoPaintEntityView *view in self.subviews) - { - if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) - continue; - - if (view.isTracking) - { - tracking = true; - break; - } - } - return tracking; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintActionsView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintActionsView.h deleted file mode 100644 index 602c2fc610..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintActionsView.h +++ /dev/null @@ -1,15 +0,0 @@ -#import - -@interface TGPhotoPaintActionsView : UIView - -@property (nonatomic, assign) UIInterfaceOrientation interfaceOrientation; - -@property (nonatomic, copy) void (^undoPressed)(void); -@property (nonatomic, copy) void (^redoPressed)(void); -@property (nonatomic, copy) void (^clearPressed)(UIView *); - -- (void)setUndoEnabled:(bool)enabled; -- (void)setRedoEnabled:(bool)enabled; -- (void)setClearEnabled:(bool)enabled; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintActionsView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintActionsView.m deleted file mode 100644 index 8b3ca16860..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintActionsView.m +++ /dev/null @@ -1,115 +0,0 @@ -#import "TGPhotoPaintActionsView.h" - -#import "LegacyComponentsInternal.h" -#import "TGFont.h" -#import "TGImageUtils.h" - -#import - -@interface TGPhotoPaintActionsView () -{ - TGModernButton *_undoButton; - TGModernButton *_redoButton; - TGModernButton *_clearButton; -} -@end - -@implementation TGPhotoPaintActionsView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _undoButton = [[TGModernButton alloc] init]; - _undoButton.adjustsImageWhenDisabled = false; - _undoButton.enabled = false; - _undoButton.exclusiveTouch = true; - [_undoButton setImage:TGTintedImage([UIImage imageNamed:@"Editor/Undo"], [UIColor whiteColor]) forState:UIControlStateNormal]; - [_undoButton addTarget:self action:@selector(undoButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_undoButton]; - - _redoButton = [[TGModernButton alloc] init]; - _redoButton.adjustsImageWhenDisabled = false; - _redoButton.enabled = false; - _redoButton.exclusiveTouch = true; - [_redoButton setImage:TGComponentsImageNamed(@"PaintRedoIcon") forState:UIControlStateNormal]; - [_redoButton addTarget:self action:@selector(redoButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - //[self addSubview:_redoButton]; - - _clearButton = [[TGModernButton alloc] init]; - _clearButton.enabled = false; - _clearButton.exclusiveTouch = true; - _clearButton.titleLabel.font = TGSystemFontOfSize(17.0f); - _clearButton.titleLabel.textAlignment = NSTextAlignmentCenter; - [_clearButton setTitle:TGLocalized(@"Paint.Clear") forState:UIControlStateNormal]; - [_clearButton setTitleColor:[UIColor whiteColor]]; - [_clearButton addTarget:self action:@selector(clearButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [_clearButton sizeToFit]; - [self addSubview:_clearButton]; - } - return self; -} - -- (void)undoButtonPressed -{ - if (self.undoPressed != nil) - self.undoPressed(); -} - -- (void)redoButtonPressed -{ - if (self.redoPressed != nil) - self.redoPressed(); -} - -- (void)clearButtonPressed -{ - if (self.clearPressed != nil) - self.clearPressed(_clearButton); -} - -- (void)setUndoEnabled:(bool)enabled -{ - _undoButton.enabled = enabled; -} - -- (void)setRedoEnabled:(bool)enabled -{ - _redoButton.enabled = enabled; -} - -- (void)setClearEnabled:(bool)enabled -{ - _clearButton.enabled = enabled; -} - -- (void)layoutSubviews -{ - if (self.frame.size.width > self.frame.size.height) - { - _undoButton.frame = CGRectMake(6, 0, 40, self.frame.size.height); - _redoButton.frame = CGRectMake(CGRectGetMaxX(_undoButton.frame) + 18, 0, 40, self.frame.size.height); - - _clearButton.titleLabel.font = TGSystemFontOfSize(17.0f); - _clearButton.titleLabel.numberOfLines = 1; - - if (_clearButton.frame.size.width < FLT_EPSILON) { - _clearButton.frame = CGRectMake(0, 0, 100, self.frame.size.height); - [_clearButton sizeToFit]; - } - - _clearButton.frame = CGRectMake(self.frame.size.width - _clearButton.frame.size.width - 10.0f, 0, _clearButton.frame.size.width, self.frame.size.height); - } - else - { - //_redoButton.frame = CGRectMake(0, self.frame.size.height - 40 - 14, self.frame.size.width, 40); - _undoButton.frame = CGRectMake(0, self.frame.size.height - 40 - 6, self.frame.size.width, 40); - - _clearButton.titleLabel.font = TGSystemFontOfSize(13.0f); - _clearButton.titleLabel.numberOfLines = 2; - _clearButton.frame = CGRectMake(0.0f, 10.0f, self.frame.size.width, 24.0f); - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintColorPicker.h b/submodules/LegacyComponents/Sources/TGPhotoPaintColorPicker.h deleted file mode 100644 index 02a89beb1d..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintColorPicker.h +++ /dev/null @@ -1,14 +0,0 @@ -#import - -@class TGPaintSwatch; - -@interface TGPhotoPaintColorPicker : UIControl - -@property (nonatomic, copy) void (^beganPicking)(void); -@property (nonatomic, copy) void (^valueChanged)(void); -@property (nonatomic, copy) void (^finishedPicking)(void); - -@property (nonatomic, strong) TGPaintSwatch *swatch; -@property (nonatomic, assign) UIInterfaceOrientation orientation; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintColorPicker.m b/submodules/LegacyComponents/Sources/TGPhotoPaintColorPicker.m deleted file mode 100644 index 71812d67a3..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintColorPicker.m +++ /dev/null @@ -1,737 +0,0 @@ -#import "TGPhotoPaintColorPicker.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -#import - -#import "TGPaintSwatch.h" - -const CGFloat TGPhotoPaintColorWeightGestureRange = 320.0f; -const CGFloat TGPhotoPaintVerticalThreshold = 5.0f; -const CGFloat TGPhotoPaintPreviewOffset = -70.0f; -const CGFloat TGPhotoPaintPreviewScale = 2.0f; -const CGFloat TGPhotoPaintDefaultBrushWeight = 0.08f; -const CGFloat TGPhotoPaintDefaultColorLocation = 0.0f; - -@interface TGPhotoPaintColorPickerKnobCircleView : UIView -{ - CGFloat _strokeIntensity; -} - -@property (nonatomic, strong) UIColor *color; -@property (nonatomic, assign) bool strokesLowContrastColors; - -@end - -@interface TGPhotoPaintColorPickerKnob : UIView -{ - UIView *_wrapperView; - UIImageView *_shadowView; - TGPhotoPaintColorPickerKnobCircleView *_backgroundView; - TGPhotoPaintColorPickerKnobCircleView *_colorView; - - bool _dragging; - CGFloat _weight; -} - -- (void)setColor:(UIColor *)color; -- (void)setWeight:(CGFloat)weight; - -@property (nonatomic, assign) bool dragging; -@property (nonatomic, assign) bool changingWeight; -@property (nonatomic, assign) UIInterfaceOrientation orientation; - -@end - -@interface TGPhotoPaintColorPickerBackground : UIView - -+ (NSArray *)colors; -+ (NSArray *)locations; - -@end - -@interface TGPhotoPaintColorPicker () -{ - TGPhotoPaintColorPickerBackground *_backgroundView; - TGPhotoPaintColorPickerKnob *_knobView; - - UIPanGestureRecognizer *_panGestureRecognizer; - UILongPressGestureRecognizer *_pressGestureRecognizer; - UITapGestureRecognizer *_tapGestureRecognizer; - - CGPoint _gestureStartLocation; - - CGFloat _location; - bool _dragging; - - CGFloat _weight; -} -@end - -@implementation TGPhotoPaintColorPicker - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - _backgroundView = [[TGPhotoPaintColorPickerBackground alloc] initWithFrame:self.bounds]; - _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self addSubview:_backgroundView]; - - _knobView = [[TGPhotoPaintColorPickerKnob alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 24.0f, 24.0f)]; - [_knobView setColor:[TGPhotoPaintColorPicker colorForLocation:0.0f]]; - [self addSubview:_knobView]; - - _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _panGestureRecognizer.delegate = self; - [self addGestureRecognizer:_panGestureRecognizer]; - - _pressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePress:)]; - _pressGestureRecognizer.delegate = self; - _pressGestureRecognizer.minimumPressDuration = 0.1; - [self addGestureRecognizer:_pressGestureRecognizer]; - - _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; - [self addGestureRecognizer:_tapGestureRecognizer]; - - _location = [self restoreLastColorLocation]; - _weight = TGPhotoPaintDefaultBrushWeight; - } - return self; -} - -- (CGFloat)restoreLastColorLocation -{ - NSNumber *lastColor = [[NSUserDefaults standardUserDefaults] objectForKey:@"TG_paintLastColorLocation_v0"]; - if (lastColor != nil) - return [lastColor floatValue]; - - return TGPhotoPaintDefaultColorLocation; -} - -- (void)storeCurrentColorLocation -{ - [[NSUserDefaults standardUserDefaults] setObject:@(_location) forKey:@"TG_paintLastColorLocation_v0"]; -} - -- (void)setOrientation:(UIInterfaceOrientation)orientation -{ - _orientation = orientation; - _knobView.orientation = orientation; -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ - if (CGRectContainsPoint(CGRectInset(self.bounds, -30.0f, -10.0f), point)) - return true; - - return [super pointInside:point withEvent:event]; -} - -- (TGPaintSwatch *)swatch -{ - return [TGPaintSwatch swatchWithColor:[TGPhotoPaintColorPicker colorForLocation:_location] colorLocation:_location brushWeight:_weight]; -} - -- (void)setSwatch:(TGPaintSwatch *)swatch -{ - [self setLocation:swatch.colorLocation]; - [self setWeight:swatch.brushWeight]; -} - -- (UIColor *)color -{ - return [TGPhotoPaintColorPicker colorForLocation:_location]; -} - -- (void)setLocation:(CGFloat)location -{ - [self setLocation:location animated:false]; -} - -- (void)setLocation:(CGFloat)location animated:(bool)animated -{ - _location = location; - [_knobView setColor:[TGPhotoPaintColorPicker colorForLocation:_location]]; - - if (animated) - { - [UIView animateWithDuration:0.3 delay:0.0 usingSpringWithDamping:0.85f initialSpringVelocity:0.0f options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionLayoutSubviews animations:^ - { - [self layoutSubviews]; - } completion:nil]; - } - else - { - [self setNeedsLayout]; - } -} - -- (void)setWeight:(CGFloat)weight -{ - _weight = weight; - [_knobView setWeight:weight]; -} - -- (void)setDragging:(bool)dragging -{ - _dragging = dragging; - [_knobView setDragging:dragging]; -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)__unused gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)__unused otherGestureRecognizer -{ - return true; -} - -- (bool)_hasBeganChangingWeight:(CGPoint)location -{ - switch (self.orientation) - { - case UIInterfaceOrientationLandscapeLeft: - if (location.x > self.frame.size.width + TGPhotoPaintVerticalThreshold) - return true; - - case UIInterfaceOrientationLandscapeRight: - if (location.x < -TGPhotoPaintVerticalThreshold) - return true; - - default: - if (location.y < -TGPhotoPaintVerticalThreshold) - return true; - } - - return false; -} - -- (CGFloat)_weightLocation:(CGPoint)location -{ - CGFloat weightLocation = 0.0f; - switch (self.orientation) - { - case UIInterfaceOrientationLandscapeLeft: - weightLocation = (location.x - self.frame.size.width - TGPhotoPaintVerticalThreshold) / TGPhotoPaintColorWeightGestureRange; - break; - - case UIInterfaceOrientationLandscapeRight: - weightLocation = ((location.x * -1) - TGPhotoPaintVerticalThreshold) / TGPhotoPaintColorWeightGestureRange; - break; - - default: - weightLocation = ((location.y * -1) - TGPhotoPaintVerticalThreshold) / TGPhotoPaintColorWeightGestureRange; - break; - } - - return MAX(0.0f, MIN(1.0f, weightLocation)); -} - -- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer -{ - CGPoint location = [gestureRecognizer locationInView:gestureRecognizer.view]; - - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateBegan: - { - _gestureStartLocation = location; - [self setDragging:true]; - - if (self.beganPicking != nil) - self.beganPicking(); - } - break; - - case UIGestureRecognizerStateChanged: - { - CGFloat colorLocation = MAX(0.0f, MIN(1.0f, self.frame.size.width > self.frame.size.height ? location.x / gestureRecognizer.view.frame.size.width : location.y / gestureRecognizer.view.frame.size.height)); - [self setLocation:colorLocation]; - - if ([self _hasBeganChangingWeight:location]) - { - [_knobView setChangingWeight:true]; - CGFloat weightLocation = [self _weightLocation:location]; - [self setWeight:weightLocation]; - } - - if (self.valueChanged != nil) - self.valueChanged(); - } - break; - - case UIGestureRecognizerStateEnded: - { - [_knobView setChangingWeight:false]; - [self setDragging:false]; - - if (self.finishedPicking != nil) - self.finishedPicking(); - - [self storeCurrentColorLocation]; - } - break; - - case UIGestureRecognizerStateCancelled: - { - [_knobView setChangingWeight:false]; - } - break; - - default: - break; - } -} - -- (void)handlePress:(UILongPressGestureRecognizer *)gestureRecognizer -{ - CGPoint location = [gestureRecognizer locationInView:gestureRecognizer.view]; - - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateBegan: - { - if (!CGRectContainsPoint(_knobView.frame, location)) - { - CGFloat colorLocation = MAX(0.0f, MIN(1.0f, self.frame.size.width > self.frame.size.height ? location.x / gestureRecognizer.view.frame.size.width : location.y / gestureRecognizer.view.frame.size.height)); - [self setLocation:colorLocation animated:true]; - } - - [self setDragging:true]; - - if (self.beganPicking != nil) - self.beganPicking(); - } - break; - - case UIGestureRecognizerStateEnded: - { - [self setDragging:false]; - - if (self.finishedPicking != nil) - self.finishedPicking(); - - [self storeCurrentColorLocation]; - } - break; - - default: - break; - } -} - -- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer -{ - CGPoint location = [gestureRecognizer locationInView:gestureRecognizer.view]; - if (!CGRectContainsPoint(_knobView.frame, location)) - { - CGFloat colorLocation = MAX(0.0f, MIN(1.0f, self.frame.size.width > self.frame.size.height ? location.x / gestureRecognizer.view.frame.size.width : location.y / gestureRecognizer.view.frame.size.height)); - [self setLocation:colorLocation animated:true]; - - if (self.finishedPicking != nil) - self.finishedPicking(); - - [self storeCurrentColorLocation]; - } -} - -+ (UIColor *)colorForLocation:(CGFloat)location -{ - NSArray *locations = [TGPhotoPaintColorPickerBackground locations]; - NSArray *colors = [TGPhotoPaintColorPickerBackground colors]; - - if (location < FLT_EPSILON) - return [UIColor colorWithCGColor:(CGColorRef)colors.firstObject]; - else if (location > 1 - FLT_EPSILON) - return [UIColor colorWithCGColor:(CGColorRef)colors.lastObject]; - - __block NSInteger leftIndex = -1; - __block NSInteger rightIndex = -1; - - [locations enumerateObjectsUsingBlock:^(NSNumber *value, NSUInteger index, BOOL *stop) - { - if (index > 0) - { - if (value.doubleValue > location) - { - leftIndex = index - 1; - rightIndex = index; - *stop = true; - } - } - }]; - - CGFloat leftLocation = [locations[leftIndex] doubleValue]; - UIColor *leftColor = [UIColor colorWithCGColor:(CGColorRef)colors[leftIndex]]; - - CGFloat rightLocation = [locations[rightIndex] doubleValue]; - UIColor *rightColor = [UIColor colorWithCGColor:(CGColorRef)colors[rightIndex]]; - - CGFloat factor = (location - leftLocation) / (rightLocation - leftLocation); - return [self _interpolateColor:leftColor withColor:rightColor factor:factor]; -} - -+ (void)_colorComponentsForColor:(UIColor *)color red:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue -{ - NSInteger componentsCount = CGColorGetNumberOfComponents(color.CGColor); - const CGFloat *components = CGColorGetComponents(color.CGColor); - - CGFloat r = 0.0f; - CGFloat g = 0.0f; - CGFloat b = 0.0f; - CGFloat a = 1.0f; - - if (componentsCount == 4) - { - r = components[0]; - g = components[1]; - b = components[2]; - a = components[3]; - } - else - { - r = g = b = components[0]; - } - - *red = r; - *green = g; - *blue = b; -} - -+ (UIColor *)_interpolateColor:(UIColor *)color1 withColor:(UIColor *)color2 factor:(CGFloat)factor -{ - factor = MIN(MAX(factor, 0.0), 1.0); - - CGFloat r1 = 0, r2 = 0; - CGFloat g1 = 0, g2 = 0; - CGFloat b1 = 0, b2 = 0; - - [self _colorComponentsForColor:color1 red:&r1 green:&g1 blue:&b1]; - [self _colorComponentsForColor:color2 red:&r2 green:&g2 blue:&b2]; - - CGFloat r = r1 + (r2 - r1) * factor; - CGFloat g = g1 + (g2 - g1) * factor; - CGFloat b = b1 + (b2 - b1) * factor; - - return [UIColor colorWithRed:r green:g blue:b alpha:1.0f]; -} - -- (void)layoutSubviews -{ - CGFloat pos = self.frame.size.width > self.frame.size.height ? -_knobView.frame.size.width / 2.0f + self.frame.size.width * _location : -_knobView.frame.size.height / 2.0f + self.frame.size.height * _location; - - _knobView.frame = self.frame.size.width > self.frame.size.height ? CGRectMake(pos, (self.frame.size.height - _knobView.frame.size.height) / 2.0f, _knobView.frame.size.width, _knobView.frame.size.height) : CGRectMake((self.frame.size.width - _knobView.frame.size.width) / 2.0f, pos, _knobView.frame.size.width, _knobView.frame.size.height); -} - -@end - -@implementation TGPhotoPaintColorPickerKnobCircleView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.backgroundColor = [UIColor clearColor]; - self.contentMode = UIViewContentModeRedraw; - self.opaque = false; - } - return self; -} - -- (void)setColor:(UIColor *)color -{ - _color = color; - - if (self.strokesLowContrastColors) - { - CGFloat strokeIntensity = 0.0f; - CGFloat hue; - CGFloat saturation; - CGFloat brightness; - CGFloat alpha; - - bool success = [color getHue:&hue saturation:&saturation brightness:&brightness alpha:&alpha]; - if (success && hue < FLT_EPSILON && saturation < FLT_EPSILON && brightness > 0.92f) - strokeIntensity = (brightness - 0.92f) / 0.08f; - - _strokeIntensity = strokeIntensity; - } - - [self setNeedsDisplay]; -} - -- (void)drawRect:(CGRect)rect -{ - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetFillColorWithColor(context, self.color.CGColor); - CGContextFillEllipseInRect(context, rect); - - if (_strokeIntensity > FLT_EPSILON) - { - CGContextSetLineWidth(context, 1.0f); - CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:0.88f alpha:_strokeIntensity].CGColor); - CGContextStrokeEllipseInRect(context, CGRectInset(rect, 1.0f, 1.0f)); - } -} - -@end - - -const CGFloat TGPhotoPaintColorSmallCircle = 4.0f; -const CGFloat TGPhotoPaintColorLargeCircle = 20.0f; - -@implementation TGPhotoPaintColorPickerKnob - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.userInteractionEnabled = false; - - _wrapperView = [[UIView alloc] initWithFrame:self.bounds]; - [self addSubview:_wrapperView]; - - static UIImage *shadowImage = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^ - { - UIGraphicsBeginImageContextWithOptions(CGSizeMake(48.0f, 48.0f), false, 0.0f); - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGContextSetShadowWithColor(context, CGSizeMake(0, 1.5f), 4.0f, [UIColor colorWithWhite:0.0f alpha:0.7f].CGColor); - CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 1.0f).CGColor); - CGContextFillEllipseInRect(context, CGRectMake(4.0f, 4.0f, 40.0f, 40.0f)); - shadowImage = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - - _shadowView = [[UIImageView alloc] initWithImage:shadowImage]; - _shadowView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _shadowView.frame = CGRectInset(_wrapperView.bounds, -2, -2); - [_wrapperView addSubview:_shadowView]; - - _backgroundView = [[TGPhotoPaintColorPickerKnobCircleView alloc] initWithFrame:self.bounds]; - _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _backgroundView.color = [UIColor whiteColor]; - [_wrapperView addSubview:_backgroundView]; - - _colorView = [[TGPhotoPaintColorPickerKnobCircleView alloc] init]; - _colorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; - _colorView.center = TGPaintCenterOfRect(self.bounds); - _colorView.color = [UIColor blueColor]; - _colorView.strokesLowContrastColors = true; - [self setWeight:0.5f]; - [_wrapperView addSubview:_colorView]; - } - return self; -} - -- (void)setColor:(UIColor *)color -{ - [_colorView setColor:color]; -} - -- (void)setWeight:(CGFloat)size -{ - _weight = size; - if (_dragging) - [self updateLocationAnimated:true updateColorSize:false]; - - CGFloat diameter = [self _circleDiameterForBrushWeight:size zoomed:_dragging]; - [_colorView setBounds:CGRectMake(0, 0, diameter, diameter)]; -} - -- (void)setDragging:(bool)dragging -{ - if (dragging == _dragging) - return; - - _dragging = dragging; - [self updateLocationAnimated:true updateColorSize:true]; -} - -- (CGFloat)_circleDiameterForBrushWeight:(CGFloat)size zoomed:(bool)zoomed -{ - CGFloat result = TGPhotoPaintColorSmallCircle + (TGPhotoPaintColorLargeCircle - TGPhotoPaintColorSmallCircle) * size; - result = zoomed ? TGRetinaFloor(result) * TGPhotoPaintPreviewScale : floor(result); - return result; -} - -- (void)updateLocationAnimated:(bool)animated updateColorSize:(bool)updateColorSize -{ - void (^changeBlock)(void) = ^ - { - CGPoint center = TGPaintCenterOfRect(self.bounds); - CGFloat scale = 1.0f; - if (_dragging) - { - scale = TGPhotoPaintPreviewScale; - - CGFloat offset = TGPhotoPaintPreviewOffset; - if (self.changingWeight) - offset -= _weight * TGPhotoPaintColorWeightGestureRange; - - switch (self.orientation) - { - case UIInterfaceOrientationLandscapeLeft: - center.x -= offset; - break; - - case UIInterfaceOrientationLandscapeRight: - center.x += offset; - break; - - default: - center.y += offset; - break; - } - } - - _wrapperView.center = center; - _wrapperView.bounds = CGRectMake(0, 0, 24.0f * scale, 24.0f * scale); - - if (updateColorSize) - { - CGFloat diameter = [self _circleDiameterForBrushWeight:_weight zoomed:_dragging]; - [_colorView setBounds:CGRectMake(0, 0, diameter, diameter)]; - } - }; - - if (animated) - { - [UIView animateWithDuration:0.3 delay:0.0 usingSpringWithDamping:0.85f initialSpringVelocity:0.0f options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionLayoutSubviews animations:changeBlock completion:nil]; - } - else - { - changeBlock(); - } -} - -@end - - -static void addRoundedRectToPath(CGContextRef context, CGRect rect, CGFloat ovalWidth, CGFloat ovalHeight) -{ - CGFloat fw, fh; - if (ovalWidth == 0 || ovalHeight == 0) - { - CGContextAddRect(context, rect); - return; - } - - CGContextSaveGState(context); - CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect)); - CGContextScaleCTM (context, ovalWidth, ovalHeight); - fw = CGRectGetWidth (rect) / ovalWidth; - fh = CGRectGetHeight (rect) / ovalHeight; - CGContextMoveToPoint(context, fw, fh/2); - CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); - CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); - CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); - CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); - CGContextClosePath(context); - CGContextRestoreGState(context); -} - -@implementation TGPhotoPaintColorPickerBackground - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.backgroundColor = [UIColor clearColor]; - self.contentMode = UIViewContentModeRedraw; - self.opaque = false; - } - return self; -} - -- (void)drawRect:(CGRect)rect -{ - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGFloat radius = rect.size.width > rect.size.height ? rect.size.height / 2.0f : rect.size.width / 2.0f; - addRoundedRectToPath(context, self.frame, radius, radius); - CGContextClip(context); - - CFArrayRef colors = (__bridge CFArrayRef)[TGPhotoPaintColorPickerBackground colors]; - CGFloat locations[[TGPhotoPaintColorPickerBackground colors].count]; - [TGPhotoPaintColorPickerBackground fillLocations:locations]; - - CGColorSpaceRef colorSpc = CGColorSpaceCreateDeviceRGB(); - CGGradientRef gradient = CGGradientCreateWithColors(colorSpc, colors, locations); - - if (rect.size.width > rect.size.height) - { - CGContextDrawLinearGradient(context, gradient, CGPointMake(0.0f, rect.size.height / 2.0f), CGPointMake(rect.size.width, rect.size.height / 2.0f), kCGGradientDrawsAfterEndLocation); - } - else - { - CGContextDrawLinearGradient(context, gradient, CGPointMake(rect.size.width / 2.0f, 0.0f), CGPointMake(rect.size.width / 2.0f, rect.size.height), kCGGradientDrawsAfterEndLocation); - } - - CGContextSetBlendMode(context, kCGBlendModeClear); - CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor); - - CGColorSpaceRelease(colorSpc); - CGGradientRelease(gradient); -} - -+ (NSArray *)colors -{ - static dispatch_once_t onceToken; - static NSArray *colors; - dispatch_once(&onceToken, ^ - { - colors = @ - [ - (id)UIColorRGB(0xea2739).CGColor, //red - (id)UIColorRGB(0xdb3ad2).CGColor, //pink - (id)UIColorRGB(0x3051e3).CGColor, //blue - (id)UIColorRGB(0x49c5ed).CGColor, //cyan - (id)UIColorRGB(0x80c864).CGColor, //green - (id)UIColorRGB(0xfcde65).CGColor, //yellow - (id)UIColorRGB(0xfc964d).CGColor, //orange - (id)UIColorRGB(0x000000).CGColor, //black - (id)UIColorRGB(0xffffff).CGColor //white - ]; - }); - return colors; -} - -+ (NSArray *)locations -{ - static dispatch_once_t onceToken; - static NSArray *locations; - dispatch_once(&onceToken, ^ - { - locations = @ - [ - @0.0f, //red - @0.14f, //pink - @0.24f, //blue - @0.39f, //cyan - @0.49f, //green - @0.62f, //yellow - @0.73f, //orange - @0.85f, //black - @1.0f //white - ]; - }); - return locations; -} - -+ (void)fillLocations:(CGFloat *)buf -{ - NSArray *locations = [self locations]; - [locations enumerateObjectsUsingBlock:^(NSNumber *location, NSUInteger index, __unused BOOL *stop) - { - buf[index] = location.doubleValue; - }]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintController.h b/submodules/LegacyComponents/Sources/TGPhotoPaintController.h deleted file mode 100644 index 341eae634a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintController.h +++ /dev/null @@ -1,28 +0,0 @@ -//#import "TGPhotoEditorTabController.h" -// -//#import -// -//@class PGPhotoEditor; -//@class TGPhotoEditorPreviewView; -// -//@protocol TGPhotoPaintStickersContext; -// -//@interface TGPhotoPaintController : TGPhotoEditorTabController -// -//@property (nonatomic, strong) id stickersContext; -// -//- (instancetype)initWithContext:(id)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView entitiesView:(TGPhotoEntitiesContainerView *)entitiesView; -// -//- (TGPaintingData *)paintingData; -// -//+ (CGRect)photoContainerFrameForParentViewFrame:(CGRect)parentViewFrame toolbarLandscapeSize:(CGFloat)toolbarLandscapeSize orientation:(UIInterfaceOrientation)orientation panelSize:(CGFloat)panelSize hasOnScreenNavigation:(bool)hasOnScreenNavigation; -// -//+ (CGSize)fittedContentSize:(CGRect)cropRect orientation:(UIImageOrientation)orientation originalSize:(CGSize)originalSize; -//+ (CGRect)fittedCropRect:(CGRect)cropRect originalSize:(CGSize)originalSize keepOriginalSize:(bool)originalSize; -//+ (CGPoint)fittedCropRect:(CGRect)cropRect centerScale:(CGFloat)scale; -//+ (CGSize)maximumPaintingSize; -// -//@end -// -//extern const CGFloat TGPhotoPaintTopPanelSize; -//extern const CGFloat TGPhotoPaintBottomPanelSize; diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m b/submodules/LegacyComponents/Sources/TGPhotoPaintController.m deleted file mode 100644 index 4b28ca2afd..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintController.m +++ /dev/null @@ -1,2602 +0,0 @@ -//#import "TGPhotoPaintController.h" -// -//#import "LegacyComponentsInternal.h" -// -//#import -// -//#import -//#import -//#import -//#import "TGPhotoEditorInterfaceAssets.h" -//#import -// -//#import -//#import -// -//#import "TGMenuSheetController.h" -// -//#import -//#import -// -//#import "TGPainting.h" -//#import -//#import "TGPaintRadialBrush.h" -//#import "TGPaintEllipticalBrush.h" -//#import "TGPaintNeonBrush.h" -//#import "TGPaintArrowBrush.h" -//#import "TGPaintCanvas.h" -//#import "TGPaintingWrapperView.h" -//#import "TGPaintState.h" -//#import "TGPaintBrushPreview.h" -//#import "TGPaintSwatch.h" -//#import "TGPhotoPaintFont.h" -//#import -// -//#import "PGPhotoEditor.h" -//#import "TGPhotoEditorPreviewView.h" -// -//#import "TGPhotoPaintActionsView.h" -//#import "TGPhotoPaintSettingsView.h" -// -//#import "TGPhotoPaintSettingsWrapperView.h" -//#import "TGPhotoBrushSettingsView.h" -//#import "TGPhotoTextSettingsView.h" -// -//#import "TGPhotoPaintSelectionContainerView.h" -//#import "TGPhotoEntitiesContainerView.h" -//#import "TGPhotoStickerEntityView.h" -//#import "TGPhotoTextEntityView.h" -//#import "TGPhotoPaintEyedropperView.h" -// -//#import "TGPaintFaceDetector.h" -//#import "TGPhotoMaskPosition.h" -// -//const CGFloat TGPhotoPaintTopPanelSize = 44.0f; -//const CGFloat TGPhotoPaintBottomPanelSize = 79.0f; -//const CGSize TGPhotoPaintingLightMaxSize = { 1280.0f, 1280.0f }; -//const CGSize TGPhotoPaintingMaxSize = { 2560.0f, 2560.0f }; -// -//const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f; -// -//@interface TGPhotoPaintController () -//{ -// TGPaintUndoManager *_undoManager; -// TGObserverProxy *_keyboardWillChangeFrameProxy; -// CGFloat _keyboardHeight; -// -// TGModernGalleryZoomableScrollView *_scrollView; -// UIView *_scrollContentView; -// -// UIButton *_containerView; -// TGPhotoEditorSparseView *_wrapperView; -// UIView *_portraitToolsWrapperView; -// UIView *_landscapeToolsWrapperView; -// -// UIPinchGestureRecognizer *_pinchGestureRecognizer; -// UIRotationGestureRecognizer *_rotationGestureRecognizer; -// -// NSArray *_brushes; -// TGPainting *_painting; -// TGPaintCanvas *_canvasView; -// TGPaintBrushPreview *_brushPreview; -// -// CGSize _previousSize; -// UIView *_contentView; -// UIView *_contentWrapperView; -// -// UIView *_dimView; -// TGModernButton *_doneButton; -// -// TGPhotoPaintActionsView *_landscapeActionsView; -// TGPhotoPaintActionsView *_portraitActionsView; -// -// TGPhotoPaintSettingsView *_portraitSettingsView; -// TGPhotoPaintSettingsView *_landscapeSettingsView; -// -// TGPhotoPaintSettingsWrapperView *_settingsViewWrapper; -// UIView *_settingsView; -// id _stickersScreen; -// -// double _stickerStartTime; -// -// bool _appeared; -// bool _skipEntitiesSetup; -// bool _entitiesReady; -// -// TGPhotoPaintFont *_selectedTextFont; -// TGPhotoPaintTextEntityStyle _selectedTextStyle; -// -// TGPhotoEntitiesContainerView *_entitiesContainerView; -// TGPhotoPaintEntityView *_currentEntityView; -// -// TGPhotoPaintSelectionContainerView *_selectionContainerView; -// TGPhotoPaintEntitySelectionView *_entitySelectionView; -// TGPhotoPaintEyedropperView *_eyedropperView; -// -// TGPhotoTextEntityView *_editedTextView; -// CGPoint _editedTextCenter; -// CGAffineTransform _editedTextTransform; -// UIButton *_textEditingDismissButton; -// -// TGMenuContainerView *_menuContainerView; -// -// TGPaintingData *_resultData; -// -// TGPaintingWrapperView *_paintingWrapperView; -// -// bool _enableStickers; -// -// NSData *_eyedropperBackgroundData; -// CGSize _eyedropperBackgroundSize; -// NSInteger _eyedropperBackgroundBytesPerRow; -// CGBitmapInfo _eyedropperBackgroundInfo; -// -// id _context; -//} -// -//@property (nonatomic, strong) ASHandle *actionHandle; -// -//@property (nonatomic, weak) PGPhotoEditor *photoEditor; -//@property (nonatomic, weak) TGPhotoEditorPreviewView *previewView; -// -//@end -// -//@implementation TGPhotoPaintController -// -//- (instancetype)initWithContext:(id)context photoEditor:(PGPhotoEditor *)photoEditor previewView:(TGPhotoEditorPreviewView *)previewView entitiesView:(TGPhotoEntitiesContainerView *)entitiesView -//{ -// self = [super initWithContext:context]; -// if (self != nil) -// { -// _context = context; -// _enableStickers = photoEditor.enableStickers; -// -// _stickerStartTime = NAN; -// -// _actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true]; -// -// self.photoEditor = photoEditor; -// self.previewView = previewView; -// _entitiesContainerView = entitiesView; -// if (entitiesView != nil) { -// _skipEntitiesSetup = true; -// } -// entitiesView.userInteractionEnabled = true; -// -// _brushes = @ -// [ -// [[TGPaintRadialBrush alloc] init], -// [[TGPaintEllipticalBrush alloc] init], -// [[TGPaintNeonBrush alloc] init], -// [[TGPaintArrowBrush alloc] init], -// ]; -// _selectedTextFont = [[TGPhotoPaintFont availableFonts] firstObject]; -// _selectedTextStyle = TGPhotoPaintTextEntityStyleFramed; -// -// _undoManager = [[TGPaintUndoManager alloc] init]; -// -// CGSize size = TGScaleToSize(photoEditor.originalSize, [TGPhotoPaintController maximumPaintingSize]); -//// _painting = [[TGPainting alloc] initWithSize:size undoManager:_undoManager imageData:[_photoEditor.paintingData data]]; -// _undoManager.painting = _painting; -// -// _keyboardWillChangeFrameProxy = [[TGObserverProxy alloc] initWithTarget:self targetSelector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification]; -// } -// return self; -//} -// -//- (void)dealloc -//{ -// [_actionHandle reset]; -//} -// -//- (void)loadView -//{ -// [super loadView]; -// self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; -// -// _scrollView = [[TGModernGalleryZoomableScrollView alloc] initWithFrame:self.view.bounds hasDoubleTap:false]; -// if (@available(iOS 11.0, *)) { -// _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; -// } -// _scrollView.contentInset = UIEdgeInsetsZero; -// _scrollView.delegate = self; -// _scrollView.showsHorizontalScrollIndicator = false; -// _scrollView.showsVerticalScrollIndicator = false; -// [self.view addSubview:_scrollView]; -// -// _scrollContentView = [[UIView alloc] initWithFrame:self.view.bounds]; -// [_scrollView addSubview:_scrollContentView]; -// -// _containerView = [[UIButton alloc] initWithFrame:self.view.bounds]; -// _containerView.clipsToBounds = true; -// [_containerView addTarget:self action:@selector(containerPressed) forControlEvents:UIControlEventTouchUpInside]; -// [_scrollContentView addSubview:_containerView]; -// -// _pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)]; -// _pinchGestureRecognizer.delegate = self; -// [_containerView addGestureRecognizer:_pinchGestureRecognizer]; -// -// _rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotate:)]; -// _rotationGestureRecognizer.delegate = self; -// [_containerView addGestureRecognizer:_rotationGestureRecognizer]; -// -// TGPhotoEditorPreviewView *previewView = _previewView; -// previewView.userInteractionEnabled = false; -// previewView.hidden = true; -// -// __weak TGPhotoPaintController *weakSelf = self; -// _paintingWrapperView = [[TGPaintingWrapperView alloc] init]; -// _paintingWrapperView.clipsToBounds = true; -// _paintingWrapperView.shouldReceiveTouch = ^bool -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return false; -// -// return (strongSelf->_editedTextView == nil); -// }; -// [_containerView addSubview:_paintingWrapperView]; -// -// _contentView = [[UIView alloc] init]; -// _contentView.clipsToBounds = true; -// _contentView.userInteractionEnabled = false; -// [_containerView addSubview:_contentView]; -// -// _contentWrapperView = [[UIView alloc] init]; -// _contentWrapperView.userInteractionEnabled = false; -// [_contentView addSubview:_contentWrapperView]; -// -// if (_entitiesContainerView == nil) { -// _entitiesContainerView = [[TGPhotoEntitiesContainerView alloc] init]; -// _entitiesContainerView.clipsToBounds = true; -// _entitiesContainerView.stickersContext = _stickersContext; -// } -// _entitiesContainerView.entitySelected = ^(TGPhotoPaintEntityView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf selectEntityView:sender]; -// }; -// _entitiesContainerView.entityRemoved = ^(TGPhotoPaintEntityView *entity) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// if (entity == strongSelf->_currentEntityView) -// [strongSelf _clearCurrentSelection]; -// -// [strongSelf updateSettingsButton]; -// }; -// if (!_skipEntitiesSetup) { -// [_contentWrapperView addSubview:_entitiesContainerView]; -// } -// _undoManager.entitiesContainer = _entitiesContainerView; -// -// _dimView = [[UIView alloc] init]; -// _dimView.alpha = 0.0f; -// _dimView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; -// _dimView.backgroundColor = UIColorRGBA(0x000000, 0.4f); -// _dimView.userInteractionEnabled = false; -// [_entitiesContainerView addSubview:_dimView]; -// -// _selectionContainerView = [[TGPhotoPaintSelectionContainerView alloc] init]; -// _selectionContainerView.clipsToBounds = false; -// [_containerView addSubview:_selectionContainerView]; -// -// _eyedropperView = [[TGPhotoPaintEyedropperView alloc] init]; -// _eyedropperView.locationChanged = ^(CGPoint location, bool finished) { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// { -// UIColor *color = [strongSelf colorAtPoint:location]; -// strongSelf->_eyedropperView.color = color; -// -// if (finished) { -// TGPaintSwatch *swatch = [TGPaintSwatch swatchWithColor:color colorLocation:0.5 brushWeight:strongSelf->_portraitSettingsView.swatch.brushWeight]; -// [strongSelf setCurrentSwatch:swatch sender:nil]; -// -// [strongSelf commitEyedropper:false]; -// } -// } -// }; -// _eyedropperView.hidden = true; -// [_selectionContainerView addSubview:_eyedropperView]; -// -// _wrapperView = [[TGPhotoEditorSparseView alloc] initWithFrame:CGRectZero]; -// [self.view addSubview:_wrapperView]; -// -// _portraitToolsWrapperView = [[UIView alloc] initWithFrame:CGRectZero]; -// _portraitToolsWrapperView.alpha = 0.0f; -// [_wrapperView addSubview:_portraitToolsWrapperView]; -// -// _landscapeToolsWrapperView = [[UIView alloc] initWithFrame:CGRectZero]; -// _landscapeToolsWrapperView.alpha = 0.0f; -// [_wrapperView addSubview:_landscapeToolsWrapperView]; -// -// void (^undoPressed)(void) = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// [strongSelf->_undoManager undo]; -// }; -// -// void (^clearPressed)(UIView *) = ^(UIView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// [strongSelf presentClearAllAlert:sender]; -// }; -// -// _portraitActionsView = [[TGPhotoPaintActionsView alloc] init]; -// _portraitActionsView.alpha = 0.0f; -// _portraitActionsView.undoPressed = undoPressed; -// _portraitActionsView.clearPressed = clearPressed; -// [_wrapperView addSubview:_portraitActionsView]; -// -// _landscapeActionsView = [[TGPhotoPaintActionsView alloc] init]; -// _landscapeActionsView.alpha = 0.0f; -// _landscapeActionsView.undoPressed = undoPressed; -// _landscapeActionsView.clearPressed = clearPressed; -// [_wrapperView addSubview:_landscapeActionsView]; -// -// _doneButton = [[TGModernButton alloc] init]; -// _doneButton.alpha = 0.0f; -// _doneButton.userInteractionEnabled = false; -// [_doneButton setTitle:TGLocalized(@"Common.Done") forState:UIControlStateNormal]; -// _doneButton.titleLabel.font = TGSystemFontOfSize(17.0); -// [_doneButton sizeToFit]; -//// [_wrapperView addSubview:_doneButton]; -// -// void (^settingsPressed)(void) = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf commitEyedropper:true]; -// -// if ([strongSelf->_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// [strongSelf presentTextSettingsView]; -// else if ([strongSelf->_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]]) -// [strongSelf mirrorSelectedStickerEntity]; -// else -// [strongSelf presentBrushSettingsView]; -// }; -// -// void (^eyedropperPressed)(void) = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [self enableEyedropper]; -// }; -// -// void (^beganColorPicking)(void) = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf commitEyedropper:true]; -// -// if (![strongSelf->_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// [strongSelf setDimHidden:false animated:true]; -// }; -// -// void (^changedColor)(TGPhotoPaintSettingsView *, TGPaintSwatch *) = ^(TGPhotoPaintSettingsView *sender, TGPaintSwatch *swatch) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf setCurrentSwatch:swatch sender:sender]; -// }; -// -// void (^finishedColorPicking)(TGPhotoPaintSettingsView *, TGPaintSwatch *) = ^(TGPhotoPaintSettingsView *sender, TGPaintSwatch *swatch) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf commitEyedropper:true]; -// -// [strongSelf setCurrentSwatch:swatch sender:sender]; -// -// if (![strongSelf->_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// [strongSelf setDimHidden:true animated:true]; -// }; -// -// _portraitSettingsView = [[TGPhotoPaintSettingsView alloc] initWithContext:_context]; -// _portraitSettingsView.eyedropperPressed = eyedropperPressed; -// _portraitSettingsView.beganColorPicking = beganColorPicking; -// _portraitSettingsView.changedColor = changedColor; -// _portraitSettingsView.finishedColorPicking = finishedColorPicking; -// _portraitSettingsView.settingsPressed = settingsPressed; -// _portraitSettingsView.layer.rasterizationScale = TGScreenScaling(); -// _portraitSettingsView.interfaceOrientation = UIInterfaceOrientationPortrait; -// [_portraitToolsWrapperView addSubview:_portraitSettingsView]; -// -// _landscapeSettingsView = [[TGPhotoPaintSettingsView alloc] initWithContext:_context]; -// _landscapeSettingsView.eyedropperPressed = eyedropperPressed; -// _landscapeSettingsView.beganColorPicking = beganColorPicking; -// _landscapeSettingsView.changedColor = changedColor; -// _landscapeSettingsView.finishedColorPicking = finishedColorPicking; -// _landscapeSettingsView.settingsPressed = settingsPressed; -// _landscapeSettingsView.layer.rasterizationScale = TGScreenScaling(); -// _landscapeSettingsView.interfaceOrientation = UIInterfaceOrientationLandscapeLeft; -// [_landscapeToolsWrapperView addSubview:_landscapeSettingsView]; -// -// [self setCurrentSwatch:_portraitSettingsView.swatch sender:nil]; -// -// if (![self _updateControllerInset:false]) -// [self controllerInsetUpdated:UIEdgeInsetsZero]; -//} -// -//- (void)setStickersContext:(id)stickersContext { -// _stickersContext = stickersContext; -// _entitiesContainerView.stickersContext = stickersContext; -//} -// -//- (void)setupCanvas -//{ -// if (_canvasView == nil) { -// __weak TGPhotoPaintController *weakSelf = self; -// _canvasView = [[TGPaintCanvas alloc] initWithFrame:CGRectZero]; -// _canvasView.pointInsideContainer = ^bool(CGPoint point) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return false; -// -// return [strongSelf->_containerView pointInside:[strongSelf->_canvasView convertPoint:point toView:strongSelf->_containerView] withEvent:nil]; -// }; -// _canvasView.shouldDraw = ^bool -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return false; -// -// return ![strongSelf->_entitiesContainerView isTrackingAnyEntityView]; -// }; -// _canvasView.shouldDrawOnSingleTap = ^bool -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return false; -// -// bool rotating = (strongSelf->_rotationGestureRecognizer.state == UIGestureRecognizerStateBegan || strongSelf->_rotationGestureRecognizer.state == UIGestureRecognizerStateChanged); -// bool pinching = (strongSelf->_pinchGestureRecognizer.state == UIGestureRecognizerStateBegan || strongSelf->_pinchGestureRecognizer.state == UIGestureRecognizerStateChanged); -// -// if (strongSelf->_currentEntityView != nil && !rotating && !pinching) -// { -// [strongSelf selectEntityView:nil]; -// return false; -// } -// -// return true; -// }; -// _canvasView.strokeBegan = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// [strongSelf selectEntityView:nil]; -// }; -// _canvasView.strokeCommited = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// [strongSelf updateActionsView]; -// }; -// _canvasView.hitTest = ^UIView *(CGPoint point, UIEvent *event) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return nil; -// -// return [strongSelf->_entitiesContainerView hitTest:[strongSelf->_canvasView convertPoint:point toView:strongSelf->_entitiesContainerView] withEvent:event]; -// }; -// _canvasView.cropRect = _photoEditor.cropRect; -// _canvasView.cropOrientation = _photoEditor.cropOrientation; -// _canvasView.originalSize = _photoEditor.originalSize; -// [_canvasView setPainting:_painting]; -// [_canvasView setBrush:_brushes.firstObject]; -// [self setCurrentSwatch:_portraitSettingsView.swatch sender:nil]; -// [_paintingWrapperView addSubview:_canvasView]; -// } -// -// _canvasView.hidden = false; -// [self.view setNeedsLayout]; -//} -// -//- (void)viewDidLoad -//{ -// [super viewDidLoad]; -// -// PGPhotoEditor *photoEditor = _photoEditor; -// if (!_skipEntitiesSetup) { -// [_entitiesContainerView setupWithPaintingData:photoEditor.paintingData]; -// } -// for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) -// { -// if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) -// continue; -// -// [self _commonEntityViewSetup:view]; -// } -// -// __weak TGPhotoPaintController *weakSelf = self; -// _undoManager.historyChanged = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// [strongSelf updateActionsView]; -// }; -// -// [self updateActionsView]; -//} -// -//- (void)viewDidAppear:(BOOL)animated -//{ -// [super viewDidAppear:animated]; -// -// [self transitionIn]; -//} -// -//#pragma mark - Tab Bar -// -//- (TGPhotoEditorTab)availableTabs -//{ -// TGPhotoEditorTab result = TGPhotoEditorPaintTab | TGPhotoEditorEraserTab | TGPhotoEditorTextTab; -// if (_enableStickers && _stickersContext != nil) { -// result |= TGPhotoEditorStickerTab; -// } -// return result; -//} -// -//- (void)handleTabAction:(TGPhotoEditorTab)tab -//{ -// [self commitEyedropper:true]; -// -// switch (tab) -// { -// case TGPhotoEditorStickerTab: -// { -// [self presentStickersView]; -// } -// break; -// -// case TGPhotoEditorTextTab: -// { -// [self createNewTextLabel]; -// } -// break; -// -// case TGPhotoEditorPaintTab: -// { -// [self selectEntityView:nil]; -// -// if (_canvasView.state.eraser) -// [self toggleEraserMode]; -// } -// break; -// -// case TGPhotoEditorEraserTab: -// { -// [self selectEntityView:nil]; -// [self toggleEraserMode]; -// } -// break; -// -// default: -// break; -// } -//} -// -//- (TGPhotoEditorTab)activeTab -//{ -// TGPhotoEditorTab tabs = TGPhotoEditorNoneTab; -// -// if (_currentEntityView != nil) -// return tabs; -// -// if (_canvasView.state.eraser) -// tabs |= TGPhotoEditorEraserTab; -// else -// tabs |= TGPhotoEditorPaintTab; -// -// return tabs; -//} -// -//#pragma mark - Undo & Redo -// -//- (void)updateActionsView -//{ -// if (_portraitActionsView == nil || _landscapeActionsView == nil) -// return; -// -// NSArray *views = @[ _portraitActionsView, _landscapeActionsView ]; -// for (TGPhotoPaintActionsView *view in views) -// { -// [view setUndoEnabled:_undoManager.canUndo]; -// [view setClearEnabled:_undoManager.canUndo]; -// } -//} -// -//- (void)presentClearAllAlert:(UIView *)sender -//{ -// TGMenuSheetController *controller = [[TGMenuSheetController alloc] initWithContext:_context dark:false]; -// controller.dismissesByOutsideTap = true; -// controller.narrowInLandscape = true; -// controller.permittedArrowDirections = UIPopoverArrowDirectionUp; -// __weak TGMenuSheetController *weakController = controller; -// -// __weak TGPhotoPaintController *weakSelf = self; -// NSArray *items = @ -// [ -// [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Paint.ClearConfirm") type:TGMenuSheetButtonTypeDestructive fontSize:20.0 action:^ -// { -// __strong TGMenuSheetController *strongController = weakController; -// if (strongController == nil) -// return; -// -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf->_painting clear]; -// [strongSelf->_undoManager reset]; -// -// [strongSelf->_entitiesContainerView removeAll]; -// [strongSelf _clearCurrentSelection]; -// -// [strongSelf updateSettingsButton]; -// -// [strongController dismissAnimated:true manual:false completion:nil]; -// }], -// [[TGMenuSheetButtonItemView alloc] initWithTitle:TGLocalized(@"Common.Cancel") type:TGMenuSheetButtonTypeCancel fontSize:20.0 action:^ -// { -// __strong TGMenuSheetController *strongController = weakController; -// if (strongController != nil) -// [strongController dismissAnimated:true]; -// }] -// ]; -// -// [controller setItemViews:items]; -// controller.sourceRect = ^ -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return CGRectZero; -// return [sender convertRect:sender.bounds toView:strongSelf.view]; -// }; -// [controller presentInViewController:self.parentViewController sourceView:self.view animated:true]; -//} -// -//- (void)_clearCurrentSelection -//{ -// _scrollView.pinchGestureRecognizer.enabled = true; -// _currentEntityView = nil; -// if (_entitySelectionView != nil) -// { -// [_entitySelectionView removeFromSuperview]; -// _entitySelectionView = nil; -// } -//} -// -//#pragma mark - Data Handling -// -//- (UIImage *)eyedropperImage -//{ -// UIImage *backgroundImage = [self.photoEditor currentResultImage]; -// -// CGSize fittedSize = TGFitSize(_painting.size, TGPhotoEditorResultImageMaxSize); -// UIImage *paintingImage = _painting.isEmpty ? nil : [_painting imageWithSize:fittedSize andData:NULL]; -// NSMutableArray *entities = [[NSMutableArray alloc] init]; -// -// UIImage *entitiesImage = nil; -// if (paintingImage == nil && _entitiesContainerView.entitiesCount < 1) -// { -// return backgroundImage; -// } -// else if (_entitiesContainerView.entitiesCount > 0) -// { -// for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) -// { -// if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) -// continue; -// -// TGPhotoPaintEntity *entity = [view entity]; -// if (entity != nil) { -// [entities addObject:entity]; -// } -// } -// entitiesImage = [_entitiesContainerView imageInRect:_entitiesContainerView.bounds background:nil still:true]; -// } -// -// if (entitiesImage == nil && paintingImage == nil) { -// return backgroundImage; -// } else { -// UIGraphicsBeginImageContextWithOptions(fittedSize, false, 1.0); -// -// [backgroundImage drawInRect:CGRectMake(0.0, 0.0, fittedSize.width, fittedSize.height)]; -// [paintingImage drawInRect:CGRectMake(0.0, 0.0, fittedSize.width, fittedSize.height)]; -// [entitiesImage drawInRect:CGRectMake(0.0, 0.0, fittedSize.width, fittedSize.height)]; -// -// UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); -// UIGraphicsEndImageContext(); -// return result; -// } -//} -// -//- (TGPaintingData *)_prepareResultData -//{ -// if (_resultData != nil) -// return _resultData; -// -// NSData *data = nil; -// CGSize fittedSize = TGFitSize(_painting.size, TGPhotoEditorResultImageMaxSize); -// UIImage *image = _painting.isEmpty ? nil : [_painting imageWithSize:fittedSize andData:&data]; -// NSMutableArray *entities = [[NSMutableArray alloc] init]; -// -// bool hasAnimatedEntities = false; -// UIImage *stillImage = nil; -// if (image == nil && _entitiesContainerView.entitiesCount < 1) -// { -// _resultData = nil; -// return _resultData; -// } -// else if (_entitiesContainerView.entitiesCount > 0) -// { -// for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) -// { -// if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) -// continue; -// -// TGPhotoPaintEntity *entity = [view entity]; -// if (entity != nil) { -// if (entity.animated) { -// hasAnimatedEntities = true; -// } -// [entities addObject:entity]; -// } -// } -// -// if (hasAnimatedEntities) { -// for (TGPhotoPaintEntity *entity in entities) { -// if ([entity isKindOfClass:[TGPhotoPaintTextEntity class]]) { -// TGPhotoPaintTextEntity *textEntity = (TGPhotoPaintTextEntity *)entity; -// for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) -// { -// if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) -// continue; -// -// if (view.entityUUID == textEntity.uuid) { -// textEntity.renderImage = [(TGPhotoTextEntityView *)view image]; -// break; -// } -// } -// } -// } -// } -// -// if (!hasAnimatedEntities) { -// image = [_entitiesContainerView imageInRect:_entitiesContainerView.bounds background:image still:false]; -// } else { -// stillImage = [_entitiesContainerView imageInRect:_entitiesContainerView.bounds background:image still:true]; -// } -// } -// -//// _resultData = [TGPaintingData dataWithPaintingData:data image:image stillImage:stillImage entities:entities undoManager:_undoManager]; -// return _resultData; -//} -// -//- (UIImage *)image -//{ -// TGPaintingData *paintingData = [self _prepareResultData]; -// return paintingData.image; -//} -// -//- (TGPaintingData *)paintingData -//{ -// return [self _prepareResultData]; -//} -// -//- (void)enableEyedropper { -// if (!_eyedropperView.isHidden) -// return; -// -// [self selectEntityView:nil]; -// -// self.controlVideoPlayback(false); -// [_entitiesContainerView updateVisibility:false]; -// -// UIImage *image = [self eyedropperImage]; -// CGImageRef cgImage = image.CGImage; -// CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); -// -// _eyedropperBackgroundData = (__bridge NSData *)pixelData; -// _eyedropperBackgroundSize = image.size; -// _eyedropperBackgroundBytesPerRow = CGImageGetBytesPerRow(cgImage); -// _eyedropperBackgroundInfo = CGImageGetBitmapInfo(cgImage); -// -// [_eyedropperView update]; -// [_eyedropperView present]; -//} -// -//- (void)commitEyedropper:(bool)immediate { -// self.controlVideoPlayback(true); -// [_entitiesContainerView updateVisibility:true]; -// -// _eyedropperBackgroundData = nil; -// _eyedropperBackgroundSize = CGSizeZero; -// _eyedropperBackgroundBytesPerRow = 0; -// _eyedropperBackgroundInfo = 0; -// -// double timeout = immediate ? 0.0 : 0.2; -// TGDispatchAfter(timeout, dispatch_get_main_queue(), ^{ -// [_eyedropperView dismiss]; -// }); -//} -// -//- (UIColor *)colorFromData:(NSData *)data width:(NSInteger)width height:(NSInteger)height x:(NSInteger)x y:(NSInteger)y bpr:(NSInteger)bpr { -// uint8_t *pixel = (uint8_t *)data.bytes + bpr * y + x * 4; -// if (_eyedropperBackgroundInfo & kCGBitmapByteOrder32Little) { -// return [UIColor colorWithRed:pixel[2] / 255.0 green:pixel[1] / 255.0 blue:pixel[0] / 255.0 alpha:1.0]; -// } else { -// return [UIColor colorWithRed:pixel[0] / 255.0 green:pixel[1] / 255.0 blue:pixel[2] / 255.0 alpha:1.0]; -// } -//} -// -//- (UIColor *)colorAtPoint:(CGPoint)point -//{ -// CGPoint convertedPoint = CGPointMake(point.x / _eyedropperView.bounds.size.width * _eyedropperBackgroundSize.width, point.y / _eyedropperView.bounds.size.height * _eyedropperBackgroundSize.height); -// UIColor *backgroundColor = [self colorFromData:_eyedropperBackgroundData width:_eyedropperBackgroundSize.width height:_eyedropperBackgroundSize.height x:convertedPoint.x y:convertedPoint.y bpr:_eyedropperBackgroundBytesPerRow]; -// return backgroundColor; -//} -// -// -//#pragma mark - Entities -// -//- (void)selectEntityView:(TGPhotoPaintEntityView *)view -//{ -// if (_editedTextView != nil) -// return; -// -// if (_currentEntityView != nil) -// { -// if (_currentEntityView == view) -// { -// [self showMenuForEntityView]; -// return; -// } -// -// [self _clearCurrentSelection]; -// } -// -// _currentEntityView = view; -// [self updateSettingsButton]; -// -// _scrollView.pinchGestureRecognizer.enabled = _currentEntityView == nil; -// -// if (view != nil) -// { -// [_currentEntityView.superview bringSubviewToFront:_currentEntityView]; -// } -// else -// { -// [self hideMenu]; -// return; -// } -// -// if ([view isKindOfClass:[TGPhotoTextEntityView class]]) -// { -// TGPaintSwatch *textSwatch = ((TGPhotoPaintTextEntity *)view.entity).swatch; -// [self setCurrentSwatch:[TGPaintSwatch swatchWithColor:textSwatch.color colorLocation:textSwatch.colorLocation brushWeight:_portraitSettingsView.swatch.brushWeight] sender:nil]; -// } -// -// _entitySelectionView = [view createSelectionView]; -// view.selectionView = _entitySelectionView; -// [_selectionContainerView addSubview:_entitySelectionView]; -// -// __weak TGPhotoPaintController *weakSelf = self; -// _entitySelectionView.entityResized = ^(CGFloat scale) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf->_entitySelectionView.entityView scale:scale absolute:true]; -// }; -// _entitySelectionView.entityRotated = ^(CGFloat angle) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf->_entitySelectionView.entityView rotate:angle absolute:true]; -// }; -// -// [_entitySelectionView update]; -//} -// -//- (void)deleteEntityView:(TGPhotoPaintEntityView *)view -//{ -// [_undoManager unregisterUndoWithUUID:view.entityUUID]; -// -// [view removeFromSuperview]; -// -// [self _clearCurrentSelection]; -// -// [self updateActionsView]; -// [self updateSettingsButton]; -//} -// -//- (void)duplicateEntityView:(TGPhotoPaintEntityView *)view -//{ -// TGPhotoPaintEntity *entity = [view.entity duplicate]; -// entity.position = [self startPositionRelativeToEntity:entity]; -// -// TGPhotoPaintEntityView *entityView = nil; -// if ([entity isKindOfClass:[TGPhotoPaintStickerEntity class]]) -// { -// TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; -// [self _commonEntityViewSetup:stickerView]; -// entityView = stickerView; -// } -// else -// { -// TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; -// [self _commonEntityViewSetup:textView]; -// entityView = textView; -// } -// -// [self selectEntityView:entityView]; -// [self _registerEntityRemovalUndo:entity]; -// [self updateActionsView]; -//} -// -//- (void)editEntityView:(TGPhotoPaintEntityView *)view -//{ -// if ([view isKindOfClass:[TGPhotoTextEntityView class]]) -// [(TGPhotoTextEntityView *)view beginEditing]; -//} -// -//#pragma mark Menu -// -//- (void)showMenuForEntityView -//{ -// if (_menuContainerView != nil) -// { -// TGMenuContainerView *container = _menuContainerView; -// bool isShowingMenu = container.isShowingMenu; -// _menuContainerView = nil; -// -// [container removeFromSuperview]; -// -// if (!isShowingMenu && container.menuView.userInfo[@"entity"] == _currentEntityView) -// { -// if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// [self editEntityView:_currentEntityView]; -// -// return; -// } -// } -// -// UIView *parentView = self.view; -// _menuContainerView = [[TGMenuContainerView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, parentView.frame.size.width, parentView.frame.size.height)]; -// [parentView addSubview:_menuContainerView]; -// -// NSArray *actions = nil; -// -// if ([_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]]) -// { -// actions = @ -// [ -// @{ @"title": TGLocalized(@"Paint.Delete"), @"action": @"delete" }, -// @{ @"title": TGLocalized(@"Paint.Duplicate"), @"action": @"duplicate" }, -// ]; -// } -// else -// { -// actions = @ -// [ -// @{ @"title": TGLocalized(@"Paint.Delete"), @"action": @"delete" }, -// @{ @"title": TGLocalized(@"Paint.Edit"), @"action": @"edit" }, -// @{ @"title": TGLocalized(@"Paint.Duplicate"), @"action": @"duplicate" }, -// ]; -// } -// -// [_menuContainerView.menuView setUserInfo:@{ @"entity": _currentEntityView }]; -// [_menuContainerView.menuView setButtonsAndActions:actions watcherHandle:_actionHandle]; -// [_menuContainerView.menuView sizeToFit]; -// -// CGRect sourceRect = CGRectOffset([_currentEntityView convertRect:_currentEntityView.bounds toView:_menuContainerView], 0, -15.0f); -// [_menuContainerView showMenuFromRect:sourceRect animated:false]; -//} -// -//- (void)hideMenu -//{ -// [_menuContainerView hideMenu]; -//} -// -//- (void)actionStageActionRequested:(NSString *)action options:(id)options -//{ -// if ([action isEqualToString:@"menuAction"]) -// { -// NSString *menuAction = options[@"action"]; -// TGPhotoPaintEntityView *entity = options[@"userInfo"][@"entity"]; -// -// if ([menuAction isEqualToString:@"delete"]) -// { -// [self deleteEntityView:entity]; -// } -// else if ([menuAction isEqualToString:@"duplicate"]) -// { -// [self duplicateEntityView:entity]; -// } -// else if ([menuAction isEqualToString:@"edit"]) -// { -// [self editEntityView:entity]; -// } -// } -// else if ([action isEqualToString:@"menuWillHide"]) -// { -// } -//} -// -//#pragma mark View -// -//- (CGPoint)centerPointFittedCropRect -//{ -// return [_previewView convertPoint:TGPaintCenterOfRect(_previewView.bounds) toView:_entitiesContainerView]; -//} -// -//- (CGFloat)startRotation -//{ -// return TGCounterRotationForOrientation(_photoEditor.cropOrientation) - _photoEditor.cropRotation; -//} -// -//- (CGPoint)startPositionRelativeToEntity:(TGPhotoPaintEntity *)entity -//{ -// const CGPoint offset = CGPointMake(200.0f, 200.0f); -// -// if (entity != nil) -// { -// return TGPaintAddPoints(entity.position, offset); -// } -// else -// { -// const CGFloat minimalDistance = 100.0f; -// CGPoint position = [self centerPointFittedCropRect]; -// -// while (true) -// { -// bool occupied = false; -// for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) -// { -// if (![view isKindOfClass:[TGPhotoPaintEntityView class]]) -// continue; -// -// CGPoint location = view.center; -// CGFloat distance = sqrt(pow(location.x - position.x, 2) + pow(location.y - position.y, 2)); -// if (distance < minimalDistance) -// occupied = true; -// } -// -// if (!occupied) -// break; -// else -// position = TGPaintAddPoints(position, offset); -// } -// -// return position; -// } -//} -// -//- (void)_commonEntityViewSetup:(TGPhotoPaintEntityView *)entityView -//{ -// [self hideMenu]; -// -// __weak TGPhotoPaintController *weakSelf = self; -// entityView.shouldTouchEntity = ^bool (__unused TGPhotoPaintEntityView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return false; -// -// return ![strongSelf->_canvasView isTracking] && ![strongSelf->_entitiesContainerView isTrackingAnyEntityView]; -// }; -// entityView.entityBeganDragging = ^(TGPhotoPaintEntityView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil && sender != strongSelf->_entitySelectionView.entityView) -// [strongSelf selectEntityView:sender]; -// }; -// entityView.entityChanged = ^(TGPhotoPaintEntityView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// if (sender == strongSelf->_entitySelectionView.entityView) -// [strongSelf->_entitySelectionView update]; -// -// [strongSelf updateActionsView]; -// }; -// -// if ([entityView isKindOfClass:[TGPhotoTextEntityView class]]) { -// TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)entityView; -// -// __weak TGPhotoPaintController *weakSelf = self; -// textView.beganEditing = ^(TGPhotoTextEntityView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf bringTextEntityViewFront:sender]; -// }; -// -// textView.finishedEditing = ^(__unused TGPhotoTextEntityView *sender) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// [strongSelf sendTextEntityViewBack]; -// }; -// } -//} -// -//- (void)_registerEntityRemovalUndo:(TGPhotoPaintEntity *)entity -//{ -// [_undoManager registerUndoWithUUID:entity.uuid block:^(__unused TGPainting *painting, TGPhotoEntitiesContainerView *entitiesContainer, NSInteger uuid) -// { -// [entitiesContainer removeViewWithUUID:uuid]; -// }]; -//} -// -//#pragma mark Stickers -// -// -//- (void)createNewStickerWithDocument:(id)document animated:(bool)animated transitionPoint:(CGPoint)transitionPoint snapshotView:(UIView *)snapshotView -//{ -// TGPhotoPaintStickerEntity *entity = [[TGPhotoPaintStickerEntity alloc] initWithDocument:document baseSize:[self _stickerBaseSizeForCurrentPainting] animated:animated]; -// [self _setStickerEntityPosition:entity]; -// -// -// TGPhotoStickerEntityView *stickerView = (TGPhotoStickerEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; -// -// bool hasStickers = false; -// TGPhotoStickerEntityView *existingStickerView; -// for (TGPhotoPaintEntityView *view in _entitiesContainerView.subviews) { -// if ([view isKindOfClass:[TGPhotoStickerEntityView class]]) { -// hasStickers = true; -// -// if (((TGPhotoStickerEntityView *)view).documentId == stickerView.documentId) { -// existingStickerView = (TGPhotoStickerEntityView *)view; -// } -// break; -// } -// } -// -// [_entitiesContainerView addSubview:stickerView]; -// [self _commonEntityViewSetup:stickerView]; -// -// __weak TGPhotoPaintController *weakSelf = self; -// stickerView.started = ^(double duration) { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) { -// TGPhotoEditorController *editorController = (TGPhotoEditorController *)strongSelf.parentViewController; -// if (![editorController isKindOfClass:[TGPhotoEditorController class]]) -// return; -// -// if (!hasStickers) { -// [editorController setMinimalVideoDuration:duration]; -// } -// } -// }; -// -// NSTimeInterval currentTime = NAN; -// NSTimeInterval stickerStartTime = _stickerStartTime; -// TGPhotoEditorController *editorController = (TGPhotoEditorController *)self.parentViewController; -// if ([editorController isKindOfClass:[TGPhotoEditorController class]]) { -// currentTime = editorController.currentTime; -// } -// -// if (!isnan(currentTime)) { -// [stickerView seekTo:currentTime]; -// [stickerView play]; -// } else { -// NSTimeInterval currentTime = CACurrentMediaTime(); -// if (!isnan(stickerStartTime)) { -// if (existingStickerView != nil) { -// [stickerView copyStickerView:existingStickerView]; -// } else { -// NSTimeInterval position = currentTime - stickerStartTime; -// [stickerView seekTo:position]; -// [stickerView play]; -// } -// } else { -// _stickerStartTime = currentTime; -// [stickerView play]; -// } -// } -// -// [self selectEntityView:stickerView]; -// _entitySelectionView.alpha = 0.0f; -// -// [_entitySelectionView fadeIn]; -// -// [self _registerEntityRemovalUndo:entity]; -// [self updateActionsView]; -//} -// -//- (void)mirrorSelectedStickerEntity -//{ -// if ([_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]]) -// [((TGPhotoStickerEntityView *)_currentEntityView) mirror]; -//} -// -//#pragma mark Text -// -//- (void)createNewTextLabel -//{ -// TGPaintSwatch *currentSwatch = _portraitSettingsView.swatch; -// TGPaintSwatch *whiteSwatch = [TGPaintSwatch swatchWithColor:UIColorRGB(0xffffff) colorLocation:1.0f brushWeight:currentSwatch.brushWeight]; -// TGPaintSwatch *blackSwatch = [TGPaintSwatch swatchWithColor:UIColorRGB(0x000000) colorLocation:0.85f brushWeight:currentSwatch.brushWeight]; -// [self setCurrentSwatch:_selectedTextStyle == TGPhotoPaintTextEntityStyleOutlined ? 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 style:_selectedTextStyle]; -// entity.position = [self startPositionRelativeToEntity:nil]; -// entity.angle = [self startRotation]; -// -// TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)[_entitiesContainerView createEntityViewWithEntity:entity]; -// [_entitiesContainerView addSubview:textView]; -// [self _commonEntityViewSetup:textView]; -// -// [self selectEntityView:textView]; -// -// [self _registerEntityRemovalUndo:entity]; -// [self updateActionsView]; -// -// [textView beginEditing]; -//} -// -//- (void)bringTextEntityViewFront:(TGPhotoTextEntityView *)entityView -//{ -// _editedTextView = entityView; -// entityView.inhibitGestures = true; -// -// [_dimView.superview insertSubview:_dimView belowSubview:entityView]; -// -// _textEditingDismissButton = [[UIButton alloc] initWithFrame:_dimView.bounds]; -// _dimView.userInteractionEnabled = true; -// [_textEditingDismissButton addTarget:self action:@selector(_dismissButtonTapped) forControlEvents:UIControlEventTouchUpInside]; -// [_dimView addSubview:_textEditingDismissButton]; -// -// _editedTextCenter = entityView.center; -// _editedTextTransform = entityView.transform; -// -// _entitySelectionView.alpha = 0.0f; -// -// void (^changeBlock)(void) = ^ -// { -// entityView.center = [self centerPointFittedCropRect]; -// entityView.transform = CGAffineTransformMakeRotation([self startRotation]); -// -// _dimView.alpha = 1.0f; -// }; -// -// _contentView.userInteractionEnabled = true; -// _contentWrapperView.userInteractionEnabled = true; -// -// if (iosMajorVersion() >= 7) -// { -// [UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.8f initialSpringVelocity:0.0f options:kNilOptions animations:changeBlock completion:nil]; -// } -// else -// { -// [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:changeBlock completion:nil]; -// } -// -// [self setInterfaceHidden:true animated:true]; -//} -// -//- (void)_dismissButtonTapped -//{ -// TGPhotoTextEntityView *entityView = _editedTextView; -// [entityView endEditing]; -//} -// -//- (void)sendTextEntityViewBack -//{ -// _contentView.userInteractionEnabled = false; -// _contentWrapperView.userInteractionEnabled = false; -// -// _dimView.userInteractionEnabled = false; -// [_textEditingDismissButton removeFromSuperview]; -// _textEditingDismissButton = nil; -// -// TGPhotoTextEntityView *entityView = _editedTextView; -// _editedTextView = nil; -// -// void (^changeBlock)(void) = ^ -// { -// entityView.center = _editedTextCenter; -// entityView.transform = _editedTextTransform; -// _dimView.alpha = 0.0f; -// }; -// -// void (^completionBlock)(BOOL) = ^(__unused BOOL finished) -// { -// [_dimView.superview bringSubviewToFront:_dimView]; -// entityView.inhibitGestures = false; -// -// if (entityView.isEmpty) -// { -// [self deleteEntityView:entityView]; -// } -// else -// { -// [_entitySelectionView update]; -// [_entitySelectionView fadeIn]; -// } -// }; -// -// if (iosMajorVersion() >= 7) -// { -// [UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.8f initialSpringVelocity:0.0f options:kNilOptions animations:changeBlock completion:completionBlock]; -// } -// else -// { -// [UIView animateWithDuration:0.35 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:changeBlock completion:completionBlock]; -// } -// -// [self setInterfaceHidden:false animated:true]; -// -// TGMenuContainerView *container = _menuContainerView; -// _menuContainerView = nil; -// [container removeFromSuperview]; -//} -// -//- (void)containerPressed -//{ -// if (_currentEntityView == nil) -// return; -// -// if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// { -// TGPhotoTextEntityView *textEntityView = (TGPhotoTextEntityView *)_currentEntityView; -// if ([textEntityView isEditing]) -// { -// [textEntityView endEditing]; -// return; -// } -// } -// [self selectEntityView:nil]; -//} -// -//#pragma mark - Relative Size Calculation -// -//- (CGSize)_stickerBaseSizeForCurrentPainting -//{ -// CGSize fittedSize = [self fittedContentSize]; -// CGFloat maxSide = MAX(fittedSize.width, fittedSize.height); -// CGFloat side = ceil(maxSide * 0.3125f); -// return CGSizeMake(side, side); -//} -// -//- (CGFloat)_textBaseFontSizeForCurrentPainting -//{ -// CGSize fittedSize = [self fittedContentSize]; -// CGFloat maxSide = MAX(fittedSize.width, fittedSize.height); -// return ceil(maxSide * 0.08f); -//} -// -//- (CGFloat)_brushBaseWeightForCurrentPainting -//{ -// return 15.0f / TGPhotoPaintingMaxSize.width * _painting.size.width; -//} -// -//- (CGFloat)_brushWeightRangeForCurrentPainting -//{ -// return 125.0f / TGPhotoPaintingMaxSize.width * _painting.size.width; -//} -// -//- (CGFloat)_brushWeightForSize:(CGFloat)size -//{ -// CGFloat scale = MAX(0.001, _scrollView.zoomScale); -// return ([self _brushBaseWeightForCurrentPainting] + [self _brushWeightRangeForCurrentPainting] * size) / scale; -//} -// -//+ (CGSize)maximumPaintingSize -//{ -// static dispatch_once_t onceToken; -// static CGSize size; -// dispatch_once(&onceToken, ^ -// { -// CGSize screenSize = TGScreenSize(); -// if ((NSInteger)screenSize.height == 480) -// size = TGPhotoPaintingLightMaxSize; -// else -// size = TGPhotoPaintingMaxSize; -// }); -// return size; -//} -// -//#pragma mark - Settings -// -//- (void)setCurrentSwatch:(TGPaintSwatch *)swatch sender:(id)sender -//{ -// [_canvasView setBrushColor:swatch.color]; -// [_canvasView setBrushWeight:[self _brushWeightForSize:swatch.brushWeight]]; -// if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// [(TGPhotoTextEntityView *)_currentEntityView setSwatch:swatch]; -// -// if (sender != _landscapeSettingsView) -// [_landscapeSettingsView setSwatch:swatch]; -// -// if (sender != _portraitSettingsView) -// [_portraitSettingsView setSwatch:swatch]; -//} -// -//- (void)updateSettingsButton -//{ -// if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) { -// TGPhotoPaintSettingsViewIcon icon; -// switch (((TGPhotoTextEntityView *)_currentEntityView).entity.style) { -// case TGPhotoPaintTextEntityStyleRegular: -// icon = TGPhotoPaintSettingsViewIconTextRegular; -// break; -// case TGPhotoPaintTextEntityStyleOutlined: -// icon = TGPhotoPaintSettingsViewIconTextOutlined; -// break; -// case TGPhotoPaintTextEntityStyleFramed: -// icon = TGPhotoPaintSettingsViewIconTextFramed; -// break; -// } -// [self setSettingsButtonIcon:icon]; -// } -// else if ([_currentEntityView isKindOfClass:[TGPhotoStickerEntityView class]]) { -// [self setSettingsButtonIcon:TGPhotoPaintSettingsViewIconMirror]; -// } -// else { -// TGPhotoPaintSettingsViewIcon icon = TGPhotoPaintSettingsViewIconBrushPen; -// if ([_canvasView.state.brush isKindOfClass:[TGPaintEllipticalBrush class]]) { -// icon = TGPhotoPaintSettingsViewIconBrushMarker; -// } else if ([_canvasView.state.brush isKindOfClass:[TGPaintNeonBrush class]]) { -// icon = TGPhotoPaintSettingsViewIconBrushNeon; -// } else if ([_canvasView.state.brush isKindOfClass:[TGPaintArrowBrush class]]) { -// icon = TGPhotoPaintSettingsViewIconBrushArrow; -// } -// [self setSettingsButtonIcon:icon]; -// } -// [self _updateTabs]; -//} -// -//- (void)setSettingsButtonIcon:(TGPhotoPaintSettingsViewIcon)icon -//{ -// [_portraitSettingsView setIcon:icon animated:true]; -// [_landscapeSettingsView setIcon:icon animated:true]; -//} -// -//- (void)settingsWrapperPressed -//{ -// [_settingsView dismissWithCompletion:^ -// { -// [_settingsView removeFromSuperview]; -// _settingsView = nil; -// -// [_settingsViewWrapper removeFromSuperview]; -// }]; -//} -// -//- (UIView *)settingsViewWrapper -//{ -// if (_settingsViewWrapper == nil) -// { -// _settingsViewWrapper = [[TGPhotoPaintSettingsWrapperView alloc] initWithFrame:self.parentViewController.view.bounds]; -// _settingsViewWrapper.exclusiveTouch = true; -// -// __weak TGPhotoPaintController *weakSelf = self; -// _settingsViewWrapper.pressed = ^(__unused CGPoint location) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf != nil) -// [strongSelf settingsWrapperPressed]; -// }; -// _settingsViewWrapper.suppressTouchAtPoint = ^bool(CGPoint location) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return false; -// -// UIView *view = [strongSelf.view hitTest:[strongSelf.view convertPoint:location fromView:nil] withEvent:nil]; -// if ([view isKindOfClass:[TGModernButton class]]) -// return true; -// -// if ([view isKindOfClass:[TGPaintCanvas class]]) -// return true; -// -// if (view == strongSelf->_portraitToolsWrapperView || view == strongSelf->_landscapeToolsWrapperView) -// return true; -// -// return false; -// }; -// } -// -// [self.parentViewController.view addSubview:_settingsViewWrapper]; -// -// return _settingsViewWrapper; -//} -// -//- (TGPaintBrushPreview *)brushPreview -//{ -// if ([_brushes.firstObject previewImage] != nil) -// return nil; -// -// if (_brushPreview == nil) -// _brushPreview = [[TGPaintBrushPreview alloc] init]; -// -// return _brushPreview; -//} -// -//- (void)presentBrushSettingsView -//{ -// TGPhotoBrushSettingsView *view = [[TGPhotoBrushSettingsView alloc] initWithBrushes:_brushes preview:[self brushPreview]]; -// [view setBrush:_painting.brush]; -// -// __weak TGPhotoPaintController *weakSelf = self; -// view.brushChanged = ^(TGPaintBrush *brush) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// if (strongSelf->_canvasView.state.eraser && (brush.lightSaber || brush.arrow)) -// brush = strongSelf->_brushes.firstObject; -// -// [strongSelf->_canvasView setBrush:brush]; -// -// [strongSelf settingsWrapperPressed]; -// [strongSelf updateSettingsButton]; -// }; -// _settingsView = view; -// [view sizeToFit]; -// -// UIView *wrapper = [self settingsViewWrapper]; -// wrapper.userInteractionEnabled = true; -// [wrapper addSubview:view]; -// -// [self viewWillLayoutSubviews]; -// -// [view present]; -//} -// -//- (void)presentTextSettingsView -//{ -// TGPhotoTextSettingsView *view = [[TGPhotoTextSettingsView alloc] initWithFonts:[TGPhotoPaintFont availableFonts] selectedFont:_selectedTextFont selectedStyle:_selectedTextStyle]; -// -// __weak TGPhotoPaintController *weakSelf = self; -// view.fontChanged = ^(TGPhotoPaintFont *font) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// strongSelf->_selectedTextFont = font; -// -// TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)strongSelf->_currentEntityView; -// [textView setFont:font]; -// -// [strongSelf settingsWrapperPressed]; -// [strongSelf updateSettingsButton]; -// }; -// view.styleChanged = ^(TGPhotoPaintTextEntityStyle style) -// { -// __strong TGPhotoPaintController *strongSelf = weakSelf; -// if (strongSelf == nil) -// return; -// -// strongSelf->_selectedTextStyle = style; -// -// if (style == TGPhotoPaintTextEntityStyleOutlined && [strongSelf->_portraitSettingsView.swatch.color isEqual:UIColorRGB(0xffffff)]) -// { -// TGPaintSwatch *currentSwatch = strongSelf->_portraitSettingsView.swatch; -// TGPaintSwatch *blackSwatch = [TGPaintSwatch swatchWithColor:UIColorRGB(0x000000) colorLocation:0.85f brushWeight:currentSwatch.brushWeight]; -// [strongSelf setCurrentSwatch:blackSwatch sender:nil]; -// } -// else if (style != TGPhotoPaintTextEntityStyleOutlined && [strongSelf->_portraitSettingsView.swatch.color isEqual:UIColorRGB(0x000000)]) -// { -// TGPaintSwatch *currentSwatch = strongSelf->_portraitSettingsView.swatch; -// TGPaintSwatch *whiteSwatch = [TGPaintSwatch swatchWithColor:UIColorRGB(0xffffff) colorLocation:1.0f brushWeight:currentSwatch.brushWeight]; -// [strongSelf setCurrentSwatch:whiteSwatch sender:nil]; -// } -// -// TGPhotoTextEntityView *textView = (TGPhotoTextEntityView *)strongSelf->_currentEntityView; -// [textView setStyle:style]; -// -// [strongSelf settingsWrapperPressed]; -// [strongSelf updateSettingsButton]; -// }; -// -// _settingsView = view; -// [view sizeToFit]; -// -// UIView *wrapper = [self settingsViewWrapper]; -// wrapper.userInteractionEnabled = true; -// [wrapper addSubview:view]; -// -// [self viewWillLayoutSubviews]; -// -// [view present]; -//} -// -//- (void)toggleEraserMode -//{ -// _canvasView.state.eraser = !_canvasView.state.isEraser; -// -// if (_canvasView.state.eraser) -// { -// if (_canvasView.state.brush.lightSaber || _canvasView.state.brush.arrow) -// [_canvasView setBrush:_brushes.firstObject]; -// } -// -// [_portraitSettingsView setHighlighted:_canvasView.state.isEraser]; -// [_landscapeSettingsView setHighlighted:_canvasView.state.isEraser]; -// -// [self updateSettingsButton]; -// [self _updateTabs]; -//} -// -//#pragma mark - Scroll View -// -//- (CGSize)fittedContentSize -//{ -// return [TGPhotoPaintController fittedContentSize:_photoEditor.cropRect orientation:_photoEditor.cropOrientation originalSize:_photoEditor.originalSize]; -//} -// -//+ (CGSize)fittedContentSize:(CGRect)cropRect orientation:(UIImageOrientation)orientation originalSize:(CGSize)originalSize { -// CGSize fittedOriginalSize = TGScaleToSize(originalSize, [TGPhotoPaintController maximumPaintingSize]); -// CGFloat scale = fittedOriginalSize.width / originalSize.width; -// -// CGSize size = CGSizeMake(cropRect.size.width * scale, cropRect.size.height * scale); -// if (orientation == UIImageOrientationLeft || orientation == UIImageOrientationRight) -// size = CGSizeMake(size.height, size.width); -// -// return CGSizeMake(floor(size.width), floor(size.height)); -//} -// -//- (CGRect)fittedCropRect:(bool)originalSize -//{ -// return [TGPhotoPaintController fittedCropRect:_photoEditor.cropRect originalSize:_photoEditor.originalSize keepOriginalSize:originalSize]; -//} -// -//+ (CGRect)fittedCropRect:(CGRect)cropRect originalSize:(CGSize)originalSize keepOriginalSize:(bool)keepOriginalSize { -// CGSize fittedOriginalSize = TGScaleToSize(originalSize, [TGPhotoPaintController maximumPaintingSize]); -// CGFloat scale = fittedOriginalSize.width / originalSize.width; -// -// CGSize size = fittedOriginalSize; -// if (!keepOriginalSize) -// size = CGSizeMake(cropRect.size.width * scale, cropRect.size.height * scale); -// -// return CGRectMake(-cropRect.origin.x * scale, -cropRect.origin.y * scale, size.width, size.height); -//} -// -//- (CGPoint)fittedCropCenterScale:(CGFloat)scale -//{ -// return [TGPhotoPaintController fittedCropRect:_photoEditor.cropRect centerScale:scale]; -//} -// -//+ (CGPoint)fittedCropRect:(CGRect)cropRect centerScale:(CGFloat)scale -//{ -// CGSize size = CGSizeMake(cropRect.size.width * scale, cropRect.size.height * scale); -// CGRect rect = CGRectMake(cropRect.origin.x * scale, cropRect.origin.y * scale, size.width, size.height); -// -// return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)); -//} -// -//- (void)resetScrollView -//{ -// CGSize fittedContentSize = [self fittedContentSize]; -// CGRect fittedCropRect = [self fittedCropRect:false]; -// _contentWrapperView.frame = CGRectMake(0.0f, 0.0f, fittedContentSize.width, fittedContentSize.height); -// -// CGFloat scale = _contentView.bounds.size.width / fittedCropRect.size.width; -// _contentWrapperView.transform = CGAffineTransformMakeScale(scale, scale); -// _contentWrapperView.frame = CGRectMake(0.0f, 0.0f, _contentView.bounds.size.width, _contentView.bounds.size.height); -// -// CGSize contentSize = [self contentSize]; -// _scrollView.minimumZoomScale = 1.0f; -// _scrollView.maximumZoomScale = 1.0f; -// _scrollView.normalZoomScale = 1.0f; -// _scrollView.zoomScale = 1.0f; -// _scrollView.contentSize = contentSize; -// [self contentView].frame = CGRectMake(0.0f, 0.0f, contentSize.width, contentSize.height); -// -// [self adjustZoom]; -// _scrollView.zoomScale = _scrollView.normalZoomScale; -//} -// -//- (void)scrollViewWillBeginZooming:(UIScrollView *)__unused scrollView withView:(UIView *)__unused view -//{ -//} -// -//- (void)scrollViewDidZoom:(UIScrollView *)__unused scrollView -//{ -// [self adjustZoom]; -//} -// -//- (void)scrollViewDidEndZooming:(UIScrollView *)__unused scrollView withView:(UIView *)__unused view atScale:(CGFloat)__unused scale -//{ -// [self adjustZoom]; -// -// TGPaintSwatch *currentSwatch = _portraitSettingsView.swatch; -// [_canvasView setBrushWeight:[self _brushWeightForSize:currentSwatch.brushWeight]]; -// -// if (_scrollView.zoomScale < _scrollView.normalZoomScale - FLT_EPSILON) -// { -// [TGHacks setAnimationDurationFactor:0.5f]; -// [_scrollView setZoomScale:_scrollView.normalZoomScale animated:true]; -// [TGHacks setAnimationDurationFactor:1.0f]; -// } -//} -// -//- (UIView *)contentView -//{ -// return _scrollContentView; -//} -// -//- (CGSize)contentSize -//{ -// return _scrollView.frame.size; -//} -// -//- (UIView *)viewForZoomingInScrollView:(UIScrollView *)__unused scrollView -//{ -// return [self contentView]; -//} -// -//- (void)adjustZoom -//{ -// CGSize contentSize = [self contentSize]; -// CGSize boundsSize = _scrollView.frame.size; -// if (contentSize.width < FLT_EPSILON || contentSize.height < FLT_EPSILON || boundsSize.width < FLT_EPSILON || boundsSize.height < FLT_EPSILON) -// return; -// -// CGFloat scaleWidth = boundsSize.width / contentSize.width; -// CGFloat scaleHeight = boundsSize.height / contentSize.height; -// CGFloat minScale = MIN(scaleWidth, scaleHeight); -// CGFloat maxScale = MAX(scaleWidth, scaleHeight); -// maxScale = MAX(maxScale, minScale * 3.0f); -// -// if (ABS(maxScale - minScale) < 0.01f) -// maxScale = minScale; -// -// _scrollView.contentInset = UIEdgeInsetsZero; -// -// if (_scrollView.minimumZoomScale != 0.05f) -// _scrollView.minimumZoomScale = 0.05f; -// if (_scrollView.normalZoomScale != minScale) -// _scrollView.normalZoomScale = minScale; -// if (_scrollView.maximumZoomScale != maxScale) -// _scrollView.maximumZoomScale = maxScale; -// -// CGRect contentFrame = [self contentView].frame; -// -// if (boundsSize.width > contentFrame.size.width) -// contentFrame.origin.x = (boundsSize.width - contentFrame.size.width) / 2.0f; -// else -// contentFrame.origin.x = 0; -// -// if (boundsSize.height > contentFrame.size.height) -// contentFrame.origin.y = (boundsSize.height - contentFrame.size.height) / 2.0f; -// else -// contentFrame.origin.y = 0; -// -// [self contentView].frame = contentFrame; -// -// _scrollView.scrollEnabled = ABS(_scrollView.zoomScale - _scrollView.normalZoomScale) > FLT_EPSILON; -//} -// -//#pragma mark - Gestures -// -//- (void)handlePinch:(UIPinchGestureRecognizer *)gestureRecognizer -//{ -// [_entitiesContainerView handlePinch:gestureRecognizer]; -//} -// -//- (void)handleRotate:(UIRotationGestureRecognizer *)gestureRecognizer -//{ -// [_entitiesContainerView handleRotate:gestureRecognizer]; -//} -// -//- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)__unused gestureRecognizer -//{ -// if (gestureRecognizer == _pinchGestureRecognizer && _currentEntityView == nil) { -// return false; -// } -// return !_canvasView.isTracking; -//} -// -//- (BOOL)gestureRecognizer:(UIGestureRecognizer *)__unused gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)__unused otherGestureRecognizer -//{ -// return true; -//} -// -//#pragma mark - Transitions -// -//- (void)transitionIn -//{ -// _portraitSettingsView.layer.shouldRasterize = true; -// _landscapeSettingsView.layer.shouldRasterize = true; -// -// [UIView animateWithDuration:0.3f animations:^ -// { -// _portraitToolsWrapperView.alpha = 1.0f; -// _landscapeToolsWrapperView.alpha = 1.0f; -// -// _portraitActionsView.alpha = 1.0f; -// _landscapeActionsView.alpha = 1.0f; -// } completion:^(__unused BOOL finished) -// { -// _portraitSettingsView.layer.shouldRasterize = false; -// _landscapeSettingsView.layer.shouldRasterize = false; -// }]; -// -// if (self.presentedForAvatarCreation) { -// _canvasView.hidden = true; -// } -//} -// -//+ (CGRect)photoContainerFrameForParentViewFrame:(CGRect)parentViewFrame toolbarLandscapeSize:(CGFloat)toolbarLandscapeSize orientation:(UIInterfaceOrientation)orientation panelSize:(CGFloat)panelSize hasOnScreenNavigation:(bool)hasOnScreenNavigation -//{ -// CGRect frame = [TGPhotoEditorTabController photoContainerFrameForParentViewFrame:parentViewFrame toolbarLandscapeSize:toolbarLandscapeSize orientation:orientation panelSize:panelSize hasOnScreenNavigation:hasOnScreenNavigation]; -// -// switch (orientation) -// { -// case UIInterfaceOrientationLandscapeLeft: -// frame.origin.x -= TGPhotoPaintTopPanelSize; -// break; -// -// case UIInterfaceOrientationLandscapeRight: -// frame.origin.x += TGPhotoPaintTopPanelSize; -// break; -// -// default: -// frame.origin.y += TGPhotoPaintTopPanelSize; -// break; -// } -// -// return frame; -//} -// -//- (CGRect)_targetFrameForTransitionInFromFrame:(CGRect)fromFrame -//{ -// CGSize referenceSize = [self referenceViewSize]; -// CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation]; -// -// CGSize fittedSize = TGScaleToSize(fromFrame.size, containerFrame.size); -// CGRect toFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); -// -// return toFrame; -//} -// -//- (void)_finishedTransitionInWithView:(UIView *)transitionView -//{ -// _appeared = true; -// -// if ([transitionView isKindOfClass:[TGPhotoEditorPreviewView class]]) { -// -// } else { -// [transitionView removeFromSuperview]; -// } -// -// [self setupCanvas]; -// _entitiesContainerView.hidden = false; -// -// TGPhotoEditorPreviewView *previewView = _previewView; -// [previewView setPaintingHidden:true]; -// previewView.hidden = false; -// [_containerView insertSubview:previewView belowSubview:_paintingWrapperView]; -// [self updateContentViewLayout]; -// [previewView performTransitionInIfNeeded]; -// -// CGRect rect = [self fittedCropRect:true]; -// _entitiesContainerView.frame = CGRectMake(0, 0, rect.size.width, rect.size.height); -// _entitiesContainerView.transform = CGAffineTransformMakeRotation(_photoEditor.cropRotation); -// -// CGSize fittedOriginalSize = TGScaleToSize(_photoEditor.originalSize, [TGPhotoPaintController maximumPaintingSize]); -// CGSize rotatedSize = TGRotatedContentSize(fittedOriginalSize, _photoEditor.cropRotation); -// CGPoint centerPoint = CGPointMake(rotatedSize.width / 2.0f, rotatedSize.height / 2.0f); -// -// CGFloat scale = fittedOriginalSize.width / _photoEditor.originalSize.width; -// CGPoint offset = TGPaintSubtractPoints(centerPoint, [self fittedCropCenterScale:scale]); -// -// CGPoint boundsCenter = TGPaintCenterOfRect(_contentWrapperView.bounds); -// _entitiesContainerView.center = TGPaintAddPoints(boundsCenter, offset); -// -// if (!_skipEntitiesSetup || _entitiesReady) { -// [_contentWrapperView addSubview:_entitiesContainerView]; -// } -// _entitiesReady = true; -// [self resetScrollView]; -//} -// -//- (void)prepareForCustomTransitionOut -//{ -// _previewView.hidden = true; -// _canvasView.hidden = true; -// _contentView.hidden = true; -// [UIView animateWithDuration:0.3f animations:^ -// { -// _portraitToolsWrapperView.alpha = 0.0f; -// _landscapeToolsWrapperView.alpha = 0.0f; -// } completion:nil]; -//} -// -//- (void)transitionOutSwitching:(bool)__unused switching completion:(void (^)(void))completion -//{ -// [_stickersScreen invalidate]; -// -// TGPhotoEditorPreviewView *previewView = self.previewView; -// previewView.interactionEnded = nil; -// -// _portraitSettingsView.layer.shouldRasterize = true; -// _landscapeSettingsView.layer.shouldRasterize = true; -// -// [UIView animateWithDuration:0.3f animations:^ -// { -// _portraitToolsWrapperView.alpha = 0.0f; -// _landscapeToolsWrapperView.alpha = 0.0f; -// -// _portraitActionsView.alpha = 0.0f; -// _landscapeActionsView.alpha = 0.0f; -// } completion:^(__unused BOOL finished) -// { -// if (completion != nil) -// completion(); -// }]; -//} -// -//- (CGRect)transitionOutSourceFrameForReferenceFrame:(CGRect)referenceFrame orientation:(UIInterfaceOrientation)orientation -//{ -// CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation]; -// -// CGSize fittedSize = TGScaleToSize(referenceFrame.size, containerFrame.size); -// return CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); -//} -// -//- (void)_animatePreviewViewTransitionOutToFrame:(CGRect)targetFrame saving:(bool)saving parentView:(UIView *)parentView completion:(void (^)(void))completion -//{ -// _dismissing = true; -// -// [_entitySelectionView removeFromSuperview]; -// _entitySelectionView = nil; -// -// TGPhotoEditorPreviewView *previewView = self.previewView; -// [previewView prepareForTransitionOut]; -// -// UIInterfaceOrientation orientation = self.effectiveOrientation; -// CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:self.view.frame toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation]; -// CGRect referenceFrame = CGRectMake(0, 0, self.photoEditor.rotatedCropSize.width, self.photoEditor.rotatedCropSize.height); -// CGRect rect = CGRectOffset([self transitionOutSourceFrameForReferenceFrame:referenceFrame orientation:orientation], -containerFrame.origin.x, -containerFrame.origin.y); -// previewView.frame = rect; -// -// UIView *snapshotView = nil; -// POPSpringAnimation *snapshotAnimation = nil; -// NSMutableArray *animations = [[NSMutableArray alloc] init]; -// -// if (saving && CGRectIsNull(targetFrame) && parentView != nil) -// { -// snapshotView = [previewView snapshotViewAfterScreenUpdates:false]; -// snapshotView.frame = [_containerView convertRect:previewView.frame toView:parentView]; -// -// UIView *canvasSnapshotView = [_paintingWrapperView resizableSnapshotViewFromRect:[_paintingWrapperView convertRect:previewView.bounds fromView:previewView] afterScreenUpdates:false withCapInsets:UIEdgeInsetsZero]; -// canvasSnapshotView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; -// canvasSnapshotView.transform = _contentView.transform; -// canvasSnapshotView.frame = snapshotView.bounds; -// [snapshotView addSubview:canvasSnapshotView]; -// -// UIView *entitiesSnapshotView = [_contentWrapperView resizableSnapshotViewFromRect:[_contentWrapperView convertRect:previewView.bounds fromView:previewView] afterScreenUpdates:false withCapInsets:UIEdgeInsetsZero]; -// entitiesSnapshotView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; -// entitiesSnapshotView.transform = _contentView.transform; -// entitiesSnapshotView.frame = snapshotView.bounds; -// [snapshotView addSubview:entitiesSnapshotView]; -// -// CGSize fittedSize = TGScaleToSize(previewView.frame.size, self.view.frame.size); -// targetFrame = CGRectMake((self.view.frame.size.width - fittedSize.width) / 2, (self.view.frame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); -// -// [parentView addSubview:snapshotView]; -// -// snapshotAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewFrame]; -// snapshotAnimation.fromValue = [NSValue valueWithCGRect:snapshotView.frame]; -// snapshotAnimation.toValue = [NSValue valueWithCGRect:targetFrame]; -// [animations addObject:snapshotAnimation]; -// } -// -// targetFrame = CGRectOffset(targetFrame, -containerFrame.origin.x, -containerFrame.origin.y); -// CGPoint targetCenter = TGPaintCenterOfRect(targetFrame); -// -// POPSpringAnimation *previewAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewFrame]; -// previewAnimation.fromValue = [NSValue valueWithCGRect:previewView.frame]; -// previewAnimation.toValue = [NSValue valueWithCGRect:targetFrame]; -// [animations addObject:previewAnimation]; -// -// POPSpringAnimation *previewAlphaAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewAlpha]; -// previewAlphaAnimation.fromValue = @(previewView.alpha); -// previewAlphaAnimation.toValue = @(0.0f); -// [animations addObject:previewAnimation]; -// -// POPSpringAnimation *entitiesAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewCenter]; -// entitiesAnimation.fromValue = [NSValue valueWithCGPoint:_contentView.center]; -// entitiesAnimation.toValue = [NSValue valueWithCGPoint:targetCenter]; -// [animations addObject:entitiesAnimation]; -// -// CGFloat targetEntitiesScale = targetFrame.size.width / _contentView.frame.size.width; -// POPSpringAnimation *entitiesScaleAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewScaleXY]; -// entitiesScaleAnimation.fromValue = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)]; -// entitiesScaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(targetEntitiesScale, targetEntitiesScale)]; -// [animations addObject:entitiesScaleAnimation]; -// -// POPSpringAnimation *entitiesAlphaAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewAlpha]; -// entitiesAlphaAnimation.fromValue = @(_canvasView.alpha); -// entitiesAlphaAnimation.toValue = @(0.0f); -// [animations addObject:entitiesAlphaAnimation]; -// -// POPSpringAnimation *paintingAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewCenter]; -// paintingAnimation.fromValue = [NSValue valueWithCGPoint:_paintingWrapperView.center]; -// paintingAnimation.toValue = [NSValue valueWithCGPoint:targetCenter]; -// [animations addObject:paintingAnimation]; -// -// CGFloat targetPaintingScale = targetFrame.size.width / _paintingWrapperView.frame.size.width; -// POPSpringAnimation *paintingScaleAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewScaleXY]; -// paintingScaleAnimation.fromValue = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)]; -// paintingScaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(targetPaintingScale, targetPaintingScale)]; -// [animations addObject:paintingScaleAnimation]; -// -// POPSpringAnimation *paintingAlphaAnimation = [TGPhotoEditorAnimation prepareTransitionAnimationForPropertyNamed:kPOPViewAlpha]; -// paintingAlphaAnimation.fromValue = @(_paintingWrapperView.alpha); -// paintingAlphaAnimation.toValue = @(0.0f); -// [animations addObject:paintingAlphaAnimation]; -// -// [TGPhotoEditorAnimation performBlock:^(__unused bool allFinished) -// { -// [snapshotView removeFromSuperview]; -// -// if (completion != nil) -// completion(); -// } whenCompletedAllAnimations:animations]; -// -// if (snapshotAnimation != nil) -// [snapshotView pop_addAnimation:snapshotAnimation forKey:@"frame"]; -// [previewView pop_addAnimation:previewAnimation forKey:@"frame"]; -// [previewView pop_addAnimation:previewAlphaAnimation forKey:@"alpha"]; -// -// [_contentView pop_addAnimation:entitiesAnimation forKey:@"frame"]; -// [_contentView pop_addAnimation:entitiesScaleAnimation forKey:@"scale"]; -// [_contentView pop_addAnimation:entitiesAlphaAnimation forKey:@"alpha"]; -// -// [_paintingWrapperView pop_addAnimation:paintingAnimation forKey:@"frame"]; -// [_paintingWrapperView pop_addAnimation:paintingScaleAnimation forKey:@"scale"]; -// [_paintingWrapperView pop_addAnimation:paintingAlphaAnimation forKey:@"alpha"]; -// -// if (saving) -// { -// _contentView.hidden = true; -// _paintingWrapperView.hidden = true; -// previewView.hidden = true; -// } -//} -// -//- (CGRect)transitionOutReferenceFrame -//{ -// TGPhotoEditorPreviewView *previewView = _previewView; -// return [previewView convertRect:previewView.bounds toView:self.view]; -//} -// -//- (UIView *)transitionOutReferenceView -//{ -// return _previewView; -//} -// -//- (UIView *)snapshotView -//{ -// TGPhotoEditorPreviewView *previewView = self.previewView; -// return [previewView originalSnapshotView]; -//} -// -//- (void)setInterfaceHidden:(bool)hidden animated:(bool)animated -//{ -// CGFloat targetAlpha = hidden ? 0.0f : 1.0; -// void (^changeBlock)(void) = ^ -// { -// _portraitActionsView.alpha = targetAlpha; -// _landscapeActionsView.alpha = targetAlpha; -// _portraitSettingsView.alpha = targetAlpha; -// _landscapeSettingsView.alpha = targetAlpha; -// }; -// -// if (animated) -// [UIView animateWithDuration:0.25 animations:changeBlock]; -// else -// changeBlock(); -// -// TGPhotoEditorController *editorController = (TGPhotoEditorController *)self.parentViewController; -// if (![editorController isKindOfClass:[TGPhotoEditorController class]]) -// return; -// -// [editorController setToolbarHidden:hidden animated:animated]; -//} -// -//- (void)setDimHidden:(bool)hidden animated:(bool)animated -//{ -// if (!hidden) -// { -// [_entitySelectionView fadeOut]; -// -// if ([_currentEntityView isKindOfClass:[TGPhotoTextEntityView class]]) -// [_dimView.superview insertSubview:_dimView belowSubview:_currentEntityView]; -// else -// [_dimView.superview bringSubviewToFront:_dimView]; -// -// [_doneButton.superview bringSubviewToFront:_doneButton]; -// } -// else -// { -// [_entitySelectionView fadeIn]; -// -// [_dimView.superview bringSubviewToFront:_dimView]; -// -// [_doneButton.superview bringSubviewToFront:_doneButton]; -// } -// -// void (^changeBlock)(void) = ^ -// { -// _dimView.alpha = hidden ? 0.0f : 1.0f; -// _doneButton.alpha = hidden ? 0.0f : 1.0f; -// }; -// -// if (animated) -// [UIView animateWithDuration:0.25 animations:changeBlock]; -// else -// changeBlock(); -//} -// -//- (id)currentResultRepresentation -//{ -// return TGPaintCombineCroppedImages(self.photoEditor.currentResultImage, [self image], true, _photoEditor.originalSize, _photoEditor.cropRect, _photoEditor.cropOrientation, _photoEditor.cropRotation, false); -//} -// -//#pragma mark - Layout -// -//- (void)viewWillLayoutSubviews -//{ -// [super viewWillLayoutSubviews]; -// -// [self updateLayout:[[LegacyComponentsGlobals provider] applicationStatusBarOrientation]]; -// [_entitySelectionView update]; -//} -// -//- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration -//{ -// [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; -// -// if (_menuContainerView != nil) -// { -// [_menuContainerView removeFromSuperview]; -// _menuContainerView = nil; -// } -// -// [self updateLayout:toInterfaceOrientation]; -//} -// -//- (void)updateContentViewLayout -//{ -// CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(TGRotationForOrientation(_photoEditor.cropOrientation)); -// _contentView.transform = rotationTransform; -// _contentView.frame = self.previewView.frame; -// [self resetScrollView]; -//} -// -//- (void)updateLayout:(UIInterfaceOrientation)orientation -//{ -// if ([self inFormSheet] || [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) -// { -// _landscapeToolsWrapperView.hidden = true; -// orientation = UIInterfaceOrientationPortrait; -// } -// -// CGSize referenceSize = [self referenceViewSize]; -// CGFloat screenSide = MAX(referenceSize.width, referenceSize.height) + 2 * TGPhotoPaintBottomPanelSize; -// -// bool sizeUpdated = false; -// if (!CGSizeEqualToSize(referenceSize, _previousSize)) { -// sizeUpdated = true; -// _previousSize = referenceSize; -// } -// -// CGFloat panelToolbarPortraitSize = TGPhotoPaintBottomPanelSize + TGPhotoEditorToolbarSize; -// CGFloat panelToolbarLandscapeSize = TGPhotoPaintBottomPanelSize + self.toolbarLandscapeSize; -// -// UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:self.hasOnScreenNavigation]; -// UIEdgeInsets screenEdges = UIEdgeInsetsMake((screenSide - referenceSize.height) / 2, (screenSide - referenceSize.width) / 2, (screenSide + referenceSize.height) / 2, (screenSide + referenceSize.width) / 2); -// screenEdges.top += safeAreaInset.top; -// screenEdges.left += safeAreaInset.left; -// screenEdges.bottom -= safeAreaInset.bottom; -// screenEdges.right -= safeAreaInset.right; -// -// CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:orientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation]; -// -// _settingsViewWrapper.frame = self.parentViewController.view.bounds; -// -// _doneButton.frame = CGRectMake(screenEdges.right - _doneButton.frame.size.width - 8.0, screenEdges.top + 2.0, _doneButton.frame.size.width, _doneButton.frame.size.height); -// -// if (_settingsView != nil) -// [_settingsView setInterfaceOrientation:orientation]; -// -// switch (orientation) -// { -// case UIInterfaceOrientationLandscapeLeft: -// { -// _landscapeSettingsView.interfaceOrientation = orientation; -// -// [UIView performWithoutAnimation:^ -// { -// _landscapeToolsWrapperView.frame = CGRectMake(0, screenEdges.top, panelToolbarLandscapeSize, _landscapeToolsWrapperView.frame.size.height); -// _landscapeSettingsView.frame = CGRectMake(panelToolbarLandscapeSize - TGPhotoPaintBottomPanelSize, 0, TGPhotoPaintBottomPanelSize, _landscapeSettingsView.frame.size.height); -// }]; -// -// _landscapeToolsWrapperView.frame = CGRectMake(screenEdges.left, screenEdges.top, panelToolbarLandscapeSize, referenceSize.height); -// _landscapeSettingsView.frame = CGRectMake(_landscapeSettingsView.frame.origin.x, _landscapeSettingsView.frame.origin.y, _landscapeSettingsView.frame.size.width, _landscapeToolsWrapperView.frame.size.height); -// -// _portraitToolsWrapperView.frame = CGRectMake(screenEdges.left, screenSide - panelToolbarPortraitSize, referenceSize.width, panelToolbarPortraitSize); -// _portraitSettingsView.frame = CGRectMake(0, 0, _portraitToolsWrapperView.frame.size.width, TGPhotoPaintBottomPanelSize); -// -// _landscapeActionsView.frame = CGRectMake(screenEdges.right - TGPhotoPaintTopPanelSize, screenEdges.top, TGPhotoPaintTopPanelSize, referenceSize.height); -// -// _settingsView.frame = CGRectMake(self.toolbarLandscapeSize + 50.0f + safeAreaInset.left, 0.0f, _settingsView.frame.size.width, _settingsView.frame.size.height); -// } -// break; -// -// case UIInterfaceOrientationLandscapeRight: -// { -// _landscapeSettingsView.interfaceOrientation = orientation; -// -// [UIView performWithoutAnimation:^ -// { -// _landscapeToolsWrapperView.frame = CGRectMake(screenSide - panelToolbarLandscapeSize, screenEdges.top, panelToolbarLandscapeSize, _landscapeToolsWrapperView.frame.size.height); -// _landscapeSettingsView.frame = CGRectMake(0, 0, TGPhotoPaintBottomPanelSize, _landscapeSettingsView.frame.size.height); -// }]; -// -// _landscapeToolsWrapperView.frame = CGRectMake(screenEdges.right - panelToolbarLandscapeSize, screenEdges.top, panelToolbarLandscapeSize, referenceSize.height); -// _landscapeSettingsView.frame = CGRectMake(_landscapeSettingsView.frame.origin.x, _landscapeSettingsView.frame.origin.y, _landscapeSettingsView.frame.size.width, _landscapeToolsWrapperView.frame.size.height); -// -// _portraitToolsWrapperView.frame = CGRectMake(screenEdges.top, screenSide - panelToolbarPortraitSize, referenceSize.width, panelToolbarPortraitSize); -// _portraitSettingsView.frame = CGRectMake(0, 0, _portraitToolsWrapperView.frame.size.width, TGPhotoPaintBottomPanelSize); -// -// _landscapeActionsView.frame = CGRectMake(screenEdges.left, screenEdges.top, TGPhotoPaintTopPanelSize, referenceSize.height); -// -// _settingsView.frame = CGRectMake(_settingsViewWrapper.frame.size.width - _settingsView.frame.size.width - self.toolbarLandscapeSize - 50.0f - safeAreaInset.right, 0.0f, _settingsView.frame.size.width, _settingsView.frame.size.height); -// } -// break; -// -// default: -// { -// CGFloat x = _landscapeToolsWrapperView.frame.origin.x; -// if (x < screenSide / 2) -// x = 0; -// else -// x = screenSide - TGPhotoEditorPanelSize; -// _landscapeToolsWrapperView.frame = CGRectMake(x, screenEdges.top, panelToolbarLandscapeSize, referenceSize.height); -// -// _portraitToolsWrapperView.frame = CGRectMake(screenEdges.left, screenEdges.bottom - panelToolbarPortraitSize, referenceSize.width, panelToolbarPortraitSize); -// _portraitSettingsView.frame = CGRectMake(0, 0, referenceSize.width, TGPhotoPaintBottomPanelSize); -// -// _portraitActionsView.frame = CGRectMake(screenEdges.left, screenEdges.top, referenceSize.width, TGPhotoPaintTopPanelSize); -// -// if ([_context currentSizeClass] == UIUserInterfaceSizeClassRegular) -// { -// _settingsView.frame = CGRectMake(_settingsViewWrapper.frame.size.width / 2.0f - 10.0f, _settingsViewWrapper.frame.size.height - _settingsView.frame.size.height - TGPhotoEditorToolbarSize - 50.0f, _settingsView.frame.size.width, _settingsView.frame.size.height); -// } -// else -// { -// _settingsView.frame = CGRectMake(_settingsViewWrapper.frame.size.width - _settingsView.frame.size.width, _settingsViewWrapper.frame.size.height - _settingsView.frame.size.height - TGPhotoEditorToolbarSize - 50.0f - safeAreaInset.bottom, _settingsView.frame.size.width, _settingsView.frame.size.height); -// } -// } -// break; -// } -// -// PGPhotoEditor *photoEditor = self.photoEditor; -// TGPhotoEditorPreviewView *previewView = self.previewView; -// -// CGSize fittedSize = TGScaleToSize(photoEditor.rotatedCropSize, containerFrame.size); -// CGRect previewFrame = CGRectMake((containerFrame.size.width - fittedSize.width) / 2, (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); -// -// CGFloat visibleArea = self.view.frame.size.height - _keyboardHeight; -// CGFloat yCenter = visibleArea / 2.0f; -// CGFloat offset = yCenter - _previewView.center.y - containerFrame.origin.y; -// CGFloat offsetHeight = _keyboardHeight > FLT_EPSILON ? offset : 0.0f; -// -// _wrapperView.frame = CGRectMake((referenceSize.width - screenSide) / 2, (referenceSize.height - screenSide) / 2 + offsetHeight, screenSide, screenSide); -// -// if (_dismissing || (previewView.superview != _containerView && previewView.superview != self.view)) -// return; -// -// if (previewView.superview == self.view) -// { -// previewFrame = CGRectMake(containerFrame.origin.x + (containerFrame.size.width - fittedSize.width) / 2, containerFrame.origin.y + (containerFrame.size.height - fittedSize.height) / 2, fittedSize.width, fittedSize.height); -// } -// -// UIImageOrientation cropOrientation = _photoEditor.cropOrientation; -// CGRect cropRect = _photoEditor.cropRect; -// CGSize originalSize = _photoEditor.originalSize; -// CGFloat rotation = _photoEditor.cropRotation; -// -// CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(TGRotationForOrientation(cropOrientation)); -// _contentView.transform = rotationTransform; -// _contentView.frame = previewFrame; -// -// _scrollView.frame = self.view.bounds; -// -// if (sizeUpdated) { -// [self resetScrollView]; -// } -// [self adjustZoom]; -// -// _paintingWrapperView.transform = CGAffineTransformMakeRotation(TGRotationForOrientation(cropOrientation)); -// _paintingWrapperView.frame = previewFrame; -// -// CGFloat originalWidth = TGOrientationIsSideward(cropOrientation, NULL) ? previewFrame.size.height : previewFrame.size.width; -// CGFloat ratio = originalWidth / cropRect.size.width; -// CGRect originalFrame = CGRectMake(-cropRect.origin.x * ratio, -cropRect.origin.y * ratio, originalSize.width * ratio, originalSize.height * ratio); -// -// previewView.frame = previewFrame; -// -// if ([self presentedForAvatarCreation]) { -// CGAffineTransform transform = CGAffineTransformMakeRotation(TGRotationForOrientation(photoEditor.cropOrientation)); -// if (photoEditor.cropMirrored) -// transform = CGAffineTransformScale(transform, -1.0f, 1.0f); -// previewView.transform = transform; -// } -// -// CGSize fittedOriginalSize = CGSizeMake(originalSize.width * ratio, originalSize.height * ratio); -// CGSize rotatedSize = TGRotatedContentSize(fittedOriginalSize, rotation); -// CGPoint centerPoint = CGPointMake(rotatedSize.width / 2.0f, rotatedSize.height / 2.0f); -// -// CGFloat scale = fittedOriginalSize.width / _photoEditor.originalSize.width; -// CGPoint centerOffset = TGPaintSubtractPoints(centerPoint, [self fittedCropCenterScale:scale]); -// -// _canvasView.transform = CGAffineTransformIdentity; -// _canvasView.frame = originalFrame; -// _canvasView.transform = CGAffineTransformMakeRotation(rotation); -// _canvasView.center = TGPaintAddPoints(TGPaintCenterOfRect(_paintingWrapperView.bounds), centerOffset); -// -// _selectionContainerView.transform = CGAffineTransformRotate(rotationTransform, rotation); -// _selectionContainerView.frame = previewFrame; -// _eyedropperView.frame = _selectionContainerView.bounds; -// -// _containerView.frame = CGRectMake(containerFrame.origin.x, containerFrame.origin.y + offsetHeight, containerFrame.size.width, containerFrame.size.height); -//} -// -//#pragma mark - Keyboard Avoidance -// -//- (void)keyboardWillChangeFrame:(NSNotification *)notification -//{ -// UIView *parentView = self.view; -// -// NSTimeInterval duration = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] == nil ? 0.3 : [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; -// int curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] intValue]; -// CGRect screenKeyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; -// CGRect keyboardFrame = [parentView convertRect:screenKeyboardFrame fromView:nil]; -// -// CGFloat keyboardHeight = (keyboardFrame.size.height <= FLT_EPSILON || keyboardFrame.size.width <= FLT_EPSILON) ? 0.0f : (parentView.frame.size.height - keyboardFrame.origin.y); -// keyboardHeight = MAX(keyboardHeight, 0.0f); -// -// _keyboardHeight = keyboardHeight; -// -// [self keyboardHeightChangedTo:keyboardHeight duration:duration curve:curve]; -//} -// -//- (void)keyboardHeightChangedTo:(CGFloat)height duration:(NSTimeInterval)duration curve:(NSInteger)curve -//{ -// CGSize referenceSize = [self referenceViewSize]; -// CGFloat screenSide = MAX(referenceSize.width, referenceSize.height) + 2 * TGPhotoPaintBottomPanelSize; -// -// CGRect containerFrame = [TGPhotoPaintController photoContainerFrameForParentViewFrame:CGRectMake(0, 0, referenceSize.width, referenceSize.height) toolbarLandscapeSize:self.toolbarLandscapeSize orientation:self.effectiveOrientation panelSize:TGPhotoPaintTopPanelSize + TGPhotoPaintBottomPanelSize hasOnScreenNavigation:self.hasOnScreenNavigation]; -// -// CGFloat visibleArea = self.view.frame.size.height - height; -// CGFloat yCenter = visibleArea / 2.0f; -// CGFloat offset = yCenter - _previewView.center.y - containerFrame.origin.y; -// CGFloat offsetHeight = height > FLT_EPSILON ? offset : 0.0f; -// -// [UIView animateWithDuration:duration delay:0.0 options:curve animations:^ -// { -// _wrapperView.frame = CGRectMake((referenceSize.width - screenSide) / 2, (referenceSize.height - screenSide) / 2 + offsetHeight, _wrapperView.frame.size.width, _wrapperView.frame.size.height); -// _containerView.frame = CGRectMake(containerFrame.origin.x, containerFrame.origin.y + offsetHeight, containerFrame.size.width, containerFrame.size.height); -// } completion:nil]; -//} -// -//- (void)_setStickerEntityPosition:(TGPhotoPaintStickerEntity *)entity -//{ -// TGStickerMaskDescription *mask = [_stickersContext maskDescriptionForDocument:entity.document]; -// int64_t documentId = [_stickersContext documentIdForDocument:entity.document]; -// TGPhotoMaskPosition *position = [self _positionForMaskDescription:mask documentId:documentId]; -// if (position != nil) -// { -// entity.position = position.center; -// entity.angle = position.angle; -// entity.scale = position.scale; -// } -// else -// { -// entity.position = [self startPositionRelativeToEntity:nil]; -// entity.angle = [self startRotation]; -// } -//} -// -//- (TGPhotoMaskPosition *)_positionForMaskDescription:(TGStickerMaskDescription *)mask documentId:(int64_t)documentId -//{ -// if (mask == nil) -// return nil; -// -// TGPhotoMaskAnchor anchor = [TGPhotoMaskPosition anchorOfMask:mask]; -// if (anchor == TGPhotoMaskAnchorNone) -// return nil; -// -// TGPaintFace *face = [self _randomFaceWithVacantAnchor:anchor documentId:documentId]; -// if (face == nil) -// return nil; -// -// CGPoint referencePoint = CGPointZero; -// CGFloat referenceWidth = 0.0f; -// CGFloat angle = 0.0f; -// CGSize baseSize = [self _stickerBaseSizeForCurrentPainting]; -// CGRect faceBounds = [TGPaintFaceUtils transposeRect:face.bounds paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// -// switch (anchor) -// { -// case TGPhotoMaskAnchorForehead: -// { -// referencePoint = [TGPaintFaceUtils transposePoint:[face foreheadPoint] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// referenceWidth = faceBounds.size.width; -// angle = face.angle; -// } -// break; -// -// case TGPhotoMaskAnchorEyes: -// { -// CGPoint point = [face eyesCenterPointAndDistance:&referenceWidth]; -// referenceWidth = [TGPaintFaceUtils transposeWidth:referenceWidth paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// referencePoint = [TGPaintFaceUtils transposePoint:point paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// angle = [face eyesAngle]; -// } -// break; -// -// case TGPhotoMaskAnchorMouth: -// { -// referencePoint = [TGPaintFaceUtils transposePoint:[face mouthPoint] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// referenceWidth = faceBounds.size.width; -// angle = face.angle; -// } -// break; -// -// case TGPhotoMaskAnchorChin: -// { -// referencePoint = [TGPaintFaceUtils transposePoint:[face chinPoint] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// referenceWidth = faceBounds.size.width; -// angle = face.angle; -// } -// break; -// -// default: -// break; -// } -// -// CGFloat scale = referenceWidth / baseSize.width * mask.zoom; -// -// CGPoint xComp = CGPointMake(sin(M_PI_2 - angle) * referenceWidth * mask.point.x, -// cos(M_PI_2 - angle) * referenceWidth * mask.point.x); -// CGPoint yComp = CGPointMake(cos(M_PI_2 + angle) * referenceWidth * mask.point.y, -// sin(M_PI_2 + angle) * referenceWidth * mask.point.y); -// -// CGPoint position = CGPointMake(referencePoint.x + xComp.x + yComp.x, referencePoint.y + xComp.y + yComp.y); -// -// return [TGPhotoMaskPosition maskPositionWithCenter:position scale:scale angle:angle]; -//} -// -//- (TGPaintFace *)_randomFaceWithVacantAnchor:(TGPhotoMaskAnchor)anchor documentId:(int64_t)documentId -//{ -// NSInteger randomIndex = (NSInteger)arc4random_uniform((uint32_t)self.faces.count); -// NSInteger count = self.faces.count; -// NSInteger remaining = self.faces.count; -// -// for (NSInteger i = randomIndex; remaining > 0; (i = (i + 1) % count), remaining--) -// { -// TGPaintFace *face = self.faces[i]; -// if (![self _isFaceAnchorOccupied:face anchor:anchor documentId:documentId]) -// return face; -// } -// -// return nil; -//} -// -//- (bool)_isFaceAnchorOccupied:(TGPaintFace *)face anchor:(TGPhotoMaskAnchor)anchor documentId:(int64_t)documentId -//{ -// CGPoint anchorPoint = CGPointZero; -// switch (anchor) -// { -// case TGPhotoMaskAnchorForehead: -// { -// anchorPoint = [TGPaintFaceUtils transposePoint:[face foreheadPoint] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// } -// break; -// -// case TGPhotoMaskAnchorEyes: -// { -// anchorPoint = [TGPaintFaceUtils transposePoint:[face eyesCenterPointAndDistance:NULL] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// } -// break; -// -// case TGPhotoMaskAnchorMouth: -// { -// anchorPoint = [TGPaintFaceUtils transposePoint:[face mouthPoint] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// } -// break; -// -// case TGPhotoMaskAnchorChin: -// { -// anchorPoint = [TGPaintFaceUtils transposePoint:[face chinPoint] paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// } -// break; -// -// default: -// { -// -// } -// break; -// } -// -// CGRect faceBounds = [TGPaintFaceUtils transposeRect:face.bounds paintingSize:_painting.size originalSize:_photoEditor.originalSize]; -// CGFloat minDistance = faceBounds.size.width * 1.1; -// -// for (TGPhotoStickerEntityView *view in _entitiesContainerView.subviews) -// { -// if (![view isKindOfClass:[TGPhotoStickerEntityView class]]) -// continue; -// -// TGPhotoPaintStickerEntity *entity = view.entity; -// TGStickerMaskDescription *mask = [_stickersContext maskDescriptionForDocument:view.entity.document]; -// int64_t maskDocumentId = [_stickersContext documentIdForDocument:entity.document]; -// -// if ([TGPhotoMaskPosition anchorOfMask:mask] != anchor) -// continue; -// -// if ((documentId == maskDocumentId || self.faces.count > 1) && TGPaintDistance(entity.position, anchorPoint) < minDistance) -// return true; -// } -// -// return false; -//} -// -//- (NSArray *)faces -//{ -// TGPhotoEditorController *editorController = (TGPhotoEditorController *)self.parentViewController; -// if ([editorController isKindOfClass:[TGPhotoEditorController class]]) -// return editorController.faces; -// else -// return @[]; -//} -// -//- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures -//{ -// return UIRectEdgeTop | UIRectEdgeBottom; -//} -// -//@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintEntity.m b/submodules/LegacyComponents/Sources/TGPhotoPaintEntity.m deleted file mode 100644 index dd61c0a5ef..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintEntity.m +++ /dev/null @@ -1,27 +0,0 @@ -#import "TGPhotoPaintEntity.h" - -@implementation TGPhotoPaintEntity - -- (instancetype)init -{ - self = [super init]; - if (self != nil) - { - arc4random_buf(&_uuid, sizeof(NSInteger)); - } - return self; -} - -- (instancetype)copyWithZone:(NSZone *)__unused zone -{ - return nil; -} - -- (instancetype)duplicate -{ - TGPhotoPaintEntity *entity = [self copy]; - arc4random_buf(&entity->_uuid, sizeof(NSInteger)); - return entity; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintEntityView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintEntityView.m deleted file mode 100644 index 17f7d1d52a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintEntityView.m +++ /dev/null @@ -1,247 +0,0 @@ -#import "TGPhotoPaintEntityView.h" - -#import "TGPhotoEntitiesContainerView.h" -#import - -const CGFloat TGPhotoPaintEntityMinScale = 0.12f; - -@interface TGPhotoPaintEntityView () -{ - UIPanGestureRecognizer *_panGestureRecognizer; - - bool _measuring; - CGFloat _realScale; - CGAffineTransform _realTransform; -} -@end - -@implementation TGPhotoPaintEntityView - -@dynamic entity; - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.contentScaleFactor = MIN(2.0f, self.contentScaleFactor); - - _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _panGestureRecognizer.delegate = self; - [self addGestureRecognizer:_panGestureRecognizer]; - } - return self; -} - -- (NSInteger)entityUUID -{ - return _entityUUID; -} - -- (void)_pushIdentityTransformForMeasurement -{ - if (_measuring) - return; - - _measuring = true; - _realTransform = self.transform; - _realScale = [[self.layer valueForKeyPath:@"transform.scale.x"] floatValue]; - self.transform = CGAffineTransformIdentity; -} - -- (void)_popIdentityTransformForMeasurement -{ - if (!_measuring) - return; - - _measuring = false; - self.transform = _realTransform; - - _realTransform = CGAffineTransformIdentity; - _realScale = 1.0f; -} - -- (CGFloat)angle -{ - return atan2(self.transform.b, self.transform.a); -} - -- (CGFloat)scale -{ - if (_measuring) - return _realScale; - - return [[self.layer valueForKeyPath:@"transform.scale.x"] floatValue]; -} - -- (void)_notifyOfChange -{ - if (self.entityChanged != nil) - self.entityChanged(self); -} - -- (void)pan:(CGPoint)point absolute:(bool)absolute -{ - if (absolute) - self.center = point; - else - self.center = TGPaintAddPoints(self.center, point); - - [self _notifyOfChange]; -} - -- (void)rotate:(CGFloat)angle absolute:(bool)absolute -{ - CGFloat deltaAngle = angle; - if (absolute) - deltaAngle = angle - self.angle; - self.transform = CGAffineTransformRotate(self.transform, deltaAngle); - - [self _notifyOfChange]; -} - -- (void)scale:(CGFloat)scale absolute:(bool)__unused absolute -{ - CGFloat newScale = self.scale * scale; - - if (newScale < TGPhotoPaintEntityMinScale) - scale = self.scale / TGPhotoPaintEntityMinScale; - - self.transform = CGAffineTransformScale(self.transform, scale, scale); - - [self _notifyOfChange]; -} - -- (bool)inhibitGestures -{ - return _panGestureRecognizer.enabled; -} - -- (void)setInhibitGestures:(bool)inhibitGestures -{ - _panGestureRecognizer.enabled = !inhibitGestures; -} - -- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer -{ - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateBegan: - { - if (self.entityBeganDragging != nil) - self.entityBeganDragging(self); - } - case UIGestureRecognizerStateChanged: - { - CGPoint translation = [gestureRecognizer translationInView:self.superview]; - [self pan:translation absolute:false]; - [gestureRecognizer setTranslation:CGPointZero inView:self.superview]; - } - break; - - case UIGestureRecognizerStateEnded: - { - [self _notifyOfChange]; - } - break; - - default: - break; - } -} - -- (bool)precisePointInside:(CGPoint)point -{ - return [self pointInside:point withEvent:nil]; -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)__unused gestureRecognizer -{ - if (self.shouldTouchEntity != nil) - return self.shouldTouchEntity(self); - - return true; -} - -- (CGRect)selectionBounds -{ - return self.bounds; -} - -- (TGPhotoPaintEntitySelectionView *)createSelectionView -{ - return nil; -} - -- (bool)isTracking -{ - bool panTracking = (_panGestureRecognizer.state == UIGestureRecognizerStateBegan || _panGestureRecognizer.state == UIGestureRecognizerStateChanged); - bool selectionTracking = self.selectionView.isTracking; - - return panTracking || selectionTracking; -} - -@end - - -@implementation TGPhotoPaintEntitySelectionView - -- (void)update -{ - TGPhotoPaintEntityView *entityView = self.entityView; - - [entityView _pushIdentityTransformForMeasurement]; - self.transform = CGAffineTransformIdentity; - CGRect bounds = entityView.selectionBounds; - CGPoint center = TGPaintCenterOfRect(bounds); - - CGFloat scale = [[entityView.superview.superview.layer valueForKeyPath:@"transform.scale.x"] floatValue]; - self.center = [entityView convertPoint:center toView:self.superview]; - self.bounds = CGRectMake(0.0f, 0.0f, bounds.size.width * scale, bounds.size.height * scale); - [entityView _popIdentityTransformForMeasurement]; - - self.transform = CGAffineTransformMakeRotation(entityView.angle); -} - -- (void)fadeIn -{ - self.alpha = 0.0f; - [UIView animateWithDuration:0.18 animations:^ - { - self.alpha = 1.0f; - }]; -} - -- (void)fadeOut -{ - [UIView animateWithDuration:0.18 animations:^ - { - self.alpha = 0.0f; - }]; -} - -@end - -@implementation UIView (PixelColor) - -- (UIColor *)colorAtPoint:(CGPoint)point -{ - if (point.x > self.bounds.size.width || point.y > self.bounds.size.height) - return nil; - - unsigned char pixel[4] = {0}; - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast); - - CGContextTranslateCTM(context, -point.x, -point.y); - - [self.layer renderInContext:context]; - - CGContextRelease(context); - CGColorSpaceRelease(colorSpace); - - return [UIColor colorWithRed:pixel[0] / 255.0 green:pixel[1] / 255.0 blue:pixel[2] / 255.0 alpha:pixel[3] / 255.0]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintEyedropperView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintEyedropperView.h deleted file mode 100644 index 31317aa742..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintEyedropperView.h +++ /dev/null @@ -1,13 +0,0 @@ -#import - -@interface TGPhotoPaintEyedropperView : UIView - -@property (nonatomic, strong) UIColor *color; -@property (nonatomic, copy) void(^locationChanged)(CGPoint, bool); - -- (void)update; -- (void)present; -- (void)dismiss; - -@end - diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintEyedropperView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintEyedropperView.m deleted file mode 100644 index 2b99e6a9ff..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintEyedropperView.m +++ /dev/null @@ -1,157 +0,0 @@ -#import "TGPhotoPaintEyedropperView.h" - -#import "TGImageUtils.h" - -@interface TGPhotoPaintEyedropperIndicatorView : UIView - -@property (nonatomic, strong) UIColor *color; - -@end - -@implementation TGPhotoPaintEyedropperIndicatorView - --(instancetype)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if (self != nil) { - self.backgroundColor = [UIColor clearColor]; - self.opaque = false; - self.userInteractionEnabled = false; - } - return self; -} - -- (void)setColor:(UIColor *)color { - _color = color; - [self setNeedsDisplay]; -} - -- (void)drawRect:(CGRect)rect { - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGFloat lineWidth = 1.0f + TGScreenPixel; - - CGContextSetFillColorWithColor(context, _color.CGColor); - CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); - - CGContextSaveGState(context); - - CGContextScaleCTM(context, 0.333333, 0.333333); - CGContextSetLineWidth(context, lineWidth * 3.0); - - TGDrawSvgPath(context, @"M75,0.5 C54.4273931,0.5 35.8023931,8.83869653 22.3205448,22.3205448 C8.83869653,35.8023931 0.5,54.4273931 0.5,75 C0.5,94.6543797 10.7671345,116.856807 23.8111444,136.192682 C42.4188317,163.77591 66.722394,185.676747 75,185.676747 C83.277606,185.676747 107.581168,163.77591 126.188856,136.192682 C139.232866,116.856807 149.5,94.6543797 149.5,75 C149.5,54.4273931 141.161303,35.8023931 127.679455,22.3205448 C114.197607,8.83869653 95.5726069,0.5 75,0.5 Z"); - - TGDrawSvgPath(context, @"M75,0.5 C54.4273931,0.5 35.8023931,8.83869653 22.3205448,22.3205448 C8.83869653,35.8023931 0.5,54.4273931 0.5,75 C0.5,94.6543797 10.7671345,116.856807 23.8111444,136.192682 C42.4188317,163.77591 66.722394,185.676747 75,185.676747 C83.277606,185.676747 107.581168,163.77591 126.188856,136.192682 C139.232866,116.856807 149.5,94.6543797 149.5,75 C149.5,54.4273931 141.161303,35.8023931 127.679455,22.3205448 C114.197607,8.83869653 95.5726069,0.5 75,0.5 S"); - - CGContextRestoreGState(context); - - CGContextSetLineWidth(context, lineWidth); - CGContextFillEllipseInRect(context, CGRectMake(20.0, 68.0, 11.0, 11.0)); - CGContextStrokeEllipseInRect(context, CGRectMake(20.0, 68.0, 11.0, 11.0)); -} - -@end - -@interface TGPhotoPaintEyedropperView() - -@end - -@implementation TGPhotoPaintEyedropperView -{ - TGPhotoPaintEyedropperIndicatorView *_indicatorView; - - UITapGestureRecognizer *_tapGestureRecognizer; - UIPanGestureRecognizer *_panGestureRecognizer; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) { - _indicatorView = [[TGPhotoPaintEyedropperIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 51.0, 81.0)]; - _indicatorView.layer.anchorPoint = CGPointMake(0.5, 0.92); - [self addSubview:_indicatorView]; - - _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; - [self addGestureRecognizer:_tapGestureRecognizer]; - - _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _panGestureRecognizer.delegate = self; - [self addGestureRecognizer:_panGestureRecognizer]; - } - return self; -} - -- (void)setColor:(UIColor *)color { - _color = color; - _indicatorView.color = color; -} - -- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer { - CGPoint location = [gestureRecognizer locationInView:self]; - [self layoutIndicator:location]; - self.locationChanged(location, true); -} - -- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer { - CGPoint location = [gestureRecognizer locationInView:self]; - switch (gestureRecognizer.state) - { - case UIGestureRecognizerStateChanged: - { - [self layoutIndicator:location]; - self.locationChanged(location, false); - - } - break; - - case UIGestureRecognizerStateEnded: - { - [self layoutIndicator:location]; - self.locationChanged(location, true); - } - break; - - default: - break; - } -} - -- (void)update { - CGPoint location = CGPointMake(self.bounds.size.width / 2.0, self.bounds.size.height / 2.0); - self.locationChanged(location, false); - [self layoutIndicator:location]; -} - -- (void)present { - self.hidden = false; - - _indicatorView.alpha = 0.0f; - _indicatorView.transform = CGAffineTransformMakeScale(0.2, 0.2); - [UIView animateWithDuration:0.2 animations:^ - { - _indicatorView.alpha = 1.0f; - _indicatorView.transform = CGAffineTransformIdentity; - } completion:^(__unused BOOL finished) - { - }]; -} - -- (void)dismiss { - if (self.hidden) - return; - - [UIView animateWithDuration:0.15 animations:^ - { - _indicatorView.alpha = 0.0f; - _indicatorView.transform = CGAffineTransformMakeScale(0.2, 0.2); - } completion:^(__unused BOOL finished) - { - self.hidden = true; - }]; -} - -- (void)layoutIndicator:(CGPoint)point { - _indicatorView.center = CGPointMake(point.x, point.y); -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintFont.h b/submodules/LegacyComponents/Sources/TGPhotoPaintFont.h deleted file mode 100644 index 842f517437..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintFont.h +++ /dev/null @@ -1,16 +0,0 @@ -#import -#import - -@interface TGPhotoPaintFont : NSObject - -@property (nonatomic, readonly) NSString *title; -@property (nonatomic, readonly) CGFloat titleInset; - -@property (nonatomic, readonly) NSString *fontName; -@property (nonatomic, readonly) NSString *previewFontName; - -@property (nonatomic, readonly) CGFloat sizeCorrection; - -+ (NSArray *)availableFonts; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintFont.m b/submodules/LegacyComponents/Sources/TGPhotoPaintFont.m deleted file mode 100644 index 4e723a8a75..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintFont.m +++ /dev/null @@ -1,36 +0,0 @@ -#import "TGPhotoPaintFont.h" - -@implementation TGPhotoPaintFont - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return true; - - if (!object || ![object isKindOfClass:[self class]]) - return false; - - TGPhotoPaintFont *font = (TGPhotoPaintFont *)object; - return [font.title isEqualToString:self.title]; -} - -+ (instancetype)fontWithTitle:(NSString *)title titleInset:(CGFloat)titleInset fontName:(NSString *)fontName previewFontName:(NSString *)previewFontName sizeCorrection:(CGFloat)sizeCorrection -{ - TGPhotoPaintFont *font = [[TGPhotoPaintFont alloc] init]; - font->_title = title; - font->_titleInset = titleInset; - font->_fontName = fontName; - font->_previewFontName = previewFontName; - font->_sizeCorrection = sizeCorrection; - return font; -} - -+ (NSArray *)availableFonts -{ - return @ - [ - [TGPhotoPaintFont fontWithTitle:@"Main" titleInset:0 fontName:@"Helvetica-Bold" previewFontName:@"Helvetica" sizeCorrection:0] - ]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintScrollView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintScrollView.h deleted file mode 100644 index 8db5756e4a..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintScrollView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface TGPhotoPaintScrollView : UIScrollView - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintScrollView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintScrollView.m deleted file mode 100644 index 34d70f2086..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintScrollView.m +++ /dev/null @@ -1,15 +0,0 @@ -#import "TGPhotoPaintScrollView.h" - -@implementation TGPhotoPaintScrollView - -- (UIView *)hitTest:(CGPoint)__unused point withEvent:(UIEvent *)__unused event -{ - return nil; -} - -- (void)handlePinch:(id)__unused sender -{ - -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSelectionContainerView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintSelectionContainerView.h deleted file mode 100644 index 5469746bcb..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSelectionContainerView.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "TGPhotoEditorSparseView.h" - -@interface TGPhotoPaintSelectionContainerView : TGPhotoEditorSparseView - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSelectionContainerView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintSelectionContainerView.m deleted file mode 100644 index 9b11abb772..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSelectionContainerView.m +++ /dev/null @@ -1,20 +0,0 @@ -#import "TGPhotoPaintSelectionContainerView.h" - -@implementation TGPhotoPaintSelectionContainerView - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event -{ - bool pointInside = [super pointInside:point withEvent:event]; - if (!pointInside) - { - for (UIView *subview in self.subviews) - { - CGPoint convertedPoint = [self convertPoint:point toView:subview]; - if ([subview pointInside:convertedPoint withEvent:event]) - pointInside = true; - } - } - return pointInside; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h deleted file mode 100644 index 035895cab6..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.h +++ /dev/null @@ -1,47 +0,0 @@ -#import - -#import - -@class TGPaintSwatch; - -typedef enum -{ - TGPhotoPaintSettingsViewIconBrushPen, - TGPhotoPaintSettingsViewIconBrushMarker, - TGPhotoPaintSettingsViewIconBrushNeon, - TGPhotoPaintSettingsViewIconBrushArrow, - TGPhotoPaintSettingsViewIconTextRegular, - TGPhotoPaintSettingsViewIconTextOutlined, - TGPhotoPaintSettingsViewIconTextFramed, - TGPhotoPaintSettingsViewIconMirror -} TGPhotoPaintSettingsViewIcon; - -@interface TGPhotoPaintSettingsView : UIView - -@property (nonatomic, copy) void (^beganColorPicking)(void); -@property (nonatomic, copy) void (^changedColor)(TGPhotoPaintSettingsView *sender, TGPaintSwatch *swatch); -@property (nonatomic, copy) void (^finishedColorPicking)(TGPhotoPaintSettingsView *sender, TGPaintSwatch *swatch); - -@property (nonatomic, copy) void (^eyedropperPressed)(void); -@property (nonatomic, copy) void (^settingsPressed)(void); - -@property (nonatomic, readonly) UIButton *settingsButton; - -@property (nonatomic, strong) TGPaintSwatch *swatch; -@property (nonatomic, assign) UIInterfaceOrientation interfaceOrientation; - -- (instancetype)initWithContext:(id)context; - -- (void)setIcon:(TGPhotoPaintSettingsViewIcon)icon animated:(bool)animated; -- (void)setHighlighted:(bool)highlighted; - -@end - -@protocol TGPhotoPaintPanelView - -@property (nonatomic, assign) UIInterfaceOrientation interfaceOrientation; - -- (void)present; -- (void)dismissWithCompletion:(void (^)(void))completion; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m deleted file mode 100644 index 9a48e7c7c5..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsView.m +++ /dev/null @@ -1,239 +0,0 @@ -#import "TGPhotoPaintSettingsView.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -#import "TGPhotoEditorInterfaceAssets.h" - -#import -#import "TGPhotoPaintColorPicker.h" -#import "TGPhotoEditorTintSwatchView.h" - -const CGFloat TGPhotoPaintSettingsPadPickerWidth = 360.0f; - -@interface TGPhotoPaintSettingsView () -{ - TGPhotoPaintColorPicker *_colorPicker; - TGModernButton *_eyedropperButton; - TGModernButton *_settingsButton; - TGPhotoPaintSettingsViewIcon _icon; - - id _context; -} -@end - -@implementation TGPhotoPaintSettingsView - -@dynamic swatch; - -- (instancetype)initWithContext:(id)context -{ - self = [super initWithFrame:CGRectZero]; - if (self) - { - _context = context; - - __weak TGPhotoPaintSettingsView *weakSelf = self; - _colorPicker = [[TGPhotoPaintColorPicker alloc] init]; - _colorPicker.beganPicking = ^ - { - __strong TGPhotoPaintSettingsView *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf.beganColorPicking != nil) - strongSelf.beganColorPicking(); - }; - _colorPicker.valueChanged = ^ - { - __strong TGPhotoPaintSettingsView *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf.changedColor != nil) - strongSelf.changedColor(strongSelf, strongSelf->_colorPicker.swatch); - }; - _colorPicker.finishedPicking = ^ - { - __strong TGPhotoPaintSettingsView *strongSelf = weakSelf; - if (strongSelf != nil && strongSelf.finishedColorPicking != nil) - strongSelf.finishedColorPicking(strongSelf, strongSelf->_colorPicker.swatch); - }; - [self addSubview:_colorPicker]; - - _icon = TGPhotoPaintSettingsViewIconBrushPen; - - _eyedropperButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 44.0f, 44.0f)]; - _eyedropperButton.exclusiveTouch = true; - [_eyedropperButton setImage:TGTintedImage([UIImage imageNamed:@"Editor/Eyedropper"], [UIColor whiteColor]) forState:UIControlStateNormal]; - [_eyedropperButton addTarget:self action:@selector(eyedropperButtonPressed) forControlEvents:UIControlEventTouchUpInside]; -// [self addSubview:_eyedropperButton]; - - _settingsButton = [[TGModernButton alloc] initWithFrame:CGRectMake(0, 0, 44.0f, 44.0f)]; - _settingsButton.exclusiveTouch = true; - [_settingsButton setImage:[self _imageForIcon:_icon highlighted:false] forState:UIControlStateNormal]; - [_settingsButton addTarget:self action:@selector(settingsButtonPressed) forControlEvents:UIControlEventTouchUpInside]; - [self addSubview:_settingsButton]; - } - return self; -} - -- (TGPaintSwatch *)swatch -{ - return _colorPicker.swatch; -} - -- (void)setSwatch:(TGPaintSwatch *)swatch -{ - [_colorPicker setSwatch:swatch]; -} - -- (UIInterfaceOrientation)interfaceOrientation -{ - return _colorPicker.orientation; -} - -- (void)setInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - _colorPicker.orientation = interfaceOrientation; -} - -- (void)eyedropperButtonPressed -{ - if (self.eyedropperPressed != nil) - self.eyedropperPressed(); -} - -- (void)settingsButtonPressed -{ - if (self.settingsPressed != nil) - self.settingsPressed(); -} - -- (UIButton *)settingsButton -{ - return _settingsButton; -} - -- (void)setIcon:(TGPhotoPaintSettingsViewIcon)icon animated:(bool)animated -{ - void (^changeBlock)(void) = ^ - { - [_settingsButton setImage:[self _imageForIcon:icon highlighted:false] forState:UIControlStateNormal]; - }; - - if (icon == _icon) - return; - - _icon = icon; - - if (animated) - { - UIView *transitionView = [_settingsButton snapshotViewAfterScreenUpdates:false]; - transitionView.frame = _settingsButton.frame; - [_settingsButton.superview addSubview:transitionView]; - - changeBlock(); - _settingsButton.alpha = 0.0f; - _settingsButton.transform = CGAffineTransformMakeScale(0.2f, 0.2); - - [UIView animateWithDuration:0.2 animations:^ - { - transitionView.alpha = 0.0f; - transitionView.transform = CGAffineTransformMakeScale(0.2f, 0.2f); - - _settingsButton.alpha = 1.0f; - _settingsButton.transform = CGAffineTransformIdentity; - } completion:^(__unused BOOL finished) - { - [transitionView removeFromSuperview]; - }]; - } - else - { - changeBlock(); - } -} - -- (void)setHighlighted:(bool)__unused highlighted -{ - [_settingsButton setImage:[self _imageForIcon:_icon highlighted:false] forState:UIControlStateNormal]; -} - -- (UIImage *)_imageForIcon:(TGPhotoPaintSettingsViewIcon)icon highlighted:(bool)highlighted -{ - UIColor *color = highlighted ? [TGPhotoEditorInterfaceAssets accentColor] : [UIColor whiteColor]; - UIImage *iconImage = nil; - switch (icon) - { - case TGPhotoPaintSettingsViewIconBrushPen: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedPen"], color); - break; - case TGPhotoPaintSettingsViewIconBrushMarker: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedMarker"], color); - break; - case TGPhotoPaintSettingsViewIconBrushNeon: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedNeon"], color); - break; - case TGPhotoPaintSettingsViewIconBrushArrow: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/BrushSelectedArrow"], color); - break; - case TGPhotoPaintSettingsViewIconTextRegular: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/TextSelectedRegular"], color); - break; - case TGPhotoPaintSettingsViewIconTextOutlined: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/TextSelectedOutlined"], color); - break; - case TGPhotoPaintSettingsViewIconTextFramed: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/TextSelectedFramed"], color); - break; - case TGPhotoPaintSettingsViewIconMirror: - iconImage = TGTintedImage([UIImage imageNamed:@"Editor/Flip"], color); - break; - } - return iconImage; -} - -+ (NSArray *)colors -{ - static dispatch_once_t onceToken; - static NSArray *colors; - dispatch_once(&onceToken, ^ - { - colors = @ - [ - UIColorRGB(0xfd2a69), - UIColorRGB(0xfe921d), - UIColorRGB(0xfec926), - UIColorRGB(0x67d442), - UIColorRGB(0x1dabf0), - UIColorRGB(0xc273d7), - UIColorRGB(0xffffff), - UIColorRGB(0x282828) - ]; - }); - return colors; -} - -- (void)layoutSubviews -{ - CGFloat leftInset = 23.0f; - CGFloat rightInset = 66.0f; - CGFloat colorPickerHeight = 10.0f; - if (self.frame.size.width > self.frame.size.height) - { - if ([_context currentSizeClass] == UIUserInterfaceSizeClassRegular) - { - _colorPicker.frame = CGRectMake(ceil((self.frame.size.width - TGPhotoPaintSettingsPadPickerWidth) / 2.0f), ceil((self.frame.size.height - colorPickerHeight) / 2.0f), TGPhotoPaintSettingsPadPickerWidth, colorPickerHeight); - _settingsButton.frame = CGRectMake(CGRectGetMaxX(_colorPicker.frame) + 11.0f, floor((self.frame.size.height - _settingsButton.frame.size.height) / 2.0f) + 1.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height); - } - else - { - _colorPicker.frame = CGRectMake(leftInset, ceil((self.frame.size.height - colorPickerHeight) / 2.0f), self.frame.size.width - leftInset - rightInset, colorPickerHeight); - _eyedropperButton.frame = CGRectMake(10.0f, floor((self.frame.size.height - _eyedropperButton.frame.size.height) / 2.0f) + 1.0f, _eyedropperButton.frame.size.width, _eyedropperButton.frame.size.height); - _settingsButton.frame = CGRectMake(self.frame.size.width - _settingsButton.frame.size.width - 10.0f, floor((self.frame.size.height - _settingsButton.frame.size.height) / 2.0f) + 1.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height); - } - } - else - { - _colorPicker.frame = CGRectMake(ceil((self.frame.size.width - colorPickerHeight) / 2.0f), rightInset, colorPickerHeight, self.frame.size.height - leftInset - rightInset); - _eyedropperButton.frame = CGRectMake(floor((self.frame.size.width - _eyedropperButton.frame.size.width) / 2.0f), self.frame.size.height - _eyedropperButton.frame.size.height - 10.0, _eyedropperButton.frame.size.width, _eyedropperButton.frame.size.height); - _settingsButton.frame = CGRectMake(floor((self.frame.size.width - _settingsButton.frame.size.width) / 2.0f), 10.0f, _settingsButton.frame.size.width, _settingsButton.frame.size.height); - } -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsWrapperView.h b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsWrapperView.h deleted file mode 100644 index 89f17b2225..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsWrapperView.h +++ /dev/null @@ -1,8 +0,0 @@ -#import - -@interface TGPhotoPaintSettingsWrapperView : UIButton - -@property (nonatomic, copy) void (^pressed)(CGPoint location); -@property (nonatomic, copy) bool (^suppressTouchAtPoint)(CGPoint location); - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsWrapperView.m b/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsWrapperView.m deleted file mode 100644 index 39ad8b69c6..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintSettingsWrapperView.m +++ /dev/null @@ -1,24 +0,0 @@ -#import "TGPhotoPaintSettingsWrapperView.h" - -@implementation TGPhotoPaintSettingsWrapperView - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - UIView *view = [super hitTest:point withEvent:event]; - if (view == self) - { - CGPoint location = [self convertPoint:point toView:nil]; - - if (self.pressed != nil) - self.pressed(location); - - if (self.suppressTouchAtPoint != nil && self.suppressTouchAtPoint(location)) - return view; - - return nil; - } - - return view; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintStickerEntity.m b/submodules/LegacyComponents/Sources/TGPhotoPaintStickerEntity.m deleted file mode 100644 index 2b2e463413..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintStickerEntity.m +++ /dev/null @@ -1,65 +0,0 @@ -#import "TGPhotoPaintStickerEntity.h" - -#import - -@implementation TGPhotoPaintStickerEntity - -@synthesize animated = _animated; - -- (instancetype)initWithDocument:(NSData *)document baseSize:(CGSize)baseSize animated:(bool)animated -{ - self = [super init]; - if (self != nil) - { - _document = document; - _baseSize = baseSize; - _animated = animated; - self.scale = 1.0; - } - return self; -} - -- (instancetype)initWithEmoji:(NSString *)emoji -{ - self = [super init]; - if (self != nil) - { - _emoji = emoji; - _animated = false; - self.scale = 1.0f; - } - return self; -} - -- (instancetype)copyWithZone:(NSZone *)__unused zone -{ - TGPhotoPaintStickerEntity *entity = nil; - if (_document != nil) - entity = [[TGPhotoPaintStickerEntity alloc] initWithDocument:self.document baseSize:self.baseSize animated:self.animated]; - else if (_emoji != nil) - entity = [[TGPhotoPaintStickerEntity alloc] initWithEmoji:self.emoji]; - else - return nil; - - entity->_uuid = self.uuid; - entity.position = self.position; - entity.scale = self.scale; - entity.angle = self.angle; - entity.mirrored = self.mirrored; - - return entity; -} - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return true; - - if (!object || ![object isKindOfClass:[self class]]) - return false; - - TGPhotoPaintStickerEntity *entity = (TGPhotoPaintStickerEntity *)object; - return entity.uuid == self.uuid && CGSizeEqualToSize(entity.baseSize, self.baseSize) && CGPointEqualToPoint(entity.position, self.position) && fabs(entity.scale - self.scale) < FLT_EPSILON && fabs(entity.angle - self.angle) < FLT_EPSILON && entity.mirrored == self.mirrored; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoPaintTextEntity.m b/submodules/LegacyComponents/Sources/TGPhotoPaintTextEntity.m deleted file mode 100644 index d3463c9ff0..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoPaintTextEntity.m +++ /dev/null @@ -1,57 +0,0 @@ -#import "TGPhotoPaintTextEntity.h" - -#import "TGPhotoPaintFont.h" -#import "TGPaintSwatch.h" - -@implementation TGPhotoPaintTextEntity - -- (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) - { - _text = text; - _font = font; - _swatch = swatch; - _baseFontSize = baseFontSize; - _maxWidth = maxWidth; - _style = style; - self.scale = 1.0f; - } - return self; -} - -- (instancetype)copyWithZone:(NSZone *)__unused zone -{ - 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; - entity.scale = self.scale; - entity.angle = self.angle; - - return entity; -} - -- (bool)animated { - return false; -} - -- (BOOL)isEqual:(id)object -{ - if (object == self) - return true; - - if (!object || ![object isKindOfClass:[self class]]) - 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.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 - - -@implementation TGPhotoPaintStaticEntity - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h b/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h deleted file mode 100644 index 92cbdebff1..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.h +++ /dev/null @@ -1,33 +0,0 @@ -#import -#import - -@interface TGPhotoStickerSelectionView : TGPhotoPaintEntitySelectionView - -@end - -@protocol TGPhotoPaintStickersContext; - -@interface TGPhotoStickerEntityView : TGPhotoPaintEntityView - -@property (nonatomic, copy) void(^started)(double); - -@property (nonatomic, readonly) TGPhotoPaintStickerEntity *entity; -@property (nonatomic, readonly) bool isMirrored; - -@property (nonatomic, readonly) int64_t documentId; - -- (instancetype)initWithEntity:(TGPhotoPaintStickerEntity *)entity context:(id)context; -- (void)mirror; -- (UIImage *)image; - -- (void)updateVisibility:(bool)visible; -- (void)seekTo:(double)timestamp; -- (void)play; -- (void)pause; -- (void)resetToStart; -- (void)playFromFrame:(NSInteger)frameIndex; -- (void)copyStickerView:(TGPhotoStickerEntityView *)view; - -- (CGRect)realBounds; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m b/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m deleted file mode 100644 index 8fd2bc3ed0..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoStickerEntityView.m +++ /dev/null @@ -1,358 +0,0 @@ -#import "TGPhotoStickerEntityView.h" - -#import "LegacyComponentsInternal.h" - -#import -#import -#import - -#import "TGDocumentMediaAttachment.h" -#import "TGStringUtils.h" -#import "TGImageUtils.h" -#import "TGColor.h" - -const CGFloat TGPhotoStickerSelectionViewHandleSide = 30.0f; - -@interface UIView (OpaquePixel) - -- (bool)isOpaqueAtPoint:(CGPoint)pixelPoint; - -@end - -@interface TGPhotoStickerSelectionView () -{ - UIView *_leftHandle; - UIView *_rightHandle; - - UIPanGestureRecognizer *_leftGestureRecognizer; - UIPanGestureRecognizer *_rightGestureRecognizer; -} -@end - - -@interface TGPhotoStickerEntityView () -{ - id _document; - bool _animated; - bool _mirrored; - - CGSize _baseSize; - CATransform3D _defaultTransform; -} -@end - -@implementation TGPhotoStickerEntityView - -- (instancetype)initWithEntity:(TGPhotoPaintStickerEntity *)entity context:(id)context -{ - self = [super initWithFrame:CGRectMake(0.0f, 0.0f, entity.baseSize.width, entity.baseSize.height)]; - if (self != nil) - { - _entityUUID = entity.uuid; - _baseSize = entity.baseSize; - _mirrored = entity.isMirrored; - - _document = entity.document; - _animated = entity.animated; - - CGSize imageSize = CGSizeMake(512.0f, 512.0f); - - CGSize displaySize = [self fittedSizeForSize:imageSize maxSize:CGSizeMake(512.0f, 512.0f)]; - - CGFloat scale = displaySize.width > displaySize.height ? self.frame.size.width / displaySize.width : self.frame.size.height / displaySize.height; - _defaultTransform = CATransform3DMakeScale(scale, scale, 1.0f); - - } - return self; -} - - -- (TGPhotoPaintStickerEntity *)entity -{ - TGPhotoPaintStickerEntity *entity = [[TGPhotoPaintStickerEntity alloc] initWithDocument:_document baseSize:_baseSize animated:_animated]; - entity.uuid = _entityUUID; - entity.position = self.center; - entity.scale = self.scale; - entity.angle = self.angle; - entity.mirrored = _mirrored; - return entity; -} - -- (CGRect)realBounds -{ - CGSize size = CGSizeMake(_baseSize.width * self.scale, _baseSize.height * self.scale); - return CGRectMake(self.center.x - size.width / 2.0f, self.center.y - size.height / 2.0f, size.width, size.height); -} - -- (bool)isMirrored -{ - return _mirrored; -} - -- (CGSize)fittedSizeForSize:(CGSize)size maxSize:(CGSize)maxSize -{ - return TGFitSize(CGSizeMake(size.width, size.height), maxSize); -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)__unused event -{ - CGPoint center = CGPointMake(self.bounds.size.width / 2.0f, self.bounds.size.height / 2.0f); - if (self.selectionView != nil) - { - CGFloat selectionRadius = self.bounds.size.width / sin(M_PI_4); - return pow(point.x - center.x, 2) + pow(point.y - center.y, 2) < pow(selectionRadius / 2.0f, 2); - } - else - { - return [super pointInside:point withEvent:event]; - } -} - -- (bool)precisePointInside:(CGPoint)point -{ - return false; -} - -- (void)mirror -{ - -} - -- (UIImage *)image -{ - return nil; -} - -- (TGPhotoPaintEntitySelectionView *)createSelectionView -{ - TGPhotoStickerSelectionView *view = [[TGPhotoStickerSelectionView alloc] init]; - view.entityView = self; - return view; -} - -- (CGRect)selectionBounds -{ - CGFloat side = self.bounds.size.width / sin(M_PI_4) * self.scale; - return CGRectMake((self.bounds.size.width - side) / 2.0f, (self.bounds.size.height - side) / 2.0f, side, side); -} - -- (void)updateVisibility:(bool)visible { - -} - -- (void)seekTo:(double)timestamp { - -} - -- (void)play { - -} - -- (void)pause { - -} - -- (void)resetToStart { - -} - -- (void)playFromFrame:(NSInteger)frameIndex { - -} - -- (void)copyStickerView:(TGPhotoStickerEntityView *)view { - -} - -- (int64_t)documentId { - return 0; -} - -@end - - -@implementation TGPhotoStickerSelectionView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.backgroundColor = [UIColor clearColor]; - self.contentMode = UIViewContentModeRedraw; - - _leftHandle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, TGPhotoStickerSelectionViewHandleSide, TGPhotoStickerSelectionViewHandleSide)]; - [self addSubview:_leftHandle]; - - _leftGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _leftGestureRecognizer.delegate = self; - [_leftHandle addGestureRecognizer:_leftGestureRecognizer]; - - _rightHandle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, TGPhotoStickerSelectionViewHandleSide, TGPhotoStickerSelectionViewHandleSide)]; - [self addSubview:_rightHandle]; - - _rightGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _rightGestureRecognizer.delegate = self; - [_rightHandle addGestureRecognizer:_rightGestureRecognizer]; - } - return self; -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - bool (^isTracking)(UIGestureRecognizer *) = ^bool (UIGestureRecognizer *recognizer) - { - return (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged); - }; - - if (self.entityView.shouldTouchEntity != nil && !self.entityView.shouldTouchEntity(self.entityView)) - return false; - - if (gestureRecognizer == _leftGestureRecognizer) - return !isTracking(_rightGestureRecognizer); - - if (gestureRecognizer == _rightGestureRecognizer) - return !isTracking(_leftGestureRecognizer); - - return true; -} - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - UIView *view = [super hitTest:point withEvent:event]; - if (view == self) - return nil; - - return view; -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)__unused event -{ - return CGRectContainsPoint(CGRectInset(self.bounds, -10.0f, -10.0f), point); -} - -- (bool)isTracking -{ - bool (^isTracking)(UIGestureRecognizer *) = ^bool (UIGestureRecognizer *recognizer) - { - return (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged); - }; - - return isTracking(_leftGestureRecognizer) || isTracking(_rightGestureRecognizer); -} - -- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer -{ - CGPoint parentLocation = [gestureRecognizer locationInView:self.superview]; - - if (gestureRecognizer.state == UIGestureRecognizerStateChanged) - { - CGFloat deltaX = [gestureRecognizer translationInView:self].x; - if (gestureRecognizer.view == _leftHandle) - deltaX *= - 1; - CGFloat scaleDelta = (self.bounds.size.width + deltaX * 2) / self.bounds.size.width; - - if (self.entityResized != nil) - self.entityResized(scaleDelta); - - CGFloat angle = 0.0f; - if (gestureRecognizer.view == _leftHandle) - angle = atan2(self.center.y - parentLocation.y, self.center.x - parentLocation.x); - if (gestureRecognizer.view == _rightHandle) - angle = atan2(parentLocation.y - self.center.y, parentLocation.x - self.center.x); - - if (self.entityRotated != nil) - self.entityRotated(angle); - - [gestureRecognizer setTranslation:CGPointZero inView:self]; - } -} - -- (void)drawRect:(CGRect)rect -{ - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGFloat thickness = 1.5f; - CGFloat radius = rect.size.width / 2.0f - 5.5f; - - UIColor *color = UIColorRGBA(0xeaeaea, 0.8); - - CGContextSetFillColorWithColor(context, color.CGColor); - - CGFloat radSpace = TGDegreesToRadians(4.0f); - CGFloat radLen = TGDegreesToRadians(4.0f); - - CGPoint centerPoint = TGPaintCenterOfRect(rect); - - for (NSInteger i = 0; i < 48; i++) - { - CGMutablePathRef path = CGPathCreateMutable(); - - CGPathAddArc(path, NULL, centerPoint.x, centerPoint.y, radius, i * (radSpace + radLen), i * (radSpace + radLen) + radLen, false); - - CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(path, NULL, thickness, kCGLineCapButt, kCGLineJoinMiter, 10); - - CGContextAddPath(context, strokedArc); - - CGPathRelease(strokedArc); - CGPathRelease(path); - } - - CGContextFillPath(context); - - CGContextSetStrokeColorWithColor(context, color.CGColor); - CGContextSetLineWidth(context, thickness); - - void (^drawEllipse)(CGPoint, bool) = ^(CGPoint center, bool clear) - { - CGRect rect = CGRectMake(center.x - 4.5f, center.y - 4.5f, 9.0f, 9.0f); - if (clear) { - rect = CGRectInset(rect, -thickness, -thickness); - CGContextFillEllipseInRect(context, rect); - } else { - CGContextStrokeEllipseInRect(context, rect); - } - }; - - CGContextSetBlendMode(context, kCGBlendModeClear); - - drawEllipse(CGPointMake(5.5f, centerPoint.y), true); - drawEllipse(CGPointMake(rect.size.width - 5.5f, centerPoint.y), true); - - CGContextSetBlendMode(context, kCGBlendModeNormal); - - drawEllipse(CGPointMake(5.5f, centerPoint.y), false); - drawEllipse(CGPointMake(rect.size.width - 5.5f, centerPoint.y), false); -} - -- (void)layoutSubviews -{ - _leftHandle.frame = CGRectMake(-9.5f, floor((self.bounds.size.height - _leftHandle.frame.size.height) / 2.0f), _leftHandle.frame.size.width, _leftHandle.frame.size.height); - _rightHandle.frame = CGRectMake(self.bounds.size.width - _rightHandle.frame.size.width + 9.5f, floor((self.bounds.size.height - _rightHandle.frame.size.height) / 2.0f), _rightHandle.frame.size.width, _rightHandle.frame.size.height); -} - -@end - -@implementation UIView (OpaquePixel) - -- (bool)isOpaqueAtPoint:(CGPoint)point -{ - if (point.x > self.bounds.size.width || point.y > self.bounds.size.height) - return false; - - unsigned char pixel[4] = {0}; - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast); - - CGContextTranslateCTM(context, -point.x, -point.y); - - [self.layer renderInContext:context]; - - CGContextRelease(context); - CGColorSpaceRelease(colorSpace); - - return pixel[3] > 16; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoTextEntityView.h b/submodules/LegacyComponents/Sources/TGPhotoTextEntityView.h deleted file mode 100644 index 2a15e997bf..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoTextEntityView.h +++ /dev/null @@ -1,41 +0,0 @@ -#import "TGPhotoPaintEntityView.h" -#import "TGPhotoPaintTextEntity.h" - -@class TGPaintSwatch; - -@interface TGPhotoTextSelectionView : TGPhotoPaintEntitySelectionView - -@end - - -@interface TGPhotoTextEntityView : TGPhotoPaintEntityView - -@property (nonatomic, readonly) TGPhotoPaintTextEntity *entity; -@property (nonatomic, readonly) UIImage *image; - -@property (nonatomic, readonly) bool isEmpty; - -@property (nonatomic, copy) void (^beganEditing)(TGPhotoTextEntityView *); -@property (nonatomic, copy) void (^finishedEditing)(TGPhotoTextEntityView *); - -- (instancetype)initWithEntity:(TGPhotoPaintTextEntity *)entity; -- (void)setFont:(TGPhotoPaintFont *)font; -- (void)setSwatch:(TGPaintSwatch *)swatch; -- (void)setStyle:(TGPhotoPaintTextEntityStyle)style; - -@property (nonatomic, readonly) bool isEditing; -- (void)beginEditing; -- (void)endEditing; - -@end - - -@interface TGPhotoTextView : UITextView - -@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 diff --git a/submodules/LegacyComponents/Sources/TGPhotoTextEntityView.m b/submodules/LegacyComponents/Sources/TGPhotoTextEntityView.m deleted file mode 100644 index cdce772876..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoTextEntityView.m +++ /dev/null @@ -1,851 +0,0 @@ -#import "TGPhotoTextEntityView.h" - -#import "TGPaintSwatch.h" -#import "TGPhotoPaintFont.h" - -#import "TGColor.h" -#import "LegacyComponentsInternal.h" - -#import - -const CGFloat TGPhotoTextSelectionViewHandleSide = 30.0f; - -@interface TGPhotoTextView () - -@end - -@interface TGPhotoTextSelectionView () -{ - UIView *_leftHandle; - UIView *_rightHandle; - - UIPanGestureRecognizer *_leftGestureRecognizer; - UIPanGestureRecognizer *_rightGestureRecognizer; -} -@end - - -@interface TGPhotoTextLayoutManager : NSLayoutManager - -@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 - - -@interface TGPhotoTextEntityView () -{ - TGPaintSwatch *_swatch; - TGPhotoPaintFont *_font; - CGFloat _baseFontSize; - CGFloat _maxWidth; - TGPhotoPaintTextEntityStyle _style; - - TGPhotoTextView *_textView; -} -@end - -@implementation TGPhotoTextEntityView - -- (instancetype)initWithEntity:(TGPhotoPaintTextEntity *)entity -{ - self = [super initWithFrame:CGRectZero]; - if (self != nil) - { - _entityUUID = entity.uuid; - _baseFontSize = entity.baseFontSize; - _font = entity.font; - _maxWidth = entity.maxWidth; - - _textView = [[TGPhotoTextView alloc] initWithFrame:CGRectZero]; - _textView.clipsToBounds = false; - _textView.backgroundColor = [UIColor clearColor]; - _textView.delegate = self; - _textView.text = entity.text; - _textView.textColor = entity.swatch.color; - _textView.editable = false; - _textView.selectable = false; - _textView.contentInset = UIEdgeInsetsZero; - _textView.showsHorizontalScrollIndicator = false; - _textView.showsVerticalScrollIndicator = false;; - _textView.scrollsToTop = false; - _textView.scrollEnabled = false; - _textView.textContainerInset = UIEdgeInsetsZero; - _textView.textAlignment = NSTextAlignmentCenter; - _textView.minimumZoomScale = 1.0f; - _textView.maximumZoomScale = 1.0f; - _textView.keyboardAppearance = UIKeyboardAppearanceDark; - _textView.autocorrectionType = UITextAutocorrectionTypeNo; - _textView.spellCheckingType = UITextSpellCheckingTypeNo; - _textView.font = [UIFont boldSystemFontOfSize:_baseFontSize]; - _textView.typingAttributes = @{NSFontAttributeName: _textView.font}; -// _textView.frameWidthInset = floor(_baseFontSize * 0.03); - - [self setSwatch:entity.swatch]; - [self setStyle:entity.style]; - - [self addSubview:_textView]; - } - return self; -} - -- (bool)isEmpty -{ - return [_textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0; -} - -- (TGPhotoPaintTextEntity *)entity -{ - 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; - entity.position = self.center; - - return entity; -} - -- (UIImage *)image { - CGRect rect = self.bounds; - - UIGraphicsBeginImageContextWithOptions(CGSizeMake(rect.size.width, rect.size.height), false, 1.0f); - - [self drawViewHierarchyInRect:rect afterScreenUpdates:false]; - - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - return image; -} - -- (bool)isEditing -{ - return _textView.isFirstResponder; -} - -- (void)beginEditing -{ - if (self.beganEditing != nil) - self.beganEditing(self); - - _textView.editable = true; - _textView.selectable = true; - - [_textView.window makeKeyWindow]; - [_textView becomeFirstResponder]; -} - -- (void)endEditing -{ - [_textView resignFirstResponder]; - _textView.editable = false; - _textView.selectable = false; - - _textView.text = [_textView.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - - if (self.finishedEditing != nil) - self.finishedEditing(self); -} - -#pragma mark - - -- (void)textViewDidChange:(UITextView *)__unused textView -{ - [self sizeToFit]; - [_textView setNeedsDisplay]; -} - -#pragma mark - - -- (void)setSwatch:(TGPaintSwatch *)swatch -{ - _swatch = swatch; - [self updateColor]; -} - -- (void)setFont:(TGPhotoPaintFont *)font -{ - _font = font; - _textView.font = [UIFont boldSystemFontOfSize:_baseFontSize]; - _textView.typingAttributes = @{NSFontAttributeName: _textView.font}; -// _textView.frameWidthInset = floor(_baseFontSize * 0.03); - - [self sizeToFit]; -} - -- (void)setStyle:(TGPhotoPaintTextEntityStyle)style -{ - _style = style; - switch (_style) { - case TGPhotoPaintTextEntityStyleRegular: - _textView.layer.shadowColor = [UIColorRGB(0x000000) 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]; - [self setNeedsLayout]; -} - -- (void)updateColor -{ - switch (_style) { - case TGPhotoPaintTextEntityStyleRegular: - { - _textView.textColor = _swatch.color; - _textView.strokeColor = nil; - _textView.frameColor = nil; - } - break; - - case TGPhotoPaintTextEntityStyleOutlined: - { - _textView.textColor = UIColorRGB(0xffffff); - _textView.strokeColor = _swatch.color; - _textView.frameColor = nil; - } - break; - - case TGPhotoPaintTextEntityStyleFramed: - { - 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 = UIColorRGB(0x000000); - } else { - _textView.textColor = UIColorRGB(0xffffff); - } - _textView.strokeColor = nil; - _textView.frameColor = _swatch.color; - } - break; - } -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)__unused event -{ - CGFloat x = floor(_textView.font.pointSize / 2.2f); - CGFloat y = floor(_textView.font.pointSize / 3.2f); - if (self.selectionView != nil) - return CGRectContainsPoint(CGRectInset(self.bounds, -(x + 10), -(y + 10)), point); - else - return [_textView pointInside:[_textView convertPoint:point fromView:self] withEvent:nil]; -} - -- (bool)precisePointInside:(CGPoint)point -{ - return [_textView pointInside:[_textView convertPoint:point fromView:self] withEvent:nil]; -} - -- (CGSize)sizeThatFits:(CGSize)__unused size -{ - CGSize result = [_textView sizeThatFits:CGSizeMake(_maxWidth, FLT_MAX)]; - result.width = MAX(224, ceil(result.width) + 20.0f); - result.height = ceil(result.height) + 20.0f + _textView.font.pointSize * _font.sizeCorrection; - return result; -} - -- (void)sizeToFit -{ - CGPoint center = self.center; - CGAffineTransform transform = self.transform; - self.transform = CGAffineTransformIdentity; - [super sizeToFit]; - self.center = center; - self.transform = transform; - - if (self.entityChanged != nil) - self.entityChanged(self); -} - -- (CGRect)selectionBounds -{ - CGFloat x = floor(_textView.font.pointSize / 2.8f); - CGFloat y = floor(_textView.font.pointSize / 4.0f); - CGRect bounds = CGRectInset(self.bounds, -x, -y); - CGSize size = CGSizeMake(bounds.size.width * self.scale, bounds.size.height * self.scale); - return CGRectMake((self.bounds.size.width - size.width) / 2.0f, (self.bounds.size.height - size.height) / 2.0f, size.width, size.height); -} - -- (TGPhotoPaintEntitySelectionView *)createSelectionView -{ - TGPhotoTextSelectionView *view = [[TGPhotoTextSelectionView alloc] init]; - view.entityView = self; - return view; -} - -- (void)layoutSubviews -{ - CGRect rect = self.bounds; - CGFloat correction = _textView.font.pointSize * _font.sizeCorrection; - rect.origin.y += correction; - rect.size.height -= correction; - rect = CGRectOffset(rect, 0.0f, 10.0f); - - _textView.frame = rect; -} - -@end - - -@implementation TGPhotoTextSelectionView - -- (instancetype)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self != nil) - { - self.backgroundColor = [UIColor clearColor]; - self.contentMode = UIViewContentModeRedraw; - - _leftHandle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, TGPhotoTextSelectionViewHandleSide, TGPhotoTextSelectionViewHandleSide)]; - [self addSubview:_leftHandle]; - - _leftGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _leftGestureRecognizer.delegate = self; - [_leftHandle addGestureRecognizer:_leftGestureRecognizer]; - - _rightHandle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, TGPhotoTextSelectionViewHandleSide, TGPhotoTextSelectionViewHandleSide)]; - [self addSubview:_rightHandle]; - - _rightGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; - _rightGestureRecognizer.delegate = self; - [_rightHandle addGestureRecognizer:_rightGestureRecognizer]; - } - return self; -} - -- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer -{ - bool (^isTracking)(UIGestureRecognizer *) = ^bool (UIGestureRecognizer *recognizer) - { - return (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged); - }; - - if (self.entityView.shouldTouchEntity != nil && !self.entityView.shouldTouchEntity(self.entityView)) - return false; - - if (gestureRecognizer == _leftGestureRecognizer) - return !isTracking(_rightGestureRecognizer); - - if (gestureRecognizer == _rightGestureRecognizer) - return !isTracking(_leftGestureRecognizer); - - return true; -} - -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event -{ - UIView *view = [super hitTest:point withEvent:event]; - if (view == self) - return nil; - - return view; -} - -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)__unused event -{ - return CGRectContainsPoint(CGRectInset(self.bounds, -10.0f, -10.0f), point); -} - -- (bool)isTracking -{ - bool (^isTracking)(UIGestureRecognizer *) = ^bool (UIGestureRecognizer *recognizer) - { - return (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged); - }; - - return isTracking(_leftGestureRecognizer) || isTracking(_rightGestureRecognizer); -} - -- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer -{ - CGPoint parentLocation = [gestureRecognizer locationInView:self.superview]; - - if (gestureRecognizer.state == UIGestureRecognizerStateChanged) - { - CGFloat deltaX = [gestureRecognizer translationInView:self].x; - if (gestureRecognizer.view == _leftHandle) - deltaX *= - 1; - CGFloat scaleDelta = (self.bounds.size.width + deltaX * 2) / self.bounds.size.width; - - if (self.entityResized != nil) - self.entityResized(scaleDelta); - - CGFloat angle = 0.0f; - if (gestureRecognizer.view == _leftHandle) - angle = atan2(self.center.y - parentLocation.y, self.center.x - parentLocation.x); - if (gestureRecognizer.view == _rightHandle) - angle = atan2(parentLocation.y - self.center.y, parentLocation.x - self.center.x); - - if (self.entityRotated != nil) - self.entityRotated(angle); - - [gestureRecognizer setTranslation:CGPointZero inView:self]; - } -} - -- (void)drawRect:(CGRect)rect -{ - CGContextRef context = UIGraphicsGetCurrentContext(); - - CGFloat space = 4.0f; - CGFloat length = 4.5f; - CGFloat thickness = 1.5f; - CGRect selectionBounds = CGRectInset(rect, 5.5f, 5.5f); - - UIColor *color = UIColorRGBA(0xeaeaea, 0.8); - - CGContextSetFillColorWithColor(context, color.CGColor); - - CGPoint centerPoint = TGPaintCenterOfRect(rect); - - NSInteger xCount = (NSInteger)(floor(selectionBounds.size.width / (space + length))); - CGFloat xGap = ceil(((selectionBounds.size.width - xCount * (space + length)) + space) / 2.0f); - for (NSInteger i = 0; i < xCount; i++) - { - CGContextAddRect(context, CGRectMake(xGap + selectionBounds.origin.x + i * (length + space), selectionBounds.origin.y - thickness / 2.0f, length, thickness)); - - CGContextAddRect(context, CGRectMake(xGap + selectionBounds.origin.x + i * (length + space), selectionBounds.origin.y + selectionBounds.size.height - thickness / 2.0f, length, thickness)); - } - - NSInteger yCount = (NSInteger)(floor(selectionBounds.size.height / (space + length))); - CGFloat yGap = ceil(((selectionBounds.size.height - yCount * (space + length)) + space) / 2.0f); - for (NSInteger i = 0; i < yCount; i++) - { - CGContextAddRect(context, CGRectMake(selectionBounds.origin.x - thickness / 2.0f, yGap + selectionBounds.origin.y + i * (length + space), thickness, length)); - - CGContextAddRect(context, CGRectMake(selectionBounds.origin.x + selectionBounds.size.width - thickness / 2.0f, yGap + selectionBounds.origin.y + i * (length + space), thickness, length)); - } - - CGContextFillPath(context); - - CGContextSetStrokeColorWithColor(context, color.CGColor); - CGContextSetLineWidth(context, thickness); - - void (^drawEllipse)(CGPoint, bool) = ^(CGPoint center, bool clear) - { - CGRect rect = CGRectMake(center.x - 4.5f, center.y - 4.5f, 9.0f, 9.0f); - if (clear) { - rect = CGRectInset(rect, -thickness, -thickness); - CGContextFillEllipseInRect(context, rect); - } else { - CGContextStrokeEllipseInRect(context, rect); - } - }; - - CGContextSetBlendMode(context, kCGBlendModeClear); - - drawEllipse(CGPointMake(5.5f, centerPoint.y), true); - drawEllipse(CGPointMake(rect.size.width - 5.5f, centerPoint.y), true); - - CGContextSetBlendMode(context, kCGBlendModeNormal); - - drawEllipse(CGPointMake(5.5f, centerPoint.y), false); - drawEllipse(CGPointMake(rect.size.width - 5.5f, centerPoint.y), false); -} - -- (void)layoutSubviews -{ - _leftHandle.frame = CGRectMake(-9.5f, floor((self.bounds.size.height - _leftHandle.frame.size.height) / 2.0f), _leftHandle.frame.size.width, _leftHandle.frame.size.height); - _rightHandle.frame = CGRectMake(self.bounds.size.width - _rightHandle.frame.size.width + 9.5f, floor((self.bounds.size.height - _rightHandle.frame.size.height) / 2.0f), _rightHandle.frame.size.width, _rightHandle.frame.size.height); -} - -@end - - -@implementation TGPhotoTextView -{ - UIFont *_font; - UIColor *_forcedTextColor; -} - -- (instancetype)initWithFrame:(CGRect)frame -{ - TGPhotoTextStorage *textStorage = [[TGPhotoTextStorage alloc] init]; - TGPhotoTextLayoutManager *layoutManager = [[TGPhotoTextLayoutManager alloc] init]; - - NSTextContainer *container = [[NSTextContainer alloc] initWithSize:CGSizeMake(0.0f, CGFLOAT_MAX)]; - container.widthTracksTextView = true; - [layoutManager addTextContainer:container]; - [textStorage addLayoutManager:layoutManager]; - - return [self initWithFrame:frame textContainer:container]; -} - -- (CGRect)caretRectForPosition:(UITextPosition *)position -{ - CGRect rect = [super caretRectForPosition:position]; - rect.size.width = rect.size.height / 25.0f; - return rect; -} - -- (CGFloat)strokeWidth -{ - return ((TGPhotoTextLayoutManager *)self.layoutManager).strokeWidth; -} - -- (void)setStrokeWidth:(CGFloat)strokeWidth -{ - [(TGPhotoTextLayoutManager *)self.layoutManager setStrokeWidth:strokeWidth]; - [self setNeedsDisplay]; -} - -- (UIColor *)strokeColor -{ - return ((TGPhotoTextLayoutManager *)self.layoutManager).strokeColor; -} - -- (void)setStrokeColor:(UIColor *)strokeColor -{ - [(TGPhotoTextLayoutManager *)self.layoutManager setStrokeColor:strokeColor]; - [self setNeedsDisplay]; -} - -- (CGPoint)strokeOffset -{ - return ((TGPhotoTextLayoutManager *)self.layoutManager).strokeOffset; -} - -- (void)setStrokeOffset:(CGPoint)strokeOffset -{ - [(TGPhotoTextLayoutManager *)self.layoutManager setStrokeOffset:strokeOffset]; - [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]; - _font = font; - - self.layoutManager.textContainers.firstObject.lineFragmentPadding = floor(font.pointSize * 0.3); -} - -- (void)setTextColor:(UIColor *)textColor { - _forcedTextColor = textColor; - [super setTextColor:textColor]; -} - -- (void)insertText:(NSString *)text { - [self fixTypingAttributes]; - [super insertText:text]; - [self fixTypingAttributes]; -} - -- (void)paste:(id)sender { - [self fixTypingAttributes]; - [super paste:sender]; - [self fixTypingAttributes]; -} - -- (void)fixTypingAttributes { - NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init]; - if (_font != nil) { - attributes[NSFontAttributeName] = _font; - } - if (_forcedTextColor != nil) { - attributes[NSForegroundColorAttributeName] = _forcedTextColor; - } - self.typingAttributes = attributes; -} - -@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 *)attributes inContext:(CGContextRef)context -{ - if (self.strokeColor != nil) - { - CGContextSetStrokeColorWithColor(context, self.strokeColor.CGColor); - CGContextSetLineJoin(context, kCGLineJoinRound); - - CGFloat lineWidth = self.strokeWidth > FLT_EPSILON ? self.strokeWidth : floor(font.pointSize / 9.0f); - CGContextSetLineWidth(context, lineWidth); - CGContextSetTextDrawingMode(context, kCGTextStroke); - - CGContextSaveGState(context); - CGContextTranslateCTM(context, self.strokeOffset.x, self.strokeOffset.y); - - [super showCGGlyphs:glyphs positions:positions count:glyphCount font:font matrix:textMatrix attributes:attributes inContext:context]; - - CGContextRestoreGState(context); - CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); - CGContextSetTextDrawingMode(context, kCGTextFill); - } - [super showCGGlyphs:glyphs positions:positions count:glyphCount font:font matrix:textMatrix attributes:attributes inContext:context]; -} - -- (void)prepare { - _path = nil; - [self.rectArray removeAllObjects]; - - [self enumerateLineFragmentsForGlyphRange:NSMakeRange(0, self.textStorage.string.length) usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) { - bool ignoreRange = false; - NSRange characterRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:nil]; - NSString *substring = [[self.textStorage string] substringWithRange:characterRange]; - if ([substring stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]].length == 0) { - ignoreRange = true; - } - - if (!ignoreRange) { - 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]; -} - -- (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin { -// [super drawBackgroundForGlyphRange:glyphsToShow atPoint:origin]; - - if (self.frameColor != nil) { - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSaveGState(context); - CGContextTranslateCTM(context, origin.x, origin.y); - - CGContextSetBlendMode(context, kCGBlendModeNormal); - CGContextSetFillColorWithColor(context, self.frameColor.CGColor); - CGContextSetStrokeColorWithColor(context, self.frameColor.CGColor); - - [self prepare]; -// _path = nil; -// [self.rectArray removeAllObjects]; -// -// [self enumerateLineFragmentsForGlyphRange:glyphRange usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) { -// bool ignoreRange = false; -// NSString *substring = [[self.textStorage string] substringWithRange:glyphRange]; -// if ([substring stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]].length == 0) { -// ignoreRange = true; -// } -// -// if (!ignoreRange) { -// 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]; - - CGRect last = CGRectNull; - 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]]; - if (i == 0) { - last = cur; - } else if (i > 0 && fabs(CGRectGetMaxY(last) - CGRectGetMinY(cur)) < 10.0) { - 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]; - } - - last = cur; - } - } - [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 *)attrs range:(NSRange)range { - [self beginEditing]; - [_impl setAttributes:attrs range:range]; - [self edited:NSTextStorageEditedAttributes range:range changeInLength:0]; - [self endEditing]; -} - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoTextSettingsView.h b/submodules/LegacyComponents/Sources/TGPhotoTextSettingsView.h deleted file mode 100644 index 8881778372..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoTextSettingsView.h +++ /dev/null @@ -1,13 +0,0 @@ -#import -#import "TGPhotoPaintSettingsView.h" -#import "TGPhotoPaintFont.h" -#import "TGPhotoPaintTextEntity.h" - -@interface TGPhotoTextSettingsView : UIView - -@property (nonatomic, copy) void (^fontChanged)(TGPhotoPaintFont *font); -@property (nonatomic, copy) void (^styleChanged)(TGPhotoPaintTextEntityStyle style); - -- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)font selectedStyle:(TGPhotoPaintTextEntityStyle)selectedStyle; - -@end diff --git a/submodules/LegacyComponents/Sources/TGPhotoTextSettingsView.m b/submodules/LegacyComponents/Sources/TGPhotoTextSettingsView.m deleted file mode 100644 index b05b2d5bd2..0000000000 --- a/submodules/LegacyComponents/Sources/TGPhotoTextSettingsView.m +++ /dev/null @@ -1,217 +0,0 @@ -#import "TGPhotoTextSettingsView.h" - -#import "LegacyComponentsInternal.h" -#import "TGImageUtils.h" - -#import "TGPhotoEditorSliderView.h" - -#import -#import "TGPhotoTextEntityView.h" - -const CGFloat TGPhotoTextSettingsViewMargin = 10.0f; -const CGFloat TGPhotoTextSettingsItemHeight = 44.0f; - -@interface TGPhotoTextSettingsView () -{ - NSArray *_fonts; - - UIInterfaceOrientation _interfaceOrientation; - - UIView *_wrapperView; - UIView *_contentView; - UIVisualEffectView *_effectView; - - NSArray *_fontViews; - NSArray *_fontIconViews; - NSArray *_fontSeparatorViews; -} -@end - -@implementation TGPhotoTextSettingsView - -@synthesize interfaceOrientation = _interfaceOrientation; - -- (instancetype)initWithFonts:(NSArray *)fonts selectedFont:(TGPhotoPaintFont *)__unused selectedFont selectedStyle:(TGPhotoPaintTextEntityStyle)selectedStyle -{ - self = [super initWithFrame:CGRectZero]; - if (self) - { - _fonts = fonts; - - _interfaceOrientation = UIInterfaceOrientationPortrait; - - _wrapperView = [[UIView alloc] init]; - _wrapperView.clipsToBounds = true; - _wrapperView.layer.cornerRadius = 12.0; - [self addSubview:_wrapperView]; - - _effectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]]; - _effectView.alpha = 0.0f; - _effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [_wrapperView addSubview:_effectView]; - - _contentView = [[UIView alloc] init]; - _contentView.alpha = 0.0f; - _contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [_wrapperView addSubview:_contentView]; - - NSMutableArray *fontViews = [[NSMutableArray alloc] init]; - NSMutableArray *fontIconViews = [[NSMutableArray alloc] init]; - NSMutableArray *separatorViews = [[NSMutableArray alloc] init]; - - UIFont *font = [UIFont systemFontOfSize:17]; - - TGModernButton *frameButton = [[TGModernButton alloc] initWithFrame:CGRectZero]; - frameButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; - frameButton.titleLabel.font = font; - frameButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f); - frameButton.tag = TGPhotoPaintTextEntityStyleFramed; - [frameButton setTitle:TGLocalized(@"Paint.Framed") forState:UIControlStateNormal]; - [frameButton setTitleColor:[UIColor whiteColor]]; - [frameButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside]; - [_contentView addSubview:frameButton]; - [fontViews addObject:frameButton]; - - UIImageView *iconView = [[UIImageView alloc] initWithImage:TGTintedImage([UIImage imageNamed:@"Editor/TextFramed"], [UIColor whiteColor])]; - [frameButton addSubview:iconView]; - [fontIconViews addObject:iconView]; - - TGModernButton *outlineButton = [[TGModernButton alloc] initWithFrame:CGRectZero]; - outlineButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; - outlineButton.titleLabel.font = font; - outlineButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f); - outlineButton.tag = TGPhotoPaintTextEntityStyleOutlined; - [outlineButton setTitle:TGLocalized(@"Paint.Outlined") forState:UIControlStateNormal]; - [outlineButton setTitleColor:[UIColor whiteColor]]; - [outlineButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside]; - [_contentView addSubview:outlineButton]; - [fontViews addObject:outlineButton]; - - iconView = [[UIImageView alloc] initWithImage:TGTintedImage([UIImage imageNamed:@"Editor/TextOutlined"], [UIColor whiteColor])]; - [outlineButton addSubview:iconView]; - [fontIconViews addObject:iconView]; - - UIView *separatorView = [[UIView alloc] init]; - separatorView.backgroundColor = UIColorRGBA(0xffffff, 0.2); - [_contentView addSubview:separatorView]; - [separatorViews addObject:separatorView]; - - TGModernButton *regularButton = [[TGModernButton alloc] initWithFrame:CGRectZero]; - regularButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; - regularButton.titleLabel.font = font; - regularButton.contentEdgeInsets = UIEdgeInsetsMake(0.0f, 16.0f, 0.0f, 0.0f); - regularButton.tag = TGPhotoPaintTextEntityStyleRegular; - [regularButton setTitle:TGLocalized(@"Paint.Regular") forState:UIControlStateNormal]; - [regularButton setTitleColor:[UIColor whiteColor]]; - [regularButton addTarget:self action:@selector(styleValueChanged:) forControlEvents:UIControlEventTouchUpInside]; - [_contentView addSubview:regularButton]; - [fontViews addObject:regularButton]; - - iconView = [[UIImageView alloc] initWithImage:TGTintedImage([UIImage imageNamed:@"Editor/TextRegular"], [UIColor whiteColor])]; - [regularButton addSubview:iconView]; - [fontIconViews addObject:iconView]; - - separatorView = [[UIView alloc] init]; - separatorView.backgroundColor = UIColorRGBA(0xffffff, 0.2); - [_contentView addSubview:separatorView]; - [separatorViews addObject:separatorView]; - - _fontViews = fontViews; - _fontIconViews = fontIconViews; - _fontSeparatorViews = separatorViews; - } - return self; -} - -- (void)fontButtonPressed:(TGModernButton *)sender -{ - if (self.fontChanged != nil) - self.fontChanged(_fonts[sender.tag]); -} - -- (void)styleValueChanged:(TGModernButton *)sender -{ - if (self.styleChanged != nil) - self.styleChanged((TGPhotoPaintTextEntityStyle)sender.tag); -} - -- (void)present -{ - [UIView animateWithDuration:0.25 animations:^ - { - _effectView.alpha = 1.0f; - _contentView.alpha = 1.0f; - } completion:^(__unused BOOL finished) - { - - }]; -} - -- (void)dismissWithCompletion:(void (^)(void))completion -{ - [UIView animateWithDuration:0.2 animations:^ - { - _effectView.alpha = 0.0f; - _contentView.alpha = 0.0f; - } completion:^(__unused BOOL finished) - { - if (completion != nil) - completion(); - }]; -} - -- (CGSize)sizeThatFits:(CGSize)__unused size -{ - return CGSizeMake(220, _fontViews.count * TGPhotoTextSettingsItemHeight + TGPhotoTextSettingsViewMargin * 2); -} - -- (void)setInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - _interfaceOrientation = interfaceOrientation; - - [self setNeedsLayout]; -} - -- (void)layoutSubviews -{ - CGFloat arrowSize = 0.0f; - switch (self.interfaceOrientation) - { - case UIInterfaceOrientationLandscapeLeft: - { - _wrapperView.frame = CGRectMake(TGPhotoTextSettingsViewMargin - arrowSize, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2); - } - break; - - case UIInterfaceOrientationLandscapeRight: - { - _wrapperView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2 + arrowSize, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2); - } - break; - - default: - { - _wrapperView.frame = CGRectMake(TGPhotoTextSettingsViewMargin, TGPhotoTextSettingsViewMargin, self.frame.size.width - TGPhotoTextSettingsViewMargin * 2, self.frame.size.height - TGPhotoTextSettingsViewMargin * 2 + arrowSize); - } - break; - } - - CGFloat thickness = TGScreenPixel; - - [_fontViews enumerateObjectsUsingBlock:^(TGModernButton *view, NSUInteger index, __unused BOOL *stop) - { - view.frame = CGRectMake(0.0, TGPhotoTextSettingsItemHeight * index, _contentView.frame.size.width, TGPhotoTextSettingsItemHeight); - }]; - - [_fontIconViews enumerateObjectsUsingBlock:^(UIImageView *view, NSUInteger index, __unused BOOL *stop) - { - view.frame = CGRectMake(_contentView.frame.size.width - 42.0f, (TGPhotoTextSettingsItemHeight - view.frame.size.height) / 2.0, view.frame.size.width, view.frame.size.height); - }]; - - [_fontSeparatorViews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger index, __unused BOOL *stop) - { - view.frame = CGRectMake(0.0, TGPhotoTextSettingsItemHeight * (index + 1), _contentView.frame.size.width, thickness); - }]; -} - -@end diff --git a/submodules/TelegramUI/Images.xcassets/Media Editor/FontArrow.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Editor/FontArrow.imageset/Contents.json new file mode 100644 index 0000000000..85ccbd81c9 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Editor/FontArrow.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "expand.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Media Editor/FontArrow.imageset/expand.pdf b/submodules/TelegramUI/Images.xcassets/Media Editor/FontArrow.imageset/expand.pdf new file mode 100644 index 0000000000..91d9147841 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Editor/FontArrow.imageset/expand.pdf @@ -0,0 +1,119 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.669922 0.577759 cm +1.000000 1.000000 1.000000 scn +-0.406158 10.608799 m +-0.696966 10.384483 -0.750870 9.966894 -0.526556 9.676085 c +-0.302241 9.385277 0.115349 9.331373 0.406158 9.555687 c +-0.406158 10.608799 l +h +4.330078 13.422241 m +4.736245 13.948790 l +4.496933 14.133389 4.163235 14.133392 3.923920 13.948797 c +4.330078 13.422241 l +h +8.253833 9.555695 m +8.544638 9.331375 8.962229 9.385271 9.186548 9.676076 c +9.410869 9.966881 9.356972 10.384472 9.066167 10.608791 c +8.253833 9.555695 l +h +0.406158 5.288795 m +0.115349 5.513110 -0.302241 5.459206 -0.526556 5.168397 c +-0.750870 4.877588 -0.696966 4.459998 -0.406158 4.235683 c +0.406158 5.288795 l +h +4.330078 1.422241 m +3.923920 0.895685 l +4.163235 0.711090 4.496933 0.711093 4.736245 0.895693 c +4.330078 1.422241 l +h +9.066167 4.235691 m +9.356972 4.460011 9.410869 4.877602 9.186548 5.168406 c +8.962229 5.459211 8.544638 5.513108 8.253833 5.288788 c +9.066167 4.235691 l +h +0.406158 9.555687 m +4.736236 12.895685 l +3.923920 13.948797 l +-0.406158 10.608799 l +0.406158 9.555687 l +h +3.923911 12.895693 m +8.253833 9.555695 l +9.066167 10.608791 l +4.736245 13.948790 l +3.923911 12.895693 l +h +-0.406158 4.235683 m +3.923920 0.895685 l +4.736236 1.948797 l +0.406158 5.288795 l +-0.406158 4.235683 l +h +4.736245 0.895693 m +9.066167 4.235691 l +8.253833 5.288788 l +3.923911 1.948790 l +4.736245 0.895693 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1417 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001507 00000 n +0000001530 00000 n +0000001703 00000 n +0000001777 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1836 +%%EOF \ No newline at end of file