OSDN Git Service

Doutakuを導入
[kcd/KCD.git] / KCD / ImageView.swift
1 //
2 //  ImageView.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2017/01/02.
6 //  Copyright © 2017年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 ///  複数の画像をカスケードして表示する
12 final class ImageView: NSView {
13     
14     var images: [NSImage] = [] {
15         
16         didSet { needsDisplay = true }
17     }
18     
19     var imageRect: NSRect {
20         
21         if images.isEmpty { return .zero }
22         
23         let bounds = self.bounds
24         let offset = bounds.width * 0.1 / 2 / 3
25         let border = offset * 3
26         let rect = bounds.insetBy(dx: border, dy: border)
27         let size = images[0].size
28         let ratio = min(rect.width / size.width, rect.height / size.height)
29         let drawSize = NSSize(width: size.width * ratio, height: size.height * ratio)
30         
31         return NSRect(
32             x: rect.minX + (rect.width - drawSize.width) / 2,
33             y: rect.minY + (rect.height - drawSize.height) / 2,
34             width: drawSize.width,
35             height: drawSize.height)
36     }
37     
38     private var internalImageShadow: NSShadow?
39     
40     private var imageShadow: NSShadow {
41         
42         if let s = internalImageShadow { return s }
43         
44         let s = NSShadow()
45         s.shadowOffset = NSSize(width: 2, height: -2)
46         s.shadowBlurRadius = 4
47         s.shadowColor = NSColor.darkGray
48         internalImageShadow = s
49         
50         return s
51     }
52     
53     override func draw(_ dirtyRect: NSRect) {
54         
55         NSColor.controlBackgroundColor.set()
56         NSBezierPath.stroke(bounds)
57         
58         NSColor.black.set()
59         NSBezierPath.defaultLineWidth = 1.0
60         NSBezierPath.stroke(bounds)
61         
62         NSBezierPath.clip(bounds.insetBy(dx: 1, dy: 1))
63         
64         imageShadow.set()
65         
66         let count = images.count
67         
68         let alphaFactor = 0.7
69         var alpha = pow(alphaFactor, Double(count - 1))
70         
71         let offset = bounds.width * 0.1 / 2 / 3
72         let border = offset * 3
73         let rect = bounds.insetBy(dx: border, dy: border)
74         
75         images
76             .enumerated()
77             .reversed()
78             .forEach {
79                 let offsetRect = rect.offsetBy(dx: offset * CGFloat($0.offset), dy: offset * CGFloat($0.offset))
80                 let drawRect = imageRect(with: offsetRect, imageSize: $0.element.size)
81                 $0.element.draw(in: drawRect, from: .zero, operation: .sourceOver, fraction: CGFloat(alpha))
82                 alpha /= alphaFactor
83         }
84     }
85
86     private func imageRect(with rect: NSRect, imageSize: NSSize) -> NSRect {
87         
88         let ratio = min(rect.width / imageSize.width, rect.height / imageSize.height)
89         let drawSize = NSSize(width: imageSize.width * ratio,
90                               height: imageSize.height * ratio)
91         
92         return NSRect(
93             x: rect.minX + (rect.width - drawSize.width) / 2,
94             y: rect.minY + (rect.height - drawSize.height) / 2,
95             width: drawSize.width,
96             height: drawSize.height)
97     }
98 }