OSDN Git Service

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