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?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
130         
131         if keyPath == NSSelectionIndexesBinding {
132             
133             updateSelections()
134             
135             return
136         }
137         
138         super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
139     }
140     
141     private func updateSelections() {
142         
143         guard let selection = arrayController.selectedObjects as? [ScreenshotInformation]
144             else { return }
145         
146         if selection == currentSelection { return }
147         
148         let removed: [ScreenshotInformation] = currentSelection.flatMap {
149             
150             selection.contains($0) ? nil : $0
151         }
152         
153         let appended: [ScreenshotInformation] = selection.flatMap {
154             
155             currentSelection.contains($0) ? nil : $0
156         }
157         
158         removed.forEach {
159             
160             removeEditedImage(url: $0.url)
161         }
162         
163         appended.forEach {
164             
165             appendEditedImage(url: $0.url)
166         }
167         
168         currentSelection = selection
169         makeEditedImage()
170     }
171     
172     private func removeEditedImage(url: URL) {
173         
174         _ = editedImages
175             .index { $0.url == url }
176             .map { editedImages.remove(at: $0) }
177     }
178     
179     private func appendEditedImage(url: URL) {
180         
181         NSImage(contentsOf: url)
182             .flatMap { EditedImage(image: $0, url: url) }
183             .map { editedImages.append($0) }
184     }
185     
186     private func makeEditedImage() {
187         
188         guard !editedImages.isEmpty else {
189             tiledImageView.images = []
190             return
191         }
192         
193         DispatchQueue(label: "makeTrimedImage queue").async {
194             
195             let images: [NSImage] = self.editedImages.flatMap {
196                 
197                 guard let originalImage = NSImage(contentsOf: $0.url)
198                     else { return nil }
199                 
200                 let trimedImage = NSImage(size: self.currentTrimInfo.rect.size)
201                 
202                 trimedImage.lockFocus()
203                 originalImage.draw(at: .zero,
204                                    from: self.currentTrimInfo.rect,
205                                    operation: NSCompositeCopy,
206                                    fraction: 1.0)
207                 trimedImage.unlockFocus()
208                 
209                 return trimedImage
210             }
211             
212             DispatchQueue.main.async {
213                 
214                 self.tiledImageView.images = images
215             }
216         }
217     }
218     
219     // TODO: 外部から End Handlerを登録できるようにして依存をなくす
220     @IBAction func done(_ sender: AnyObject?) {
221         
222         NSApplication.shared().sendAction(.registerImage, to: nil, from: self.image)
223         NSApplication.shared().sendAction(.changeToDetail, to: nil, from: sender)
224     }
225 }