mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-03-18 23:44:01 +01:00
feat: sync render view port with scrollview
This commit is contained in:
@@ -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 */,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user