feat: sync render view port with scrollview

This commit is contained in:
dscyrescotti
2024-07-07 13:37:45 +07:00
parent cbd2e4c484
commit 739aaa059b
8 changed files with 91 additions and 35 deletions

View File

@@ -37,6 +37,7 @@
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7F6BEB2BE5E6E300A34A7B /* MemolaApp.swift */; };
EC7F6BF02BE5E6E400A34A7B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7F6BEF2BE5E6E400A34A7B /* Assets.xcassets */; };
EC7F6BF32BE5E6E400A34A7B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7F6BF22BE5E6E400A34A7B /* Preview Assets.xcassets */; };
EC8C9DCE2C39882500A8F3C4 /* NSSyncScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8C9DCD2C39882500A8F3C4 /* NSSyncScrollView.swift */; };
EC8F54AC2C2ACDA8001C7C74 /* GridMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8F54AB2C2ACDA8001C7C74 /* GridMode.swift */; };
EC8F54AE2C2AF5A4001C7C74 /* LineGridVertex.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8F54AD2C2AF5A4001C7C74 /* LineGridVertex.swift */; };
EC8F54B02C2AF5E9001C7C74 /* LineGridContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC8F54AF2C2AF5E9001C7C74 /* LineGridContext.swift */; };
@@ -119,7 +120,7 @@
ECF7B2E02C39169C004D2C57 /* Image++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2CD2C39169C004D2C57 /* Image++.swift */; };
ECF7B2E12C39169C004D2C57 /* View++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2CE2C39169C004D2C57 /* View++.swift */; };
ECF7B2E42C39174D004D2C57 /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2E32C39174D004D2C57 /* Platform.swift */; };
ECF7B2E72C39544E004D2C57 /* CenterClipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2E62C39544E004D2C57 /* CenterClipView.swift */; };
ECF7B2E72C39544E004D2C57 /* NSCenterClipView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF7B2E62C39544E004D2C57 /* NSCenterClipView.swift */; };
ECFA15202BEF21EF00455818 /* MemoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA151F2BEF21EF00455818 /* MemoObject.swift */; };
ECFA15222BEF21F500455818 /* CanvasObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15212BEF21F500455818 /* CanvasObject.swift */; };
ECFA15242BEF223300455818 /* GraphicContextObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECFA15232BEF223300455818 /* GraphicContextObject.swift */; };
@@ -161,6 +162,7 @@
EC7F6BEB2BE5E6E300A34A7B /* MemolaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemolaApp.swift; sourceTree = "<group>"; };
EC7F6BEF2BE5E6E400A34A7B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
EC7F6BF22BE5E6E400A34A7B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
EC8C9DCD2C39882500A8F3C4 /* NSSyncScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSSyncScrollView.swift; sourceTree = "<group>"; };
EC8F54AB2C2ACDA8001C7C74 /* GridMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridMode.swift; sourceTree = "<group>"; };
EC8F54AD2C2AF5A4001C7C74 /* LineGridVertex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineGridVertex.swift; sourceTree = "<group>"; };
EC8F54AF2C2AF5E9001C7C74 /* LineGridContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineGridContext.swift; sourceTree = "<group>"; };
@@ -243,7 +245,7 @@
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>"; };
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>"; };
ECF7B2E62C39544E004D2C57 /* NSCenterClipView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSCenterClipView.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>"; };
ECFA15212BEF21F500455818 /* CanvasObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CanvasObject.swift; sourceTree = "<group>"; };
@@ -322,8 +324,8 @@
EC1437B42BE748E60022C903 /* Views */ = {
isa = PBXGroup;
children = (
EC8C9DCC2C3987FD00A8F3C4 /* AppKit */,
ECA738AC2BE60CC600A4542E /* DrawingView.swift */,
ECF7B2E62C39544E004D2C57 /* CenterClipView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -481,6 +483,15 @@
path = "Preview Content";
sourceTree = "<group>";
};
EC8C9DCC2C3987FD00A8F3C4 /* AppKit */ = {
isa = PBXGroup;
children = (
ECF7B2E62C39544E004D2C57 /* NSCenterClipView.swift */,
EC8C9DCD2C39882500A8F3C4 /* NSSyncScrollView.swift */,
);
path = AppKit;
sourceTree = "<group>";
};
EC8F54AA2C2ACD9D001C7C74 /* Grid */ = {
isa = PBXGroup;
children = (
@@ -1038,6 +1049,7 @@
ECA738862BE5FF2500A4542E /* Canvas.swift in Sources */,
ECF7B2DE2C39169C004D2C57 /* NSManagedObjectContext++.swift in Sources */,
ECA738882BE5FF4400A4542E /* Renderer.swift in Sources */,
EC8C9DCE2C39882500A8F3C4 /* NSSyncScrollView.swift in Sources */,
ECF7B2D72C39169C004D2C57 /* Color++.swift in Sources */,
EC01512C2C306BEF008A115E /* MemoCard.swift in Sources */,
ECA738D42BE60F9100A4542E /* StrokeGenerator.swift in Sources */,
@@ -1058,7 +1070,7 @@
ECA738E22BE610D000A4542E /* GraphicRenderPass.swift in Sources */,
ECE883BF2C00AB440045C53D /* Stroke.swift in Sources */,
ECA738DC2BE6108D00A4542E /* StrokeRenderPass.swift in Sources */,
ECF7B2E72C39544E004D2C57 /* CenterClipView.swift in Sources */,
ECF7B2E72C39544E004D2C57 /* NSCenterClipView.swift in Sources */,
ECF7B2D22C39169C004D2C57 /* CGFloat++.swift in Sources */,
EC4538892BEBCAE000A86FEC /* Quad.swift in Sources */,
ECE883BD2C00AA170045C53D /* EraserStroke.swift in Sources */,

View File

@@ -10,11 +10,7 @@ import Foundation
struct PointGridVertex {
var position: vector_float4
#if os(macOS)
var pointSize: Float = 256
#else
var pointSize: Float = 10
#endif
}
extension PointGridVertex {

View File

@@ -110,8 +110,9 @@ extension Canvas {
let bounds = CGRect(origin: .zero, size: size)
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)
let drawingViewBounds = drawingView.bounds
var targetRect = drawingView.convert(drawingViewBounds, to: renderView)
targetRect.origin.y = renderView.bounds.height - targetRect.maxY
#else
let targetRect = drawingView.convert(drawingView.bounds, to: renderView)
#endif
@@ -145,19 +146,23 @@ extension Canvas {
}
func updateClipBounds(_ scrollView: Platform.ScrollView, on drawingView: DrawingView) {
#if os(macOS)
let ratio = drawingView.ratio
var bounds = scrollView.convert(scrollView.bounds, to: drawingView)
bounds.origin.y = drawingView.bounds.height - (bounds.origin.y + bounds.height)
clipBounds = CGRect(origin: bounds.origin.muliply(by: ratio), size: bounds.size.multiply(by: ratio))
#else
let ratio = drawingView.ratio
let bounds = scrollView.convert(scrollView.bounds, to: drawingView)
clipBounds = CGRect(origin: bounds.origin.muliply(by: ratio), size: bounds.size.multiply(by: ratio))
#endif
}
}
// MARK: - Zoom Scale
extension Canvas {
func setZoomScale(_ zoomScale: CGFloat) {
DispatchQueue.main.async { [weak self] in
guard let self else { return }
self.zoomScale = min(max(zoomScale, minimumZoomScale), maximumZoomScale)
}
self.zoomScale = min(max(zoomScale, minimumZoomScale), maximumZoomScale)
}
}

View File

@@ -112,7 +112,7 @@ final class Renderer {
func drawPreview(on canvas: Canvas) -> Platform.Image? {
guard let commandBuffer = commandQueue.makeCommandBuffer() else {
NSLog("[Memola] - Unable to create command buffer")
NSLog("[Memola] - Unable to create command buffer for preview")
return nil
}
strokeRenderPass.eraserRenderPass = eraserRenderPass

View File

@@ -48,14 +48,11 @@ class CanvasViewController: Platform.ViewController {
}
#if os(macOS)
override func viewWillLayout() {
super.viewWillLayout()
resizeDocumentView()
updateDocumentBounds()
}
override func viewWillAppear() {
super.viewWillAppear()
resizeDocumentView()
updateDocumentBounds()
loadMemo()
}
@@ -132,9 +129,9 @@ extension CanvasViewController {
scrollView.isScrollEnabled = true
scrollView.showsVerticalScrollIndicator = true
scrollView.showsHorizontalScrollIndicator = true
scrollView.delegate = self
scrollView.backgroundColor = .clear
#endif
scrollView.delegate = self
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
@@ -146,7 +143,7 @@ extension CanvasViewController {
])
#if os(macOS)
scrollView.contentView = CenterClipView()
scrollView.contentView = NSCenterClipView()
scrollView.contentView.drawsBackground = false
scrollView.documentView = drawingView
#else
@@ -171,10 +168,14 @@ extension CanvasViewController {
let height = size.height * scale
let newFrame = CGRect(x: 0, y: 0, width: width, height: height)
drawingView.frame = newFrame
DispatchQueue.main.async { [unowned canvas] in
canvas.setZoomScale(canvas.defaultZoomScale)
}
#if os(macOS)
let rect = scrollView.documentVisibleRect
let center = NSPoint(x: rect.midX, y: rect.midY)
scrollView.contentView.setBoundsSize(newFrame.size)
let center = NSPoint(x: newFrame.midX, y: newFrame.midY)
scrollView.setMagnification(canvas.defaultZoomScale, centeredAt: center)
#else
scrollView.setZoomScale(canvas.defaultZoomScale, animated: true)
@@ -189,7 +190,6 @@ extension CanvasViewController {
scrollView.setContentOffset(point, animated: true)
#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)
@@ -204,7 +204,10 @@ extension CanvasViewController {
func updateDocumentBounds() {
#if os(macOS)
var bounds = scrollView.bounds.muliply(by: drawingView.ratio / scrollView.magnification)
let ratio = drawingView.ratio
var bounds = scrollView.convert(scrollView.bounds, to: drawingView)
bounds.origin.y = drawingView.bounds.height - (bounds.origin.y + bounds.height)
bounds = CGRect(origin: bounds.origin.muliply(by: ratio), size: bounds.size.multiply(by: ratio))
#else
var bounds = scrollView.bounds.muliply(by: drawingView.ratio / scrollView.zoomScale)
#endif
@@ -226,6 +229,7 @@ extension CanvasViewController {
#if os(macOS)
NotificationCenter.default.publisher(for: NSScrollView.didEndLiveMagnifyNotification, object: scrollView)
.sink { [weak self] _ in
self?.updateDocumentBounds()
self?.magnificationEnded()
}
.store(in: &cancellables)
@@ -241,6 +245,7 @@ extension CanvasViewController {
.store(in: &cancellables)
NotificationCenter.default.publisher(for: NSScrollView.didEndLiveScrollNotification, object: scrollView)
.sink { [weak self] _ in
self?.updateDocumentBounds()
self?.draggingEnded()
}
.store(in: &cancellables)
@@ -334,7 +339,12 @@ extension CanvasViewController {
withAnimation {
tool.selectedPhotoItem = nil
}
#if os(macOS)
let pointInLeftBottomOrigin = gesture.location(in: drawingView)
let point = CGPoint(x: pointInLeftBottomOrigin.x, y: drawingView.bounds.height - pointInLeftBottomOrigin.y)
#else
let point = gesture.location(in: drawingView)
#endif
let photo = canvas.insertPhoto(at: point.muliply(by: drawingView.ratio), photoItem: photoItem)
history.addUndo(.photo(photo))
drawingView.draw()
@@ -342,6 +352,16 @@ extension CanvasViewController {
}
#if os(macOS)
extension CanvasViewController: NSSyncScrollViewDelegate {
func scrollViewDidZoom(_ scrollView: NSSyncScrollView) {
canvas.setZoomScale(scrollView.magnification)
renderView.draw()
}
func scrollViewDidScroll(_ scrollView: NSSyncScrollView) {
renderView.draw()
}
}
#else
extension CanvasViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
@@ -392,9 +412,6 @@ extension CanvasViewController: UIScrollViewDelegate {
extension CanvasViewController {
func magnificationStarted() {
#if os(macOS)
canvas.setZoomScale(scrollView.magnification)
#endif
guard !renderer.updatesViewPort else { return }
drawingView.touchCancelled()
canvas.updateClipBounds(scrollView, on: drawingView)
@@ -403,9 +420,6 @@ extension CanvasViewController {
}
func magnificationEnded() {
#if os(macOS)
canvas.setZoomScale(scrollView.magnification)
#endif
renderer.setUpdatesViewPort(false)
renderer.setRedrawsGraphicRender()
renderView.draw()

View File

@@ -1,5 +1,5 @@
//
// CenterClipView.swift
// NSCenterClipView.swift
// Memola
//
// Created by Dscyre Scotti on 7/6/24.
@@ -8,7 +8,7 @@
#if canImport(AppKit)
import AppKit
class CenterClipView: NSClipView {
class NSCenterClipView: NSClipView {
override func constrainBoundsRect(_ proposedBounds: NSRect) -> NSRect {
var rect = super.constrainBoundsRect(proposedBounds)
if let containerView = self.documentView {

View File

@@ -0,0 +1,29 @@
//
// NSSyncScrollView.swift
// Memola
//
// Created by Dscyre Scotti on 7/6/24.
//
#if canImport(AppKit)
import AppKit
protocol NSSyncScrollViewDelegate: AnyObject {
func scrollViewDidZoom(_ scrollView: NSSyncScrollView)
func scrollViewDidScroll(_ scrollView: NSSyncScrollView)
}
class NSSyncScrollView: NSScrollView {
weak var delegate: NSSyncScrollViewDelegate?
override func magnify(with event: NSEvent) {
super.magnify(with: event)
delegate?.scrollViewDidZoom(self)
}
override func scrollWheel(with event: NSEvent) {
super.scrollWheel(with: event)
delegate?.scrollViewDidScroll(self)
}
}
#endif

View File

@@ -12,7 +12,7 @@ enum Platform {
typealias View = NSView
typealias Color = NSColor
typealias Image = NSImage
typealias ScrollView = NSScrollView
typealias ScrollView = NSSyncScrollView
typealias Application = NSApplication
typealias ViewController = NSViewController
typealias TapGestureRecognizer = NSClickGestureRecognizer