KMPenController.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. //
  2. // KMPenController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by Niehaoyu on 2024/11/26.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. class KMPenController: NSViewController {
  10. //Color
  11. @IBOutlet var colorBGView: NSView!
  12. @IBOutlet var colorLabel: NSTextField!
  13. @IBOutlet var colorGroup: ComponentCColorGroup!
  14. @IBOutlet var colorSlider: ComponentSlider!
  15. @IBOutlet var colorOpacitySelect: ComponentSelect!
  16. //Line
  17. @IBOutlet var lineBGView: NSView!
  18. @IBOutlet var lineLabel: NSTextField!
  19. @IBOutlet var lineTypeSelector: ComponentCSelectorGroup!
  20. @IBOutlet var lineWidthSlider: ComponentSlider!
  21. @IBOutlet var lineWidthSelect: ComponentSelect!
  22. @IBOutlet var linedashInfoView: NSView!
  23. @IBOutlet var lineDashSlider: ComponentSlider!
  24. @IBOutlet var lineDashSelect: ComponentSelect!
  25. private let solidProperty = ComponentCSelectorProperty.init(size: .s, state: .normal, text: "", iconImage: NSImage(named: "lineStyle_solid"))
  26. private let dashProperty = ComponentCSelectorProperty.init(size: .s, state: .normal, text: "", iconImage: NSImage(named: "lineStyle_dash"))
  27. private var annotations: [CPDFInkAnnotation] = []
  28. var pdfView: CPDFListView?
  29. //MARK: - func
  30. override func viewDidAppear() {
  31. super.viewDidAppear()
  32. colorSlider.reloadData()
  33. lineWidthSlider.reloadData()
  34. lineDashSlider.reloadData()
  35. }
  36. override func viewDidLoad() {
  37. super.viewDidLoad()
  38. // Do view setup here.
  39. setupProperty()
  40. }
  41. func setupProperty() {
  42. //Color
  43. colorLabel.stringValue = KMLocalizedString("Color")
  44. colorLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2")
  45. colorLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium")
  46. let colorAProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMPDFWatermarkData.watermarkDefaultColors()[0])
  47. let colorBProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMPDFWatermarkData.watermarkDefaultColors()[1])
  48. let colorCProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMPDFWatermarkData.watermarkDefaultColors()[2])
  49. let colorDProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMPDFWatermarkData.watermarkDefaultColors()[3])
  50. let colorEProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: true, color: KMPDFWatermarkData.watermarkDefaultColors()[4])
  51. colorGroup.setUpWithColorPropertys([colorAProperty, colorBProperty, colorCProperty, colorDProperty], customItemProperty: colorEProperty)
  52. colorGroup.delegate = self
  53. colorSlider.properties = ComponentSliderProperty(size: .m, percent: 1)
  54. colorSlider.delegate = self
  55. colorOpacitySelect.properties = ComponentSelectProperties(size: .s,
  56. state: .normal,
  57. creatable: true,
  58. text: "100%",
  59. textUnit: "%",
  60. regexString: "0123456789%")
  61. if true {
  62. var opacityItems: [ComponentMenuitemProperty] = []
  63. for string in ["25%", "50%", "75%", "100%"] {
  64. let item = ComponentMenuitemProperty(type: .normal, text: string)
  65. opacityItems.append(item)
  66. }
  67. colorOpacitySelect.updateMenuItemsArr(opacityItems)
  68. }
  69. colorOpacitySelect.delegate = self
  70. //Line
  71. lineLabel.stringValue = KMLocalizedString("Line")
  72. lineLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2")
  73. lineLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium")
  74. lineTypeSelector.updateItemProperty([solidProperty, dashProperty])
  75. lineTypeSelector.delegate = self
  76. lineWidthSlider.properties = ComponentSliderProperty(size: .m, percent: 1)
  77. lineWidthSlider.delegate = self
  78. lineWidthSelect.properties = ComponentSelectProperties(size: .s,
  79. state: .normal,
  80. creatable: true,
  81. text: "2",
  82. textUnit: " pt",
  83. regexString: "0123456789 pt")
  84. if true {
  85. var opacityItems: [ComponentMenuitemProperty] = []
  86. for string in ["1 pt", "3 pt", "6 pt", "9 pt", "12 pt", "15 pt", "18 pt"] {
  87. let item = ComponentMenuitemProperty(type: .normal, text: string)
  88. opacityItems.append(item)
  89. }
  90. lineWidthSelect.updateMenuItemsArr(opacityItems)
  91. }
  92. lineWidthSelect.delegate = self
  93. lineDashSlider.properties = ComponentSliderProperty(size: .m, percent: 1)
  94. lineDashSlider.delegate = self
  95. lineDashSelect.properties = ComponentSelectProperties(size: .s,
  96. state: .normal,
  97. creatable: true,
  98. text: "2",
  99. textUnit: " pt",
  100. regexString: "0123456789 pt")
  101. if true {
  102. var opacityItems: [ComponentMenuitemProperty] = []
  103. for string in ["1 pt", "3 pt", "6 pt", "9 pt", "12 pt", "15 pt", "18 pt"] {
  104. let item = ComponentMenuitemProperty(type: .normal, text: string)
  105. opacityItems.append(item)
  106. }
  107. lineDashSelect.updateMenuItemsArr(opacityItems)
  108. }
  109. lineDashSelect.delegate = self
  110. }
  111. func reloadData() {
  112. guard let pdfView = self.pdfView else {
  113. return
  114. }
  115. let manager = KMAnnotationPropertiesColorManager.manager
  116. self.annotations.removeAll()
  117. let allAnnotations: [CPDFAnnotation] = pdfView.activeAnnotations as? [CPDFAnnotation] ?? []
  118. for annotation in allAnnotations {
  119. if annotation is CPDFInkAnnotation {
  120. annotations.append((annotation as! CPDFInkAnnotation))
  121. }
  122. }
  123. if annotations.count == 0 {
  124. return
  125. }
  126. guard let firstAnnotation = annotations.first else {
  127. return
  128. }
  129. if annotations.count == 1 {
  130. colorGroup.currentColor = firstAnnotation.color
  131. colorGroup.refreshUI()
  132. let opacity = firstAnnotation.opacity
  133. colorSlider.properties.percent = opacity
  134. colorSlider.reloadData()
  135. colorOpacitySelect.properties.text = String(format: "%.0f%@", opacity*100, "%")
  136. colorOpacitySelect.reloadData()
  137. let border: CPDFBorder = firstAnnotation.border
  138. dashProperty.state = .normal
  139. solidProperty.state = .normal
  140. if border.style == .dashed {
  141. dashProperty.state = .pressed
  142. } else if border.style == .solid {
  143. solidProperty.state = .pressed
  144. }
  145. lineTypeSelector.reloadData()
  146. let percent = (border.lineWidth - 1)/17
  147. lineWidthSlider.properties.percent = percent
  148. lineWidthSlider.reloadData()
  149. lineWidthSelect.properties.text = String(format: "%.0f%@", border.lineWidth, " pt")
  150. lineWidthSelect.reloadData()
  151. linedashInfoView.isHidden = true
  152. if border.style == .dashed {
  153. linedashInfoView.isHidden = false
  154. var dash = 1.0
  155. for dashPattern in border.dashPattern {
  156. if let value = dashPattern as? CGFloat {
  157. dash = value
  158. break
  159. }
  160. }
  161. let percent: CGFloat = (CGFloat(dash) - 1)/17
  162. lineDashSlider.properties.percent = percent
  163. lineDashSlider.reloadData()
  164. lineDashSelect.properties.text = String(format: "%.0f%@", CGFloat(dash), " pt")
  165. lineDashSelect.reloadData()
  166. }
  167. } else {
  168. if true {
  169. var multiColor: Bool = false
  170. for annotationA in annotations {
  171. for annotationB in annotations {
  172. if annotationA != annotationB {
  173. if annotationA.color != annotationB.color {
  174. multiColor = true
  175. break
  176. }
  177. }
  178. }
  179. if multiColor == true {
  180. break
  181. }
  182. }
  183. if multiColor == true {
  184. colorGroup.currentColor = NSColor.clear
  185. } else {
  186. colorGroup.currentColor = firstAnnotation.color
  187. }
  188. colorGroup.refreshUI()
  189. }
  190. if true {
  191. var multiOpacity: Bool = false
  192. for annotationA in annotations {
  193. for annotationB in annotations {
  194. if annotationA != annotationB {
  195. if annotationA.opacity != annotationB.opacity {
  196. multiOpacity = true
  197. break
  198. }
  199. }
  200. }
  201. if multiOpacity == true {
  202. break
  203. }
  204. }
  205. if multiOpacity {
  206. colorSlider.properties.percent = 0
  207. colorSlider.reloadData()
  208. colorOpacitySelect.resetText("-")
  209. } else {
  210. let opacity = firstAnnotation.opacity
  211. colorSlider.properties.percent = opacity
  212. colorSlider.reloadData()
  213. colorOpacitySelect.properties.text = String(format: "%.0f%@", opacity*100, "%")
  214. colorOpacitySelect.reloadData()
  215. }
  216. }
  217. if true {
  218. var multiStyle: Bool = false
  219. for annotationA in annotations {
  220. for annotationB in annotations {
  221. if annotationA != annotationB {
  222. if annotationA.borderStyle() != annotationB.borderStyle() {
  223. multiStyle = true
  224. break
  225. }
  226. }
  227. }
  228. if multiStyle == true {
  229. break
  230. }
  231. }
  232. linedashInfoView.isHidden = true
  233. if multiStyle {
  234. dashProperty.state = .normal
  235. solidProperty.state = .normal
  236. lineTypeSelector.reloadData()
  237. } else {
  238. let style = firstAnnotation.border.style
  239. dashProperty.state = .normal
  240. solidProperty.state = .normal
  241. if style == .dashed {
  242. dashProperty.state = .pressed
  243. } else if style == .solid {
  244. solidProperty.state = .pressed
  245. }
  246. lineTypeSelector.reloadData()
  247. if style == .dashed {
  248. linedashInfoView.isHidden = false
  249. }
  250. }
  251. }
  252. if true {
  253. var multiLineWidth: Bool = false
  254. for annotationA in annotations {
  255. for annotationB in annotations {
  256. if annotationA != annotationB {
  257. if annotationA.borderStyle() != annotationB.borderStyle() {
  258. multiLineWidth = true
  259. break
  260. }
  261. }
  262. }
  263. if multiLineWidth == true {
  264. break
  265. }
  266. }
  267. if multiLineWidth {
  268. lineWidthSlider.properties.percent = 0
  269. lineWidthSlider.reloadData()
  270. lineWidthSelect.resetText("-")
  271. } else {
  272. let border: CPDFBorder = firstAnnotation.border
  273. let percent = (border.lineWidth - 1)/17
  274. lineWidthSlider.properties.percent = percent
  275. lineWidthSlider.reloadData()
  276. lineWidthSelect.properties.text = String(format: "%.0f%@", border.lineWidth, " pt")
  277. lineWidthSelect.reloadData()
  278. }
  279. }
  280. if true {
  281. var multiLineDash: Bool = false
  282. for annotationA in annotations {
  283. var dashA = 1.0
  284. for dashPattern in annotationA.border.dashPattern {
  285. if let value = dashPattern as? CGFloat {
  286. dashA = value
  287. break
  288. }
  289. }
  290. for annotationB in annotations {
  291. if annotationA != annotationB {
  292. var dashB = 1.0
  293. for dashPattern in annotationB.border.dashPattern {
  294. if let value = dashPattern as? CGFloat {
  295. dashB = value
  296. break
  297. }
  298. }
  299. if dashA != dashB {
  300. multiLineDash = true
  301. break
  302. }
  303. }
  304. }
  305. if multiLineDash == true {
  306. break
  307. }
  308. }
  309. if multiLineDash {
  310. lineDashSlider.properties.percent = 0
  311. lineDashSlider.reloadData()
  312. lineDashSelect.resetText("-")
  313. } else {
  314. var dashA = 1.0
  315. for dashPattern in firstAnnotation.border.dashPattern {
  316. if let value = dashPattern as? CGFloat {
  317. dashA = value
  318. break
  319. }
  320. }
  321. let percent = (dashA - 1)/17
  322. lineDashSlider.properties.percent = percent
  323. lineDashSlider.reloadData()
  324. lineDashSelect.properties.text = String(format: "%.0f%@", dashA, " pt")
  325. lineDashSelect.reloadData()
  326. }
  327. }
  328. }
  329. }
  330. //MARK: - Mouse
  331. override func mouseDown(with event: NSEvent) {
  332. super.mouseDown(with: event)
  333. view.window?.makeFirstResponder(nil)
  334. }
  335. }
  336. //MARK: - ComponentCColorDelegate
  337. extension KMPenController: ComponentCColorDelegate {
  338. func componentCColorDidChooseColor(_ view: NSView, _ color: NSColor?) {
  339. for annotation in self.annotations {
  340. annotation.updateColor(color, withPDFView: pdfView)
  341. }
  342. reloadData()
  343. }
  344. }
  345. //MARK: - ComponentSliderDelegate
  346. extension KMPenController: ComponentSliderDelegate {
  347. func componentSliderDidUpdate(_ view: ComponentSlider) {
  348. if view == colorSlider {
  349. let percent = view.properties.percent
  350. for annotation in self.annotations {
  351. annotation.updateOpacity(percent, withPDFView: pdfView)
  352. }
  353. } else if view == lineWidthSlider {
  354. let percent = view.properties.percent * 17 + 1
  355. for annotation in self.annotations {
  356. annotation.updateLineWidth(percent, withPDFView: pdfView)
  357. }
  358. } else if view == lineDashSlider {
  359. let percent = view.properties.percent * 17 + 1
  360. for annotation in self.annotations {
  361. annotation.updateDashPattern(percent, withPDFView: pdfView)
  362. }
  363. }
  364. reloadData()
  365. }
  366. }
  367. //MARK: - ComponentSelectDelegate
  368. extension KMPenController: ComponentSelectDelegate {
  369. func componentSelectTextDidEndEditing(_ view: ComponentSelect, removeUnit text: String?) {
  370. if let result = text {
  371. if view == colorOpacitySelect {
  372. let opacity = max(0, min(1, result.stringToCGFloat()/100))
  373. for annotation in self.annotations {
  374. annotation.updateOpacity(opacity, withPDFView: pdfView)
  375. }
  376. } else if view == lineWidthSelect {
  377. var value = result.stringToCGFloat()
  378. if value > 18 {
  379. value = 18
  380. } else if value < 1 {
  381. value = 1
  382. }
  383. for annotation in self.annotations {
  384. annotation.updateLineWidth(value, withPDFView: pdfView)
  385. }
  386. } else if view == lineDashSelect {
  387. var value = result.stringToCGFloat()
  388. if value > 18 {
  389. value = 18
  390. } else if value < 1 {
  391. value = 1
  392. }
  393. for annotation in self.annotations {
  394. annotation.updateDashPattern(value, withPDFView: pdfView)
  395. }
  396. }
  397. reloadData()
  398. }
  399. }
  400. }
  401. //MARK: - ComponentCSelectorGroupDelegate
  402. extension KMPenController: ComponentCSelectorGroupDelegate {
  403. func componentCSelectorGroupDidChoose(_ view: ComponentCSelectorGroup, _ item: ComponentCSelectorItem) {
  404. if item.properties == solidProperty {
  405. for annotation in self.annotations {
  406. annotation.updateStyle(.solid, withPDFView: pdfView)
  407. }
  408. } else if item.properties == dashProperty {
  409. for annotation in self.annotations {
  410. annotation.updateStyle(.dashed, withPDFView: pdfView)
  411. }
  412. }
  413. reloadData()
  414. }
  415. }