OSDN Git Service

Doutakuを導入
[kcd/KCD.git] / KCD / ScreenshotEditorViewController.swift
1 //
2 //  ScreenshotEditorViewController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/29.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10
11 private struct URLImage {
12     
13     var image: NSImage
14     var url: URL
15     
16     init(image: NSImage, url: URL) {
17         
18         self.image = image
19         self.url = url
20     }
21 }
22
23 /// 切り取りサイズ、位置と名前
24 final class TrimRectInformation: NSObject {
25     
26     @objc private(set) var name: String
27     private(set) var rect: NSRect
28     
29     fileprivate init(name: String, rect: NSRect) {
30         
31         self.name = name
32         self.rect = rect
33     }
34 }
35
36 final class ScreenshotEditorViewController: BridgeViewController {
37     
38     @objc let trimInfo = [
39         TrimRectInformation(name: "Status", rect: NSRect(x: 328, y: 13, width: 470, height: 365)),
40         TrimRectInformation(name: "List", rect: NSRect(x: 362, y: 15, width: 438, height: 368)),
41         TrimRectInformation(name: "AirplaneBase", rect: NSRect(x: 575, y: 13, width: 225, height: 358))
42     ]
43     
44     override init(nibName: NSNib.Name?, bundle: Bundle?) {
45         
46         currentTrimInfo = trimInfo[0]
47         
48         super.init(nibName: ScreenshotEditorViewController.nibName, bundle: nil)
49     }
50     
51     required init?(coder: NSCoder) {
52         
53         fatalError("init(coder:) has not been implemented")
54     }
55     
56     
57     @IBOutlet private weak var tiledImageView: TiledImageView!
58     @IBOutlet private weak var doneButton: NSButton!
59     
60     @objc var columnCount: Int {
61         
62         get { return tiledImageView.columnCount }
63         set {
64             tiledImageView.columnCount = newValue
65             UserDefaults.standard[.screenshotEditorColumnCount] = newValue
66         }
67     }
68     
69     var image: NSImage? {
70         
71         return tiledImageView.image
72     }
73     
74     @objc dynamic var currentTrimInfoIndex: Int {
75         
76         get { return realiesCurrentTrimInforIndex }
77         set {
78             guard case 0..<trimInfo.count = newValue else { return }
79             
80             realiesCurrentTrimInforIndex = newValue
81             currentTrimInfo = trimInfo[newValue]
82         }
83     }
84     
85     private var editedImage: NSImage?
86     private var currentSelection: [ScreenshotInformation] = []
87     private var originalImages: [URLImage] = []
88     private var realiesCurrentTrimInforIndex = UserDefaults.standard[.scrennshotEditorType]
89     private var currentTrimInfo: TrimRectInformation {
90         
91         didSet {
92             makeTrimedImage()
93             trimInfo
94                 .index {
95                     
96                     if $0.name != currentTrimInfo.name { return false }
97                     return $0.rect == currentTrimInfo.rect
98                 }
99                 .map { UserDefaults.standard[.scrennshotEditorType] = $0 }
100         }
101     }
102     
103     private var selectionObservation: NSKeyValueObservation?
104     
105     var completeHandler: ((NSImage?) -> Void)?
106     
107     override func viewDidLoad() {
108         
109         super.viewDidLoad()
110         
111         selectionObservation = arrayController.observe(\NSArrayController.selectionIndexes) { [weak self] (_, _) in
112             
113             self?.updateSelections()
114         }
115         
116         currentTrimInfoIndex = UserDefaults.standard[.scrennshotEditorType]
117         updateSelections()
118     }
119     
120     override func viewWillAppear() {
121         
122         doneButton.action = #selector(ScreenshotEditorViewController.done(_:))
123     }
124     
125     private func updateSelections() {
126         
127         guard let selection = arrayController.selectedObjects as? [ScreenshotInformation] else { return }
128         
129         if selection == currentSelection { return }
130         
131         let removed: [ScreenshotInformation] = currentSelection.compactMap {
132             
133             selection.contains($0) ? nil : $0
134         }
135         
136         let appended: [ScreenshotInformation] = selection.compactMap {
137             
138             currentSelection.contains($0) ? nil : $0
139         }
140         
141         removed.forEach {
142             
143             removeOriginalImage(url: $0.url)
144         }
145         
146         appended.forEach {
147             
148             appendOriginalImage(url: $0.url)
149         }
150         
151         currentSelection = selection
152         makeTrimedImage()
153     }
154     
155     private func removeOriginalImage(url: URL) {
156         
157         _ = originalImages
158             .index { $0.url == url }
159             .map { originalImages.remove(at: $0) }
160     }
161     
162     private func appendOriginalImage(url: URL) {
163         
164         NSImage(contentsOf: url)
165             .flatMap { URLImage(image: $0, url: url) }
166             .map { originalImages.append($0) }
167     }
168     
169     private func makeTrimedImage() {
170         
171         guard !originalImages.isEmpty else {
172             
173             tiledImageView.images = []
174             return
175         }
176         
177         DispatchQueue(label: "makeTrimedImage queue").async {
178             
179             let images: [NSImage] = self.originalImages.compactMap {
180                 
181                 let trimedImage = NSImage(size: self.currentTrimInfo.rect.size)
182                 
183                 trimedImage.lockFocus()
184                 $0.image.draw(at: .zero,
185                                    from: self.currentTrimInfo.rect,
186                                    operation: .copy,
187                                    fraction: 1.0)
188                 trimedImage.unlockFocus()
189                 
190                 return trimedImage
191             }
192             
193             DispatchQueue.main.async {
194                 
195                 self.tiledImageView.images = images
196             }
197         }
198     }
199     
200     @IBAction func done(_ sender: AnyObject?) {
201         
202         completeHandler?(self.image)
203     }
204 }
205
206 extension ScreenshotEditorViewController: NibLoadable {}