mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-07-08 05:45:17 +02:00
wip: fix grid line
This commit is contained in:
@@ -119,6 +119,7 @@
|
|||||||
ECF7B2E02C39169C004D2C57 /* Image++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2CD2C39169C004D2C57 /* Image++.swift */; };
|
ECF7B2E02C39169C004D2C57 /* Image++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2CD2C39169C004D2C57 /* Image++.swift */; };
|
||||||
ECF7B2E12C39169C004D2C57 /* View++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2CE2C39169C004D2C57 /* View++.swift */; };
|
ECF7B2E12C39169C004D2C57 /* View++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2CE2C39169C004D2C57 /* View++.swift */; };
|
||||||
ECF7B2E42C39174D004D2C57 /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2E32C39174D004D2C57 /* Platform.swift */; };
|
ECF7B2E42C39174D004D2C57 /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2E32C39174D004D2C57 /* Platform.swift */; };
|
||||||
|
ECF7B2E72C39544E004D2C57 /* CenterClipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2E62C39544E004D2C57 /* CenterClipView.swift */; };
|
||||||
ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA151F2BEF21EF00455818 /* MemoObject.swift */; };
|
ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA151F2BEF21EF00455818 /* MemoObject.swift */; };
|
||||||
ECFA15222BEF21F500455818 /* CanvasObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15212BEF21F500455818 /* CanvasObject.swift */; };
|
ECFA15222BEF21F500455818 /* CanvasObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15212BEF21F500455818 /* CanvasObject.swift */; };
|
||||||
ECFA15242BEF223300455818 /* GraphicContextObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15232BEF223300455818 /* GraphicContextObject.swift */; };
|
ECFA15242BEF223300455818 /* GraphicContextObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15232BEF223300455818 /* GraphicContextObject.swift */; };
|
||||||
@@ -242,6 +243,8 @@
|
|||||||
ECF7B2CD2C39169C004D2C57 /* Image++.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Image++.swift"; sourceTree = "<group>"; };
|
ECF7B2CD2C39169C004D2C57 /* Image++.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Image++.swift"; sourceTree = "<group>"; };
|
||||||
ECF7B2CE2C39169C004D2C57 /* View++.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View++.swift"; sourceTree = "<group>"; };
|
ECF7B2CE2C39169C004D2C57 /* View++.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View++.swift"; sourceTree = "<group>"; };
|
||||||
ECF7B2E32C39174D004D2C57 /* Platform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = "<group>"; };
|
ECF7B2E32C39174D004D2C57 /* Platform.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = "<group>"; };
|
||||||
|
ECF7B2E62C39544E004D2C57 /* CenterClipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterClipView.swift; sourceTree = "<group>"; };
|
||||||
|
ECF7B2E82C395A8E004D2C57 /* Memola.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Memola.entitlements; sourceTree = "<group>"; };
|
||||||
ECFA151F2BEF21EF00455818 /* MemoObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoObject.swift; sourceTree = "<group>"; };
|
ECFA151F2BEF21EF00455818 /* MemoObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemoObject.swift; sourceTree = "<group>"; };
|
||||||
ECFA15212BEF21F500455818 /* CanvasObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CanvasObject.swift; sourceTree = "<group>"; };
|
ECFA15212BEF21F500455818 /* CanvasObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CanvasObject.swift; sourceTree = "<group>"; };
|
||||||
ECFA15232BEF223300455818 /* GraphicContextObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicContextObject.swift; sourceTree = "<group>"; };
|
ECFA15232BEF223300455818 /* GraphicContextObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphicContextObject.swift; sourceTree = "<group>"; };
|
||||||
@@ -320,6 +323,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
ECA738AC2BE60CC600A4542E /* DrawingView.swift */,
|
ECA738AC2BE60CC600A4542E /* DrawingView.swift */,
|
||||||
|
ECF7B2E62C39544E004D2C57 /* CenterClipView.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -455,6 +459,7 @@
|
|||||||
EC7F6BEA2BE5E6E300A34A7B /* Memola */ = {
|
EC7F6BEA2BE5E6E300A34A7B /* Memola */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
ECF7B2E82C395A8E004D2C57 /* Memola.entitlements */,
|
||||||
ECA738762BE5EE4E00A4542E /* App */,
|
ECA738762BE5EE4E00A4542E /* App */,
|
||||||
ECA7387E2BE5FE4200A4542E /* Canvas */,
|
ECA7387E2BE5FE4200A4542E /* Canvas */,
|
||||||
EC50500A2BF6672000B4D86E /* Components */,
|
EC50500A2BF6672000B4D86E /* Components */,
|
||||||
@@ -1053,6 +1058,7 @@
|
|||||||
ECA738E22BE610D000A4542E /* GraphicRenderPass.swift in Sources */,
|
ECA738E22BE610D000A4542E /* GraphicRenderPass.swift in Sources */,
|
||||||
ECE883BF2C00AB440045C53D /* Stroke.swift in Sources */,
|
ECE883BF2C00AB440045C53D /* Stroke.swift in Sources */,
|
||||||
ECA738DC2BE6108D00A4542E /* StrokeRenderPass.swift in Sources */,
|
ECA738DC2BE6108D00A4542E /* StrokeRenderPass.swift in Sources */,
|
||||||
|
ECF7B2E72C39544E004D2C57 /* CenterClipView.swift in Sources */,
|
||||||
ECF7B2D22C39169C004D2C57 /* CGFloat++.swift in Sources */,
|
ECF7B2D22C39169C004D2C57 /* CGFloat++.swift in Sources */,
|
||||||
EC4538892BEBCAE000A86FEC /* Quad.swift in Sources */,
|
EC4538892BEBCAE000A86FEC /* Quad.swift in Sources */,
|
||||||
ECE883BD2C00AA170045C53D /* EraserStroke.swift in Sources */,
|
ECE883BD2C00AA170045C53D /* EraserStroke.swift in Sources */,
|
||||||
@@ -1235,6 +1241,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Memola/Memola.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Memola/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Memola/Preview Content\"";
|
||||||
@@ -1271,6 +1278,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Memola/Memola.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"Memola/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"Memola/Preview Content\"";
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import Foundation
|
|||||||
|
|
||||||
struct PointGridVertex {
|
struct PointGridVertex {
|
||||||
var position: vector_float4
|
var position: vector_float4
|
||||||
|
#if os(macOS)
|
||||||
|
var pointSize: Float = 256
|
||||||
|
#else
|
||||||
var pointSize: Float = 10
|
var pointSize: Float = 10
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PointGridVertex {
|
extension PointGridVertex {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ extension Canvas {
|
|||||||
state = .closing
|
state = .closing
|
||||||
let previewImage = renderer?.drawPreview(on: self)
|
let previewImage = renderer?.drawPreview(on: self)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement for macos")
|
memoObject.preview = previewImage?.tiffRepresentation
|
||||||
#else
|
#else
|
||||||
memoObject.preview = previewImage?.jpegData(compressionQuality: 0.8)
|
memoObject.preview = previewImage?.jpegData(compressionQuality: 0.8)
|
||||||
#endif
|
#endif
|
||||||
@@ -109,7 +109,12 @@ extension Canvas {
|
|||||||
func updateTransform(on drawingView: DrawingView) {
|
func updateTransform(on drawingView: DrawingView) {
|
||||||
let bounds = CGRect(origin: .zero, size: size)
|
let bounds = CGRect(origin: .zero, size: size)
|
||||||
let renderView = drawingView.renderView
|
let renderView = drawingView.renderView
|
||||||
|
#if os(macOS)
|
||||||
|
let drawingViewBounds = CGRect(origin: .zero, size: drawingView.bounds.size.multiply(by: zoomScale))
|
||||||
|
let targetRect = drawingView.convert(drawingViewBounds, to: renderView)
|
||||||
|
#else
|
||||||
let targetRect = drawingView.convert(drawingView.bounds, to: renderView)
|
let targetRect = drawingView.convert(drawingView.bounds, to: renderView)
|
||||||
|
#endif
|
||||||
let transform1 = bounds.transform(to: targetRect)
|
let transform1 = bounds.transform(to: targetRect)
|
||||||
let transform2 = renderView.bounds.transform(to: CGRect(x: -1.0, y: -1.0, width: 2.0, height: 2.0))
|
let transform2 = renderView.bounds.transform(to: CGRect(x: -1.0, y: -1.0, width: 2.0, height: 2.0))
|
||||||
let transform3 = CGAffineTransform.identity.translatedBy(x: 0, y: 1).scaledBy(x: 1, y: -1).translatedBy(x: 0, y: 1)
|
let transform3 = CGAffineTransform.identity.translatedBy(x: 0, y: 1).scaledBy(x: 1, y: -1).translatedBy(x: 0, y: 1)
|
||||||
|
|||||||
@@ -125,8 +125,7 @@ final class Renderer {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement here")
|
return NSImage(cgImage: cgImage, size: .init(width: CGFloat(cgImage.width), height: CGFloat(cgImage.height))).flipped(flipVertically: true)
|
||||||
return nil
|
|
||||||
#else
|
#else
|
||||||
return UIImage(cgImage: cgImage, scale: 1.0, orientation: .downMirrored)
|
return UIImage(cgImage: cgImage, scale: 1.0, orientation: .downMirrored)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -148,7 +148,12 @@ public class Tool: NSObject, ObservableObject {
|
|||||||
let rect = CGRect(origin: .zero, size: targetSize)
|
let rect = CGRect(origin: .zero, size: targetSize)
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
return (image, dimension)
|
let newImage = NSImage(size: rect.size, flipped: false) { destRect in
|
||||||
|
NSGraphicsContext.current?.imageInterpolation = .high
|
||||||
|
image.draw(in: destRect, from: NSZeroRect, operation: .copy, fraction: 1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return (newImage, dimension)
|
||||||
#else
|
#else
|
||||||
UIGraphicsBeginImageContextWithOptions(targetSize, true, 1.0)
|
UIGraphicsBeginImageContextWithOptions(targetSize, true, 1.0)
|
||||||
image.draw(in: rect)
|
image.draw(in: rect)
|
||||||
@@ -163,8 +168,7 @@ public class Tool: NSObject, ObservableObject {
|
|||||||
|
|
||||||
private func bookmarkPhoto(of image: Platform.Image, and previewImage: Platform.Image, in dimension: CGSize, with canvasID: NSManagedObjectID) -> PhotoItem? {
|
private func bookmarkPhoto(of image: Platform.Image, and previewImage: Platform.Image, in dimension: CGSize, with canvasID: NSManagedObjectID) -> PhotoItem? {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement for macos")
|
guard let data = image.tiffRepresentation else { return nil }
|
||||||
let data = Data()
|
|
||||||
#else
|
#else
|
||||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -48,10 +48,14 @@ class CanvasViewController: Platform.ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
override func viewWillAppear() {
|
override func viewWillLayout() {
|
||||||
super.viewWillAppear()
|
super.viewWillLayout()
|
||||||
resizeDocumentView()
|
resizeDocumentView()
|
||||||
updateDocumentBounds()
|
updateDocumentBounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear() {
|
||||||
|
super.viewWillAppear()
|
||||||
loadMemo()
|
loadMemo()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,9 +99,11 @@ class CanvasViewController: Platform.ViewController {
|
|||||||
extension CanvasViewController {
|
extension CanvasViewController {
|
||||||
func configureViews() {
|
func configureViews() {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement for macos")
|
view.wantsLayer = true
|
||||||
|
view.layer?.backgroundColor = NSColor.white.cgColor
|
||||||
#else
|
#else
|
||||||
view.backgroundColor = .white
|
view.backgroundColor = .white
|
||||||
|
#endif
|
||||||
|
|
||||||
renderView.autoResizeDrawable = false
|
renderView.autoResizeDrawable = false
|
||||||
renderView.enableSetNeedsDisplay = true
|
renderView.enableSetNeedsDisplay = true
|
||||||
@@ -111,6 +117,15 @@ extension CanvasViewController {
|
|||||||
renderView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
renderView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
scrollView.maxMagnification = canvas.maximumZoomScale
|
||||||
|
scrollView.minMagnification = canvas.minimumZoomScale
|
||||||
|
scrollView.hasVerticalScroller = true
|
||||||
|
scrollView.hasHorizontalScroller = true
|
||||||
|
scrollView.allowsMagnification = true
|
||||||
|
scrollView.drawsBackground = false
|
||||||
|
scrollView.scrollerKnobStyle = .dark
|
||||||
|
#else
|
||||||
scrollView.maximumZoomScale = canvas.maximumZoomScale
|
scrollView.maximumZoomScale = canvas.maximumZoomScale
|
||||||
scrollView.minimumZoomScale = canvas.minimumZoomScale
|
scrollView.minimumZoomScale = canvas.minimumZoomScale
|
||||||
scrollView.contentInsetAdjustmentBehavior = .never
|
scrollView.contentInsetAdjustmentBehavior = .never
|
||||||
@@ -119,6 +134,7 @@ extension CanvasViewController {
|
|||||||
scrollView.showsHorizontalScrollIndicator = true
|
scrollView.showsHorizontalScrollIndicator = true
|
||||||
scrollView.delegate = self
|
scrollView.delegate = self
|
||||||
scrollView.backgroundColor = .clear
|
scrollView.backgroundColor = .clear
|
||||||
|
#endif
|
||||||
|
|
||||||
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
scrollView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
view.addSubview(scrollView)
|
view.addSubview(scrollView)
|
||||||
@@ -129,6 +145,11 @@ extension CanvasViewController {
|
|||||||
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
scrollView.contentView = CenterClipView()
|
||||||
|
scrollView.contentView.drawsBackground = false
|
||||||
|
scrollView.documentView = drawingView
|
||||||
|
#else
|
||||||
scrollView.addSubview(drawingView)
|
scrollView.addSubview(drawingView)
|
||||||
drawingView.backgroundColor = .clear
|
drawingView.backgroundColor = .clear
|
||||||
drawingView.isUserInteractionEnabled = false
|
drawingView.isUserInteractionEnabled = false
|
||||||
@@ -137,10 +158,10 @@ extension CanvasViewController {
|
|||||||
|
|
||||||
func resizeDocumentView(to newSize: CGSize? = nil) {
|
func resizeDocumentView(to newSize: CGSize? = nil) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement for macos")
|
scrollView.layoutSubtreeIfNeeded()
|
||||||
#else
|
#else
|
||||||
scrollView.layoutIfNeeded()
|
scrollView.layoutIfNeeded()
|
||||||
|
#endif
|
||||||
let size = canvas.size
|
let size = canvas.size
|
||||||
let widthScale = (newSize?.width ?? view.frame.width) / size.width
|
let widthScale = (newSize?.width ?? view.frame.width) / size.width
|
||||||
let heightScale = (newSize?.height ?? view.frame.height) / size.height
|
let heightScale = (newSize?.height ?? view.frame.height) / size.height
|
||||||
@@ -151,36 +172,42 @@ extension CanvasViewController {
|
|||||||
let newFrame = CGRect(x: 0, y: 0, width: width, height: height)
|
let newFrame = CGRect(x: 0, y: 0, width: width, height: height)
|
||||||
drawingView.frame = newFrame
|
drawingView.frame = newFrame
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
let rect = scrollView.documentVisibleRect
|
||||||
|
let center = NSPoint(x: rect.midX, y: rect.midY)
|
||||||
|
scrollView.setMagnification(canvas.defaultZoomScale, centeredAt: center)
|
||||||
|
#else
|
||||||
scrollView.setZoomScale(canvas.defaultZoomScale, animated: true)
|
scrollView.setZoomScale(canvas.defaultZoomScale, animated: true)
|
||||||
centerDocumentView(to: newSize)
|
centerDocumentView(to: newSize)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
let offsetX = (newFrame.width * canvas.defaultZoomScale - view.frame.width) / 2
|
let offsetX = (newFrame.width * canvas.defaultZoomScale - view.frame.width) / 2
|
||||||
let offsetY = (newFrame.height * canvas.defaultZoomScale - view.frame.height) / 2
|
let offsetY = (newFrame.height * canvas.defaultZoomScale - view.frame.height) / 2
|
||||||
|
|
||||||
let point = CGPoint(x: offsetX, y: offsetY)
|
let point = CGPoint(x: offsetX, y: offsetY)
|
||||||
scrollView.setContentOffset(point, animated: true)
|
scrollView.setContentOffset(point, animated: true)
|
||||||
|
|
||||||
drawingView.updateDrawableSize(with: view.frame.size)
|
|
||||||
#endif
|
#endif
|
||||||
|
drawingView.updateDrawableSize(with: view.frame.size)
|
||||||
|
NSLog("[Memola] - drawingView: \(drawingView.frame.size.multiply(by: scrollView.magnification)), scrollView: \(scrollView.frame), renderView: \(renderView.frame)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
func centerDocumentView(to newSize: CGSize? = nil) {
|
func centerDocumentView(to newSize: CGSize? = nil) {
|
||||||
#if os(macOS)
|
|
||||||
#warning("TODO: implement for macos")
|
|
||||||
#else
|
|
||||||
let documentViewSize = drawingView.frame.size
|
let documentViewSize = drawingView.frame.size
|
||||||
let scrollViewSize = newSize ?? view.frame.size
|
let scrollViewSize = newSize ?? view.frame.size
|
||||||
let verticalPadding = documentViewSize.height < scrollViewSize.height ? (scrollViewSize.height - documentViewSize.height) / 2 : 0
|
let verticalPadding = documentViewSize.height < scrollViewSize.height ? (scrollViewSize.height - documentViewSize.height) / 2 : 0
|
||||||
let horizontalPadding = documentViewSize.width < scrollViewSize.width ? (scrollViewSize.width - documentViewSize.width) / 2 : 0
|
let horizontalPadding = documentViewSize.width < scrollViewSize.width ? (scrollViewSize.width - documentViewSize.width) / 2 : 0
|
||||||
self.scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
|
self.scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
func updateDocumentBounds() {
|
func updateDocumentBounds() {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement for macos")
|
var bounds = scrollView.bounds.muliply(by: drawingView.ratio / scrollView.magnification)
|
||||||
#else
|
#else
|
||||||
var bounds = scrollView.bounds.muliply(by: drawingView.ratio / scrollView.zoomScale)
|
var bounds = scrollView.bounds.muliply(by: drawingView.ratio / scrollView.zoomScale)
|
||||||
|
#endif
|
||||||
let xDelta = bounds.minX * 0.0
|
let xDelta = bounds.minX * 0.0
|
||||||
let yDelta = bounds.minY * 0.0
|
let yDelta = bounds.minY * 0.0
|
||||||
bounds.origin.x -= xDelta
|
bounds.origin.x -= xDelta
|
||||||
@@ -191,12 +218,33 @@ extension CanvasViewController {
|
|||||||
if canvas.state == .loaded {
|
if canvas.state == .loaded {
|
||||||
canvas.loadStrokes(bounds)
|
canvas.loadStrokes(bounds)
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CanvasViewController {
|
extension CanvasViewController {
|
||||||
func configureListeners() {
|
func configureListeners() {
|
||||||
|
#if os(macOS)
|
||||||
|
NotificationCenter.default.publisher(for: NSScrollView.didEndLiveMagnifyNotification, object: scrollView)
|
||||||
|
.sink { [weak self] _ in
|
||||||
|
self?.magnificationEnded()
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
NotificationCenter.default.publisher(for: NSScrollView.willStartLiveMagnifyNotification, object: scrollView)
|
||||||
|
.sink { [weak self] _ in
|
||||||
|
self?.magnificationStarted()
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
NotificationCenter.default.publisher(for: NSScrollView.willStartLiveScrollNotification, object: scrollView)
|
||||||
|
.sink { [weak self] _ in
|
||||||
|
self?.draggingStarted()
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
NotificationCenter.default.publisher(for: NSScrollView.didEndLiveScrollNotification, object: scrollView)
|
||||||
|
.sink { [weak self] _ in
|
||||||
|
self?.draggingEnded()
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
|
#endif
|
||||||
canvas.$state
|
canvas.$state
|
||||||
.sink { [weak self] state in
|
.sink { [weak self] state in
|
||||||
self?.canvasStateChanged(state)
|
self?.canvasStateChanged(state)
|
||||||
@@ -344,6 +392,9 @@ extension CanvasViewController: UIScrollViewDelegate {
|
|||||||
|
|
||||||
extension CanvasViewController {
|
extension CanvasViewController {
|
||||||
func magnificationStarted() {
|
func magnificationStarted() {
|
||||||
|
#if os(macOS)
|
||||||
|
canvas.setZoomScale(scrollView.magnification)
|
||||||
|
#endif
|
||||||
guard !renderer.updatesViewPort else { return }
|
guard !renderer.updatesViewPort else { return }
|
||||||
drawingView.touchCancelled()
|
drawingView.touchCancelled()
|
||||||
canvas.updateClipBounds(scrollView, on: drawingView)
|
canvas.updateClipBounds(scrollView, on: drawingView)
|
||||||
@@ -352,6 +403,9 @@ extension CanvasViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func magnificationEnded() {
|
func magnificationEnded() {
|
||||||
|
#if os(macOS)
|
||||||
|
canvas.setZoomScale(scrollView.magnification)
|
||||||
|
#endif
|
||||||
renderer.setUpdatesViewPort(false)
|
renderer.setUpdatesViewPort(false)
|
||||||
renderer.setRedrawsGraphicRender()
|
renderer.setRedrawsGraphicRender()
|
||||||
renderView.draw()
|
renderView.draw()
|
||||||
@@ -359,6 +413,9 @@ extension CanvasViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func draggingStarted() {
|
func draggingStarted() {
|
||||||
|
#if os(macOS)
|
||||||
|
canvas.setZoomScale(scrollView.magnification)
|
||||||
|
#endif
|
||||||
guard !renderer.updatesViewPort else { return }
|
guard !renderer.updatesViewPort else { return }
|
||||||
canvas.updateClipBounds(scrollView, on: drawingView)
|
canvas.updateClipBounds(scrollView, on: drawingView)
|
||||||
drawingView.disableUserInteraction()
|
drawingView.disableUserInteraction()
|
||||||
@@ -366,6 +423,9 @@ extension CanvasViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func draggingEnded() {
|
func draggingEnded() {
|
||||||
|
#if os(macOS)
|
||||||
|
canvas.setZoomScale(scrollView.magnification)
|
||||||
|
#endif
|
||||||
renderer.setUpdatesViewPort(false)
|
renderer.setUpdatesViewPort(false)
|
||||||
renderer.setRedrawsGraphicRender()
|
renderer.setRedrawsGraphicRender()
|
||||||
renderView.draw()
|
renderView.draw()
|
||||||
@@ -413,7 +473,8 @@ extension CanvasViewController {
|
|||||||
extension CanvasViewController {
|
extension CanvasViewController {
|
||||||
func zoomChanged(_ zoomScale: CGFloat) {
|
func zoomChanged(_ zoomScale: CGFloat) {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
#warning("TODO: implement for macos")
|
let rect = scrollView.documentVisibleRect
|
||||||
|
scrollView.setMagnification(zoomScale, centeredAt: CGPoint(x: rect.midX, y: rect.midY))
|
||||||
#else
|
#else
|
||||||
scrollView.setZoomScale(zoomScale, animated: true)
|
scrollView.setZoomScale(zoomScale, animated: true)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// CenterClipView.swift
|
||||||
|
// Memola
|
||||||
|
//
|
||||||
|
// Created by Dscyre Scotti on 7/6/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if canImport(AppKit)
|
||||||
|
import AppKit
|
||||||
|
|
||||||
|
class CenterClipView: NSClipView {
|
||||||
|
override func constrainBoundsRect(_ proposedBounds: NSRect) -> NSRect {
|
||||||
|
var rect = super.constrainBoundsRect(proposedBounds)
|
||||||
|
if let containerView = self.documentView {
|
||||||
|
if (rect.size.width > containerView.frame.size.width) {
|
||||||
|
rect.origin.x = (containerView.frame.width - rect.width) / 2
|
||||||
|
}
|
||||||
|
if(rect.size.height > containerView.frame.size.height) {
|
||||||
|
rect.origin.y = (containerView.frame.height - rect.height) / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict/>
|
||||||
|
</plist>
|
||||||
@@ -18,6 +18,59 @@ extension Image {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
extension NSImage {
|
||||||
|
func upsideDownMirrored() -> NSImage {
|
||||||
|
let degrees: CGFloat = 180
|
||||||
|
let sinDegrees = abs(sin(degrees * CGFloat.pi / 180.0))
|
||||||
|
let cosDegrees = abs(cos(degrees * CGFloat.pi / 180.0))
|
||||||
|
let newSize = CGSize(
|
||||||
|
width: size.height * sinDegrees + size.width * cosDegrees,
|
||||||
|
height: size.width * sinDegrees + size.height * cosDegrees
|
||||||
|
)
|
||||||
|
|
||||||
|
let imageBounds = NSRect(
|
||||||
|
x: (newSize.width - size.width) / 2,
|
||||||
|
y: (newSize.height - size.height) / 2,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height
|
||||||
|
)
|
||||||
|
|
||||||
|
let otherTransform = NSAffineTransform()
|
||||||
|
otherTransform.translateX(by: newSize.width / 2, yBy: newSize.height / 2)
|
||||||
|
otherTransform.rotate(byDegrees: degrees)
|
||||||
|
otherTransform.translateX(by: -newSize.width / 2, yBy: -newSize.height / 2)
|
||||||
|
|
||||||
|
let rotatedImage = NSImage(size: newSize)
|
||||||
|
rotatedImage.lockFocus()
|
||||||
|
otherTransform.concat()
|
||||||
|
draw(in: imageBounds, from: CGRect.zero, operation: NSCompositingOperation.copy, fraction: 1.0)
|
||||||
|
rotatedImage.unlockFocus()
|
||||||
|
|
||||||
|
return rotatedImage
|
||||||
|
}
|
||||||
|
|
||||||
|
func flipped(flipHorizontally: Bool = false, flipVertically: Bool = false) -> NSImage {
|
||||||
|
let flippedImage = NSImage(size: size)
|
||||||
|
|
||||||
|
flippedImage.lockFocus()
|
||||||
|
|
||||||
|
NSGraphicsContext.current?.imageInterpolation = .high
|
||||||
|
|
||||||
|
let transform = NSAffineTransform()
|
||||||
|
transform.translateX(by: flipHorizontally ? size.width : 0, yBy: flipVertically ? size.height : 0)
|
||||||
|
transform.scaleX(by: flipHorizontally ? -1 : 1, yBy: flipVertically ? -1 : 1)
|
||||||
|
transform.concat()
|
||||||
|
|
||||||
|
draw(at: .zero, from: NSRect(origin: .zero, size: size), operation: .sourceOver, fraction: 1)
|
||||||
|
|
||||||
|
flippedImage.unlockFocus()
|
||||||
|
|
||||||
|
return flippedImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
extension UIImage {
|
extension UIImage {
|
||||||
func imageWithUpOrientation() -> UIImage? {
|
func imageWithUpOrientation() -> UIImage? {
|
||||||
|
|||||||
Reference in New Issue
Block a user