aboutsummaryrefslogtreecommitdiff
path: root/Hotline/Shared/FileImageView.swift
blob: 141a71ba31f0e35c0c3bd729dfbd5fd7716458ac (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
99
100
101
102
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
  }
}