aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Shared/FileImageView.swift
blob: 0cc50f1e5c6f043221812bf962bc8cc829424aaf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import SwiftUI

struct FileImageView: NSViewRepresentable {
  var image: NSImage?
  
  let minimumSize: CGSize = CGSize(width: 350, height: 350)
  let presentationPaddingRatio: Double = 0.5
  
  func makeNSView(context: Context) -> NSImageView {
    let imageView = NSImageView()
    imageView.imageScaling = .scaleProportionallyUpOrDown
    imageView.animates = true
    imageView.isEditable = false
    imageView.allowsCutCopyPaste = true
    imageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
    imageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
    
    if let img = self.image {
      imageView.image = img
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        self.resizeWindowForImageView(imageView)
      }
    }
    
    return imageView
  }
  
  func updateNSView(_ nsView: NSImageView, context: Context) {
    nsView.image = self.image
  }
  
  // MARK: -
  
  func resizeWindowForImageView(_ imageView: NSImageView) {
    guard let window = imageView.window, let img = imageView.image else {
      return
    }
    
    var windowRect = window.contentLayoutRect
    let windowChromeSize = CGSize(width: window.frame.width - windowRect.width, height: window.frame.height - windowRect.height)
    
    var windowMinSize: CGSize = windowRect.size
    let centerPoint = CGPoint(x: window.frame.midX, y: window.frame.midY)
    
    windowRect.size = img.size
    
    if let screen = window.screen {
      var paddedScreenSize = screen.frame.size
      paddedScreenSize.width *= self.presentationPaddingRatio
      paddedScreenSize.height *= self.presentationPaddingRatio
      
      windowMinSize = aspectFit(source: windowRect.size, bounds: self.minimumSize)
      windowRect.size = aspectFit(source: windowRect.size, bounds: paddedScreenSize, minimum: windowMinSize)
    }
    
    windowRect.size.width += windowChromeSize.width
    windowRect.size.height += windowChromeSize.height
    
    windowRect.origin.x = centerPoint.x - windowRect.width / 2.0
    windowRect.origin.y = centerPoint.y - windowRect.height / 2.0
    
    window.setFrame(windowRect, display: true, animate: true)
    
//    Do these APIs even work??
//    window.aspectRatio = windowRect.size
//    window.contentAspectRatio = windowRect.size
  }
  
  func aspectFit(source sourceSize: CGSize, bounds boundingSize: CGSize, minimum minSize: CGSize? = nil) -> CGSize {
    let sourceAspectRatio = sourceSize.width / sourceSize.height
    
    var fitSize: CGSize = sourceSize
    
    if fitSize.width > boundingSize.width {
      fitSize.width = boundingSize.width
      fitSize.height = fitSize.width / sourceAspectRatio
    }
    
    if fitSize.height > boundingSize.height {
      fitSize.height = boundingSize.height
      fitSize.width = fitSize.height * sourceAspectRatio
    }
    
    if let m = minSize {
      if fitSize.width < m.width {
        fitSize.width = m.width
        fitSize.height = fitSize.width / sourceAspectRatio
      }
      
      if fitSize.height < m.height {
        fitSize.height = m.height
        fitSize.width = fitSize.height * sourceAspectRatio
      }
    }
    
    return fitSize
  }
}