Verified Commit 18b17808 authored by Geoff Pado's avatar Geoff Pado

Draw brush strokes in editing view

parent 2b288917
......@@ -41,6 +41,7 @@
043CD9DF227548F30012F5AE /* SettingsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043CD9DE227548F30012F5AE /* SettingsTableViewCell.swift */; };
043CD9E12275490E0012F5AE /* SettingsContentProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043CD9E02275490E0012F5AE /* SettingsContentProvider.swift */; };
043CD9E3227549330012F5AE /* SettingsTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043CD9E2227549330012F5AE /* SettingsTableViewDataSource.swift */; };
043CD9E52277EC910012F5AE /* PhotoEditingBrushStrokeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043CD9E42277EC910012F5AE /* PhotoEditingBrushStrokeView.swift */; };
047072932268134500FF20B6 /* PhotoEditingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 047072922268134500FF20B6 /* PhotoEditingView.swift */; };
047072952268137900FF20B6 /* PhotoEditingImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 047072942268137900FF20B6 /* PhotoEditingImageView.swift */; };
048909F2226571AB0048E203 /* PhotoEditingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 048909F1226571AB0048E203 /* PhotoEditingViewController.swift */; };
......@@ -102,6 +103,7 @@
043CD9DE227548F30012F5AE /* SettingsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewCell.swift; sourceTree = "<group>"; };
043CD9E02275490E0012F5AE /* SettingsContentProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsContentProvider.swift; sourceTree = "<group>"; };
043CD9E2227549330012F5AE /* SettingsTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewDataSource.swift; sourceTree = "<group>"; };
043CD9E42277EC910012F5AE /* PhotoEditingBrushStrokeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoEditingBrushStrokeView.swift; sourceTree = "<group>"; };
047072922268134500FF20B6 /* PhotoEditingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoEditingView.swift; sourceTree = "<group>"; };
047072942268137900FF20B6 /* PhotoEditingImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoEditingImageView.swift; sourceTree = "<group>"; };
048909F1226571AB0048E203 /* PhotoEditingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoEditingViewController.swift; sourceTree = "<group>"; };
......@@ -248,6 +250,7 @@
048909F1226571AB0048E203 /* PhotoEditingViewController.swift */,
043CD9CD226EB0B20012F5AE /* Text Detection */,
047072922268134500FF20B6 /* PhotoEditingView.swift */,
043CD9E42277EC910012F5AE /* PhotoEditingBrushStrokeView.swift */,
047072942268137900FF20B6 /* PhotoEditingImageView.swift */,
048909F3226573750048E203 /* PhotoEditorPresenting.swift */,
043CD9D52275316E0012F5AE /* PhotoEditingScrollView.swift */,
......@@ -436,6 +439,7 @@
041EFF6B225C36350058D8EE /* PhotoLibraryViewController.swift in Sources */,
043CD9DB22753D510012F5AE /* SettingsViewController.swift in Sources */,
041EFF70225C3D830058D8EE /* PhotoLibraryView.swift in Sources */,
043CD9E52277EC910012F5AE /* PhotoEditingBrushStrokeView.swift in Sources */,
043CD9C9226EB0400012F5AE /* TextRectangleDetector.swift in Sources */,
048909F2226571AB0048E203 /* PhotoEditingViewController.swift in Sources */,
041EFF552255A0B00058D8EE /* Colors.swift in Sources */,
......
// Created by Geoff Pado on 4/29/19.
// Copyright © 2019 Cocoatype, LLC. All rights reserved.
import UIKit
class PhotoEditingBrushStrokeView: UIControl {
init() {
super.init(frame: .zero)
backgroundColor = .clear
isOpaque = false
translatesAutoresizingMaskIntoConstraints = false
}
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let currentPath = currentPath else { return }
UIColor.black.setStroke()
currentPath.stroke()
}
// MARK: Touch Handling
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
currentPath = newPath()
currentPath?.move(to: touch.location(in: self))
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
currentPath?.addLine(to: touch.location(in: self))
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
sendActions(for: .touchUpInside)
currentPath = nil
setNeedsDisplay()
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
currentPath = nil
setNeedsDisplay()
}
// MARK: Path Manipulation
private(set) var currentPath: UIBezierPath?
private func newPath() -> UIBezierPath {
let newPath = UIBezierPath()
newPath.lineCapStyle = .round
newPath.lineJoinStyle = .round
newPath.lineWidth = adjustedLineWidth
return newPath
}
private var adjustedLineWidth: CGFloat {
guard let scrollView = self.scrollView else { return PhotoEditingBrushStrokeView.standardLineWidth }
return PhotoEditingBrushStrokeView.standardLineWidth * pow(scrollView.zoomScale, -1.0)
}
// MARK: Boilerplate
private static let standardLineWidth = CGFloat(10.0)
@available(*, unavailable)
required init(coder: NSCoder) {
let className = String(describing: type(of: self))
fatalError("\(className) does not implement init(coder:)")
}
}
......@@ -17,9 +17,13 @@ class PhotoEditingObservationVisualizationView: UIView {
guard let textObservations = textObservations else { return }
UIColor.black.setFill()
UIColor.red.withAlphaComponent(0.3).setFill()
UIColor.red.setStroke()
textObservations.forEach { observation in
UIBezierPath(rect: observation.bounds).fill()
let boundsPath = UIBezierPath(rect: observation.bounds)
boundsPath.fill()
boundsPath.stroke()
}
}
......
......@@ -12,6 +12,8 @@ class PhotoEditingScrollView: UIScrollView {
addSubview(photoEditingView)
panGestureRecognizer.minimumNumberOfTouches = 2
NSLayoutConstraint.activate([
photoEditingView.centerXAnchor.constraint(equalTo: contentLayoutGuide.centerXAnchor),
photoEditingView.centerYAnchor.constraint(equalTo: contentLayoutGuide.centerYAnchor),
......@@ -82,3 +84,13 @@ class PhotoEditingScrollView: UIScrollView {
fatalError("\(className) does not implement init(coder:)")
}
}
extension UIResponder {
var scrollView: UIScrollView? {
if let scrollView = (self as? UIScrollView) {
return scrollView
}
return next?.scrollView
}
}
......@@ -7,6 +7,7 @@ class PhotoEditingView: UIView {
init() {
imageView = PhotoEditingImageView()
visualizationView = PhotoEditingObservationVisualizationView()
brushStrokeView = PhotoEditingBrushStrokeView()
super.init(frame: .zero)
backgroundColor = .primary
......@@ -14,6 +15,7 @@ class PhotoEditingView: UIView {
addSubview(imageView)
addSubview(visualizationView)
addSubview(brushStrokeView)
NSLayoutConstraint.activate([
imageView.centerXAnchor.constraint(equalTo: centerXAnchor),
......@@ -23,8 +25,14 @@ class PhotoEditingView: UIView {
visualizationView.centerXAnchor.constraint(equalTo: centerXAnchor),
visualizationView.centerYAnchor.constraint(equalTo: centerYAnchor),
visualizationView.widthAnchor.constraint(equalTo: widthAnchor),
visualizationView.heightAnchor.constraint(equalTo: heightAnchor)
visualizationView.heightAnchor.constraint(equalTo: heightAnchor),
brushStrokeView.centerXAnchor.constraint(equalTo: centerXAnchor),
brushStrokeView.centerYAnchor.constraint(equalTo: centerYAnchor),
brushStrokeView.widthAnchor.constraint(equalTo: widthAnchor),
brushStrokeView.heightAnchor.constraint(equalTo: heightAnchor)
])
brushStrokeView.addTarget(self, action: #selector(handleStrokeCompletion), for: .touchUpInside)
}
var image: UIImage? {
......@@ -41,10 +49,18 @@ class PhotoEditingView: UIView {
}
}
// MARK: Actions
@objc func handleStrokeCompletion() {
guard let strokePath = brushStrokeView.currentPath else { return }
dump(strokePath)
}
// MARK: Boilerplate
private var imageView: PhotoEditingImageView
private var visualizationView: PhotoEditingObservationVisualizationView
private let imageView: PhotoEditingImageView
private let visualizationView: PhotoEditingObservationVisualizationView
private let brushStrokeView: PhotoEditingBrushStrokeView
@available(*, unavailable)
required init(coder: NSCoder) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment