Drawing improvements
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -9,7 +9,7 @@
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Round.png",
|
||||
"filename" : "spectrum.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 9.8 KiB |
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/RoundSpectrum.imageset/spectrum.png
vendored
Normal file
After Width: | Height: | Size: 8.8 KiB |
21
submodules/TelegramUI/Images.xcassets/Media Editor/ToolArrow.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/ToolArrow.imageset/arrow base.png
vendored
Normal file
After Width: | Height: | Size: 4.9 KiB |
@ -9,7 +9,7 @@
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "pencil.png",
|
||||
"filename" : "arrow tip.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/ToolArrowTip.imageset/arrow tip.png
vendored
Normal file
After Width: | Height: | Size: 2.1 KiB |
21
submodules/TelegramUI/Images.xcassets/Media Editor/ToolBlur.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/ToolBlur.imageset/blur base.png
vendored
Normal file
After Width: | Height: | Size: 8.4 KiB |
@ -9,7 +9,7 @@
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "pencil.png",
|
||||
"filename" : "blur tip.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Media Editor/ToolBlurTip.imageset/blur tip.png
vendored
Normal file
After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 485 B |