2 // ScreenshotEditorViewController.swift
5 // Created by Hori,Masaki on 2016/12/29.
6 // Copyright © 2016年 Hori,Masaki. All rights reserved.
11 fileprivate struct EditedImage {
13 var editedImage: NSImage
16 init(image: NSImage, url: URL) {
23 final class TrimRectInformation: NSObject {
25 fileprivate(set) var name: String
26 fileprivate(set) var rect: NSRect
28 fileprivate init(name: String, rect: NSRect) {
35 fileprivate extension Selector {
37 static let done = #selector(ScreenshotEditorViewController.done(_:))
38 static let changeToDetail = #selector(ScreenshotListWindowController.changeToDetail(_:))
39 static let registerImage = #selector(ScreenshotListViewController.registerImage(_:))
42 final class ScreenshotEditorViewController: BridgeViewController {
44 let trimInfo: [TrimRectInformation]
46 override init?(nibName: String?, bundle: Bundle?) {
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))
53 currentTrimInfo = trimInfo[0]
55 super.init(nibName: "ScreenshotEditorViewController", bundle: nil)
58 required init?(coder: NSCoder) {
60 fatalError("init(coder:) has not been implemented")
65 arrayController.removeObserver(self, forKeyPath: NSSelectionIndexesBinding)
68 @IBOutlet weak var tiledImageView: TiledImageView!
69 @IBOutlet weak var doneButton: NSButton!
71 var columnCount: Int {
73 get { return tiledImageView.columnCount }
75 tiledImageView.columnCount = newValue
76 UserDefaults.standard[.screenshotEditorColumnCount] = newValue
82 return tiledImageView.image
85 dynamic var currentTrimInfoIndex: Int {
87 get { return realiesCurrentTrimInforIndex }
89 guard 0..<trimInfo.count ~= newValue
92 realiesCurrentTrimInforIndex = newValue
93 currentTrimInfo = trimInfo[newValue]
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 {
108 if $0.name != currentTrimInfo.name { return false }
109 return $0.rect == currentTrimInfo.rect
111 .map { UserDefaults.standard[.scrennshotEditorType] = $0 }
115 override func viewDidLoad() {
119 arrayController.addObserver(self, forKeyPath: NSSelectionIndexesBinding, context: nil)
120 currentTrimInfoIndex = UserDefaults.standard[.scrennshotEditorType]
124 override func viewWillAppear() {
126 doneButton.action = .done
129 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
131 if keyPath == NSSelectionIndexesBinding {
138 super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
141 private func updateSelections() {
143 guard let selection = arrayController.selectedObjects as? [ScreenshotInformation]
146 if selection == currentSelection { return }
148 let removed: [ScreenshotInformation] = currentSelection.flatMap {
150 selection.contains($0) ? nil : $0
153 let appended: [ScreenshotInformation] = selection.flatMap {
155 currentSelection.contains($0) ? nil : $0
160 removeEditedImage(url: $0.url)
165 appendEditedImage(url: $0.url)
168 currentSelection = selection
172 private func removeEditedImage(url: URL) {
175 .index { $0.url == url }
176 .map { editedImages.remove(at: $0) }
179 private func appendEditedImage(url: URL) {
181 NSImage(contentsOf: url)
182 .flatMap { EditedImage(image: $0, url: url) }
183 .map { editedImages.append($0) }
186 private func makeEditedImage() {
188 guard !editedImages.isEmpty else {
189 tiledImageView.images = []
193 DispatchQueue(label: "makeTrimedImage queue").async {
195 let images: [NSImage] = self.editedImages.flatMap {
197 guard let originalImage = NSImage(contentsOf: $0.url)
200 let trimedImage = NSImage(size: self.currentTrimInfo.rect.size)
202 trimedImage.lockFocus()
203 originalImage.draw(at: .zero,
204 from: self.currentTrimInfo.rect,
205 operation: NSCompositeCopy,
207 trimedImage.unlockFocus()
212 DispatchQueue.main.async {
214 self.tiledImageView.images = images
219 // TODO: 外部から End Handlerを登録できるようにして依存をなくす
220 @IBAction func done(_ sender: AnyObject?) {
222 NSApplication.shared().sendAction(.registerImage, to: nil, from: self.image)
223 NSApplication.shared().sendAction(.changeToDetail, to: nil, from: sender)