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 fileprivate 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     fileprivate(set) var name: String
26     fileprivate(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 fileprivate extension Selector {
36     
37     static let done = #selector(ScreenshotEditorViewController.done(_:))
38     static let changeToDetail = #selector(ScreenshotListWindowController.changeToDetail(_:))
39     static let registerImage = #selector(ScreenshotListViewController.registerImage(_:))
40 }
41
42 final class ScreenshotEditorViewController: BridgeViewController {
43     
44     let trimInfo: [TrimRectInformation]
45     
46     override init?(nibName: String?, bundle: Bundle?) {
47         
48         trimInfo = [
49             TrimRectInformation(name: "Status", rect: NSRect(x: 328, y: 13, width: 470, height: 365)),
50             TrimRectInformation(name: "List", rect: NSRect(x: 362, y: 15, width: 438, height: 368)),
51             TrimRectInformation(name: "AirplaneBase", rect: NSRect(x: 575, y: 13, width: 225, height: 358))
52         ]
53         currentTrimInfo = trimInfo[0]
54         
55         super.init(nibName: "ScreenshotEditorViewController", bundle: nil)
56     }
57     
58     required init?(coder: NSCoder) {
59         
60         fatalError("init(coder:) has not been implemented")
61     }
62     
63     deinit {
64         
65         arrayController.removeObserver(self, forKeyPath: NSSelectionIndexesBinding)
66     }
67     
68     @IBOutlet weak var tiledImageView: TiledImageView!
69     @IBOutlet weak var doneButton: NSButton!
70     
71     var columnCount: Int {
72         
73         get { return tiledImageView.columnCount }
74         set {
75             tiledImageView.columnCount = newValue
76             UserDefaults.standard.screenshotEditorColumnCount = newValue
77         }
78     }
79     
80     var image: NSImage? {
81         
82         return tiledImageView.image
83     }
84     
85     dynamic var currentTrimInfoIndex: Int {
86         
87         get { return realiesCurrentTrimInforIndex }
88         set {
89             guard 0..<trimInfo.count ~= newValue
90                 else { return }
91             
92             realiesCurrentTrimInforIndex = newValue
93             currentTrimInfo = trimInfo[newValue]
94         }
95     }
96     
97     private var editedImage: NSImage?
98     private var currentSelection: [ScreenshotInformation] = []
99     private var editedImages: [EditedImage] = []
100     private var realiesCurrentTrimInforIndex = UserDefaults.standard.scrennshotEditorType
101     private var currentTrimInfo: TrimRectInformation {
102         
103         didSet {
104             makeEditedImage()
105             trimInfo
106                 .index {
107                     
108                     if $0.name != currentTrimInfo.name { return false }
109                     return $0.rect == currentTrimInfo.rect
110                 }
111                 .map { UserDefaults.standard.scrennshotEditorType = $0 }
112         }
113     }
114     
115     override func viewDidLoad() {
116         
117         super.viewDidLoad()
118         
119         arrayController.addObserver(self, forKeyPath: NSSelectionIndexesBinding, context: nil)
120         currentTrimInfoIndex = UserDefaults.standard.scrennshotEditorType
121         updateSelections()
122     }
123     
124     override func viewWillAppear() {
125         
126         doneButton.action = .done
127     }
128     
129     override func observeValue(forKeyPath keyPath: String?,
130                                of object: Any?,
131                                change: [NSKeyValueChangeKey : Any]?,
132                                context: UnsafeMutableRawPointer?) {
133         
134         if keyPath == NSSelectionIndexesBinding {
135             
136             updateSelections()
137             
138             return
139         }
140         
141         super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
142     }
143     
144     private func updateSelections() {
145         
146         guard let selection = arrayController.selectedObjects as? [ScreenshotInformation]
147             else { return }
148         
149         if selection == currentSelection { return }
150         
151         let removed: [ScreenshotInformation] = currentSelection.flatMap {
152             
153             selection.contains($0) ? nil : $0
154         }
155         
156         let appended: [ScreenshotInformation] = selection.flatMap {
157             
158             currentSelection.contains($0) ? nil : $0
159         }
160         
161         removed.forEach {
162             
163             removeEditedImage(url: $0.url)
164         }
165         
166         appended.forEach {
167             
168             appendEditedImage(url: $0.url)
169         }
170         
171         currentSelection = selection
172         makeEditedImage()
173     }
174     
175     private func removeEditedImage(url: URL) {
176         
177         let _ = editedImages
178             .index { $0.url == url }
179             .map { editedImages.remove(at: $0) }
180     }
181     
182     private func appendEditedImage(url: URL) {
183         
184         NSImage(contentsOf: url)
185             .flatMap { EditedImage(image: $0, url: url) }
186             .map { editedImages.append($0) }
187     }
188     
189     private func makeEditedImage() {
190         
191         guard !editedImages.isEmpty else {
192             tiledImageView.images = []
193             return
194         }
195         
196         DispatchQueue(label: "makeTrimedImage queue")
197             .async {
198                 
199                 let images: [NSImage] = self.editedImages.flatMap {
200                     
201                     guard let originalImage = NSImage(contentsOf: $0.url) else { return nil }
202                     
203                     let trimedImage = NSImage(size: self.currentTrimInfo.rect.size)
204                     
205                     trimedImage.lockFocus()
206                     originalImage.draw(at: .zero,
207                                        from: self.currentTrimInfo.rect,
208                                        operation: NSCompositeCopy,
209                                        fraction: 1.0)
210                     trimedImage.unlockFocus()
211                     
212                     return trimedImage
213                 }
214                 
215                 DispatchQueue.main.async {
216                     
217                     self.tiledImageView.images = images
218                 }
219         }
220     }
221     
222     // TODO: 外部から End Handlerを登録できるようにして依存をなくす
223     @IBAction func done(_ sender: AnyObject?) {
224         
225         NSApplication.shared().sendAction(.registerImage, to: nil, from: self.image)
226         NSApplication.shared().sendAction(.changeToDetail, to: nil, from: sender)
227     }
228 }