Drawing improvements

This commit is contained in:
Ilya Laktyushin 2022-12-18 19:23:17 +04:00
parent e380fdf6b7
commit 687fc7d5e8
18 changed files with 536 additions and 801 deletions

View File

@ -1744,7 +1744,7 @@ final class ColorSwatchComponent: Component {
if case .pallete = component.type {
contentSize = availableSize
} else {
contentSize = CGSize(width: 33.0, height: 33.0)
contentSize = CGSize(width: 24.0, height: 24.0)
}
self.contentView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - contentSize.width) / 2.0), y: floor((availableSize.height - contentSize.height) / 2.0)), size: contentSize)
@ -1753,44 +1753,20 @@ final class ColorSwatchComponent: Component {
case .main:
self.circleLayer.frame = bounds
if self.circleLayer.path == nil {
self.circleLayer.path = UIBezierPath(ovalIn: bounds.insetBy(dx: 7.0, dy: 7.0)).cgPath
self.circleLayer.path = UIBezierPath(ovalIn: bounds.insetBy(dx: 3.0, dy: 3.0)).cgPath
}
let ringFrame = bounds.insetBy(dx: -1.0, dy: -1.0)
if self.ringLayer == nil {
if #available(iOS 12.0, *) {
let ringLayer = SimpleGradientLayer()
ringLayer.rasterizationScale = UIScreen.main.scale
ringLayer.shouldRasterize = true
ringLayer.type = .conic
ringLayer.colors = [
UIColor(rgb: 0xe1564c).cgColor,
UIColor(rgb: 0xad4dc9).cgColor,
UIColor(rgb: 0x579ff2).cgColor,
UIColor(rgb: 0x4fcbd0).cgColor,
UIColor(rgb: 0x80e655).cgColor,
UIColor(rgb: 0xdad138).cgColor,
UIColor(rgb: 0xe59645).cgColor,
UIColor(rgb: 0xe1564c).cgColor
]
ringLayer.locations = [0.0, 0.15, 0.3, 0.45, 0.6, 0.75, 0.9, 1.0]
ringLayer.frame = bounds
ringLayer.startPoint = CGPoint(x: 0.5, y: 0.5)
ringLayer.endPoint = CGPoint(x: 1.0, y: 0.55)
self.contentView.layer.addSublayer(ringLayer)
let ringLayer = SimpleLayer()
ringLayer.contents = UIImage(bundleImageName: "Media Editor/RoundSpectrum")?.cgImage
ringLayer.frame = ringFrame
self.contentView.layer.addSublayer(ringLayer)
self.ringLayer = ringLayer
} else {
let ringLayer = SimpleLayer()
ringLayer.contents = UIImage(bundleImageName: "Media Editor/RoundSpectrum")?.cgImage
ringLayer.frame = bounds
self.contentView.layer.addSublayer(ringLayer)
self.ringLayer = ringLayer
}
self.ringLayer = ringLayer
let ringMaskLayer = SimpleShapeLayer()
ringMaskLayer.frame = bounds
ringMaskLayer.frame = CGRect(origin: .zero, size: ringFrame.size)
ringMaskLayer.strokeColor = UIColor.white.cgColor
ringMaskLayer.fillColor = UIColor.clear.cgColor
self.ringMaskLayer = ringMaskLayer
@ -1799,11 +1775,11 @@ final class ColorSwatchComponent: Component {
if let ringMaskLayer = self.ringMaskLayer {
if component.color == nil {
transition.setShapeLayerPath(layer: ringMaskLayer, path: UIBezierPath(ovalIn: CGRect(origin: .zero, size: contentSize).insetBy(dx: 8.25, dy: 8.25)).cgPath)
transition.setShapeLayerLineWidth(layer: ringMaskLayer, lineWidth: 16.5)
transition.setShapeLayerPath(layer: ringMaskLayer, path: UIBezierPath(ovalIn: CGRect(origin: .zero, size: ringFrame.size).insetBy(dx: 7.0, dy: 7.0)).cgPath)
transition.setShapeLayerLineWidth(layer: ringMaskLayer, lineWidth: 12.0)
} else {
transition.setShapeLayerPath(layer: ringMaskLayer, path: UIBezierPath(ovalIn: CGRect(origin: .zero, size: contentSize).insetBy(dx: 1.5, dy: 1.5)).cgPath)
transition.setShapeLayerLineWidth(layer: ringMaskLayer, lineWidth: 3.0)
transition.setShapeLayerPath(layer: ringMaskLayer, path: UIBezierPath(ovalIn: CGRect(origin: .zero, size: ringFrame.size).insetBy(dx: 1.0, dy: 1.0)).cgPath)
transition.setShapeLayerLineWidth(layer: ringMaskLayer, lineWidth: 2.0)
}
}
@ -1837,7 +1813,6 @@ final class ColorSwatchComponent: Component {
if let color = component.color {
self.circleLayer.fillColor = color.toCGColor()
if case .pallete = component.type {
if color.toUIColor().rgb == 0x000000 {
self.circleLayer.strokeColor = UIColor(rgb: 0x1f1f1f).cgColor
self.circleLayer.lineWidth = 1.0

File diff suppressed because it is too large Load Diff

View File

@ -615,41 +615,33 @@ public final class DrawingView: UIView, UIGestureRecognizerDelegate, TGPhotoDraw
self.tool = .pen
self.toolColor = brushState.color
self.toolBrushSize = brushState.size
self.toolHasArrow = brushState.mode == .arrow
self.toolHasArrow = false
case let .arrow(brushState):
self.drawingGesturePipeline?.mode = .location
self.tool = .pen
self.toolColor = brushState.color
self.toolBrushSize = brushState.size
self.toolHasArrow = true
case let .marker(brushState):
self.drawingGesturePipeline?.mode = .location
self.tool = .marker
self.toolColor = brushState.color
self.toolBrushSize = brushState.size
self.toolHasArrow = brushState.mode == .arrow
self.toolHasArrow = false
case let .neon(brushState):
self.drawingGesturePipeline?.mode = .smoothCurve
self.tool = .neon
self.toolColor = brushState.color
self.toolBrushSize = brushState.size
self.toolHasArrow = brushState.mode == .arrow
case let .pencil(brushState):
self.drawingGesturePipeline?.mode = .location
self.tool = .pencil
self.toolColor = brushState.color
self.toolBrushSize = brushState.size
self.toolHasArrow = brushState.mode == .arrow
case .lasso:
self.drawingGesturePipeline?.mode = .smoothCurve
self.tool = .lasso
self.toolHasArrow = false
case let .eraser(eraserState):
switch eraserState.mode {
case .bitmap:
self.tool = .eraser
self.drawingGesturePipeline?.mode = .smoothCurve
case .vector:
self.tool = .objectRemover
self.drawingGesturePipeline?.mode = .location
case .blur:
self.tool = .blur
self.drawingGesturePipeline?.mode = .smoothCurve
}
self.tool = .eraser
self.drawingGesturePipeline?.mode = .smoothCurve
self.toolBrushSize = eraserState.size
case let .blur(blurState):
self.tool = .blur
self.drawingGesturePipeline?.mode = .smoothCurve
self.toolBrushSize = blurState.size
}
if [.eraser, .blur].contains(self.tool) {

View File

@ -619,13 +619,16 @@ private func generateKnobImage() -> UIImage? {
final class TextSizeSliderComponent: Component {
let value: CGFloat
let updated: (CGFloat) -> Void
let released: () -> Void
public init(
value: CGFloat,
updated: @escaping (CGFloat) -> Void
updated: @escaping (CGFloat) -> Void,
released: @escaping () -> Void
) {
self.value = value
self.updated = updated
self.released = released
}
public static func ==(lhs: TextSizeSliderComponent, rhs: TextSizeSliderComponent) -> Bool {
@ -646,6 +649,7 @@ final class TextSizeSliderComponent: Component {
private let knob = SimpleLayer()
fileprivate var updated: (CGFloat) -> Void = { _ in }
fileprivate var released: () -> Void = { }
init() {
super.init(frame: CGRect())
@ -684,7 +688,7 @@ final class TextSizeSliderComponent: Component {
if let size = self.validSize, let component = self.component {
let _ = self.updateLayout(size: size, component: component, transition: .easeInOut(duration: 0.2))
}
self.released()
default:
break
}
@ -741,8 +745,10 @@ final class TextSizeSliderComponent: Component {
transition.setSublayerTransform(layer: self.knobContainer, transform: isTracking ? CATransform3DIdentity : CATransform3DMakeTranslation(4.0, 0.0, 0.0))
}
let knobTransition = self.isPanning ? transition.withAnimation(.none) : transition
let knobSize = CGSize(width: 52.0, height: 52.0)
self.knob.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - knobSize.width) / 2.0), y: -12.0 + floorToScreenPixels((size.height + 24.0 - knobSize.height) * (1.0 - component.value))), size: knobSize)
let knobFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - knobSize.width) / 2.0), y: -12.0 + floorToScreenPixels((size.height + 24.0 - knobSize.height) * (1.0 - component.value))), size: knobSize)
knobTransition.setFrame(layer: self.knob, frame: knobFrame)
transition.setFrame(view: self.backgroundNode.view, frame: CGRect(origin: CGPoint(), size: size))
self.backgroundNode.update(size: size, transition: transition.containedViewLayoutTransition)
@ -765,6 +771,7 @@ final class TextSizeSliderComponent: Component {
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
view.updated = self.updated
view.released = self.released
return view.updateLayout(size: availableSize, component: self, transition: transition)
}
}

View File

@ -16,12 +16,10 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
var isToolFocused = false
var isVisible = false
private var currentSize: CGFloat?
private var currentEraserMode: DrawingToolState.EraserState.Mode?
private let tip: UIImageView
private let background: SimpleLayer
private let band: SimpleGradientLayer
private let eraserType: SimpleLayer
var pressed: (DrawingToolState.Key) -> Void = { _ in }
var swiped: (DrawingToolState.Key, CGFloat) -> Void = { _, _ in }
@ -41,21 +39,19 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
self.band.endPoint = CGPoint(x: 1.0, y: 0.5)
self.band.masksToBounds = true
self.eraserType = SimpleLayer()
self.eraserType.opacity = 0.0
self.eraserType.transform = CATransform3DMakeScale(0.001, 0.001, 1.0)
let backgroundImage: UIImage?
let tipImage: UIImage?
var tipAbove = true
var hasBand = true
var hasEraserType = false
switch type {
case .pen:
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolPen")
tipImage = UIImage(bundleImageName: "Media Editor/ToolPenTip")?.withRenderingMode(.alwaysTemplate)
case .arrow:
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolArrow")
tipImage = UIImage(bundleImageName: "Media Editor/ToolArrowTip")?.withRenderingMode(.alwaysTemplate)
case .marker:
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolMarker")
tipImage = UIImage(bundleImageName: "Media Editor/ToolMarkerTip")?.withRenderingMode(.alwaysTemplate)
@ -64,19 +60,15 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolNeon")
tipImage = UIImage(bundleImageName: "Media Editor/ToolNeonTip")?.withRenderingMode(.alwaysTemplate)
tipAbove = false
case .pencil:
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolPencil")
tipImage = UIImage(bundleImageName: "Media Editor/ToolPencilTip")?.withRenderingMode(.alwaysTemplate)
case .lasso:
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolLasso")
tipImage = nil
hasBand = false
case .eraser:
self.eraserType.contents = UIImage(bundleImageName: "Media Editor/EraserRemove")?.cgImage
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolEraser")
tipImage = nil
hasBand = false
hasEraserType = true
case .blur:
backgroundImage = UIImage(bundleImageName: "Media Editor/ToolBlur")
tipImage = UIImage(bundleImageName: "Media Editor/ToolBlurTip")
tipAbove = false
hasBand = false
}
self.tip.image = tipImage
@ -90,9 +82,6 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
self.band.frame = CGRect(origin: CGPoint(x: 3.0, y: 64.0), size: CGSize(width: toolSize.width - 6.0, height: toolSize.width - 16.0))
self.band.anchorPoint = CGPoint(x: 0.5, y: 0.0)
self.eraserType.position = CGPoint(x: 20.0, y: 56.0)
self.eraserType.bounds = CGRect(origin: .zero, size: CGSize(width: 16.0, height: 16.0))
if tipAbove {
self.layer.addSublayer(self.background)
self.addSubview(self.tip)
@ -105,10 +94,6 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
self.layer.addSublayer(self.band)
}
if hasEraserType {
self.layer.addSublayer(self.eraserType)
}
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.addGestureRecognizer(tapGestureRecognizer)
@ -191,7 +176,7 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
var locations: [NSNumber] = [0.0, 1.0]
var colors: [CGColor] = []
switch self.type {
case .pen:
case .pen, .arrow:
locations = [0.0, 0.15, 0.85, 1.0]
colors = [
color.withMultipliedBrightnessBy(0.7).cgColor,
@ -215,16 +200,6 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
color.cgColor,
color.withMultipliedBrightnessBy(0.7).cgColor
]
case .pencil:
locations = [0.0, 0.25, 0.25, 0.75, 0.75, 1.0]
colors = [
color.withMultipliedBrightnessBy(0.85).cgColor,
color.withMultipliedBrightnessBy(0.85).cgColor,
color.withMultipliedBrightnessBy(1.15).cgColor,
color.withMultipliedBrightnessBy(1.15).cgColor,
color.withMultipliedBrightnessBy(0.85).cgColor,
color.withMultipliedBrightnessBy(0.85).cgColor
]
default:
return
}
@ -234,37 +209,6 @@ private class ToolView: UIView, UIGestureRecognizerDelegate {
self.band.locations = locations
self.band.colors = colors
}
if case .eraser = self.type {
let previousEraserMode = self.currentEraserMode
self.currentEraserMode = state.eraserMode
let transition = Transition(animation: Transition.Animation.curve(duration: 0.2, curve: .easeInOut))
if [.vector, .blur].contains(state.eraserMode) {
if !self.eraserType.opacity.isZero && (previousEraserMode != self.currentEraserMode) {
let snapshot = SimpleShapeLayer()
snapshot.contents = self.eraserType.contents
snapshot.frame = self.eraserType.frame
self.layer.addSublayer(snapshot)
snapshot.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak snapshot] _ in
snapshot?.removeFromSuperlayer()
})
snapshot.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
self.eraserType.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.eraserType.animateScale(from: 0.001, to: 1.0, duration: 0.2)
} else {
transition.setAlpha(layer: self.eraserType, alpha: 1.0)
transition.setScale(layer: self.eraserType, scale: 1.0)
}
self.eraserType.contents = UIImage(bundleImageName: state.eraserMode == .vector ? "Media Editor/EraserRemove" : "Media Editor/BrushBlur")?.cgImage
} else {
transition.setAlpha(layer: self.eraserType, alpha: 0.0)
transition.setScale(layer: self.eraserType, scale: 0.001)
}
}
}
}
@ -403,7 +347,7 @@ final class ToolsComponent: Component {
let view = self.toolViews[i]
var scale = 0.5
var verticalOffset: CGFloat = 34.0
var verticalOffset: CGFloat = 30.0
if i == selectedIndex {
if isFocused {
scale = 1.0

View File

@ -9,7 +9,7 @@
"scale" : "2x"
},
{
"filename" : "Round.png",
"filename" : "spectrum.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "arrow base.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -9,7 +9,7 @@
"scale" : "2x"
},
{
"filename" : "pencil.png",
"filename" : "arrow tip.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "blur base.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -9,7 +9,7 @@
"scale" : "2x"
},
{
"filename" : "pencil.png",
"filename" : "blur tip.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 485 B