KMNPopContentEditWindowController.swift 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. //
  2. // KMNPopContentEditWindowController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by 丁林圭 on 2024/12/2.
  6. //
  7. import Cocoa
  8. import KMComponentLibrary
  9. class KMNPopContentEditWindowController: KMNBaseWindowController {
  10. public var editType:EditContentPopType = .editNone {
  11. didSet {
  12. rightOffsetConstraint.constant = 45.0
  13. paneBox.isHidden = false
  14. switch editType {
  15. case .signTextEdit :
  16. textPopView.layoutSubtreeIfNeeded()
  17. operationWidthConstraint.constant = textPopView.bounds.width
  18. self.window?.display() //需刷新约束才会有值,不然会变化
  19. operationBox.contentView = textPopView
  20. congfigFontPopUI()
  21. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightLeft")
  22. fontAlightButton.reloadData()
  23. break
  24. case .signImageEdit:
  25. imagePopView.layoutSubtreeIfNeeded()
  26. congfigSignImageUI()
  27. operationWidthConstraint.constant = imagePopView.bounds.width
  28. self.window?.display() //需刷新约束才会有值,不然会变化
  29. operationBox.contentView = imagePopView
  30. break
  31. case .multpleTextEdit:
  32. textPopView.layoutSubtreeIfNeeded()
  33. operationWidthConstraint.constant = textPopView.bounds.width
  34. self.window?.display() //需刷新约束才会有值,不然会变化
  35. operationBox.contentView = textPopView
  36. congfigFontPopUI()
  37. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightLeft")
  38. fontAlightButton.reloadData()
  39. break
  40. case .multpleImageEdit:
  41. imagePopView.layoutSubtreeIfNeeded()
  42. congfigMultpleImageUI()
  43. operationWidthConstraint.constant = imagePopView.bounds.width
  44. self.window?.display() //需刷新约束才会有值,不然会变化
  45. operationBox.contentView = imagePopView
  46. break
  47. case .multpleImageAndText:
  48. alightView.layoutSubtreeIfNeeded()
  49. operationWidthConstraint.constant = alightView.bounds.width
  50. self.window?.display() //需刷新约束才会有值,不然会变化
  51. operationBox.contentView = alightView
  52. break
  53. case .cropImage:
  54. cropPopView.layoutSubtreeIfNeeded()
  55. rightOffsetConstraint.constant = 0
  56. paneBox.isHidden = true
  57. operationWidthConstraint.constant = cropPopView.bounds.width
  58. self.window?.display() //需刷新约束才会有值,不然会变化
  59. operationBox.contentView = cropPopView
  60. break
  61. case .editNone:
  62. break
  63. }
  64. }
  65. }
  66. public var isOpenPane = false {
  67. didSet {
  68. if isOpenPane == true {
  69. paneSelectorItem.properties.state = .pressed
  70. } else {
  71. paneSelectorItem.properties.state = .normal
  72. }
  73. paneSelectorItem.reloadData()
  74. }
  75. }
  76. public var editContentPopMode:KMNEditContentPopMode = KMNEditContentPopMode(currentEditAreas: []) {
  77. didSet {
  78. let editPopType = editContentPopMode.popType
  79. editType = editPopType
  80. if(editType == .signTextEdit || editType == .multpleTextEdit) {
  81. let textEditAreas = listView?.km_editingTextAreas()
  82. let oldColor:NSColor? = fontColor
  83. let firstTextEditArea = textEditAreas?.first
  84. let firstColor = listView?.editingSelectionFontColor(with: firstTextEditArea)
  85. var newColor:NSColor? = firstColor
  86. for textEditArea in textEditAreas ?? [] {
  87. if firstTextEditArea != textEditArea {
  88. let color = listView?.editingSelectionFontColor(with: firstTextEditArea)
  89. if CPDFListView.isTheSameColor(color, anotherColor: firstColor) == false{
  90. newColor = nil
  91. break
  92. }
  93. }
  94. }
  95. if !CPDFListView.isTheSameColor(newColor, anotherColor: oldColor) {
  96. fontColor = newColor
  97. }
  98. let oldBold:Bool = isBold
  99. let newBolds:[Bool] = listView?.km_editTextAreasFontBolds(textEditAreas ?? []) ?? []
  100. var newBold = true
  101. for i in 0 ..< newBolds.count {
  102. let boldV = newBolds[i]
  103. if boldV == false {
  104. newBold = false
  105. break
  106. }
  107. }
  108. if oldBold != newBold {
  109. isBold = newBold
  110. }
  111. let oldItalic:Bool = isItalic
  112. let newItalics:[Bool] = listView?.km_editTextAreasFontItalics(textEditAreas ?? []) ?? []
  113. var newItalic = true
  114. for i in 0 ..< newItalics.count {
  115. let boldV = newItalics[i]
  116. if boldV == false {
  117. newItalic = false
  118. break
  119. }
  120. }
  121. if oldItalic != newItalic {
  122. isItalic = newItalic
  123. }
  124. let oldStrikeoutLine:Bool = isStrikeoutLine
  125. let newStrikeoutLines:[Bool] = listView?.km_editTextAreasFontStrikeout(textEditAreas ?? []) ?? []
  126. var newStrikeoutLine = true
  127. for i in 0 ..< newStrikeoutLines.count {
  128. let boldV = newStrikeoutLines[i]
  129. if boldV == false {
  130. newStrikeoutLine = false
  131. break
  132. }
  133. }
  134. if oldStrikeoutLine != newStrikeoutLine {
  135. isStrikeoutLine = newStrikeoutLine
  136. }
  137. let oldUnderLine:Bool = isUnderLine
  138. let newUnderLines:[Bool] = listView?.km_editTextAreasFontUnder(textEditAreas ?? []) ?? []
  139. var newUnderLine = true
  140. for i in 0 ..< newStrikeoutLines.count {
  141. let boldV = newUnderLines[i]
  142. if boldV == false {
  143. newUnderLine = false
  144. break
  145. }
  146. }
  147. if oldUnderLine != newUnderLine {
  148. isUnderLine = newUnderLine
  149. }
  150. let alights = listView?.km_editTextAreasTextAlignments(textEditAreas ?? []) ?? []
  151. var newAlignment = alights.first ?? .left
  152. let oldAlignment :NSTextAlignment = fontAlight
  153. for i in 0 ..< alights.count {
  154. let alignmentV = alights[i]
  155. if oldAlignment != alignmentV {
  156. newAlignment = .left
  157. break
  158. }
  159. }
  160. if oldAlignment != newAlignment {
  161. fontAlight = newAlignment
  162. }
  163. let fonts = listView?.km_editTextAreasComPDFFonts(textEditAreas ?? []) ?? []
  164. var newFont:CPDFFont? = fonts.first
  165. for i in 0 ..< fonts.count {
  166. let fontV = fonts[i]
  167. if i != 0 && (fontV.familyName != compdfFont?.familyName || fontV.styleName != compdfFont?.styleName) {
  168. newFont = nil
  169. break
  170. }
  171. }
  172. compdfFont = newFont
  173. }
  174. }
  175. }
  176. private var fontColor:NSColor? {
  177. didSet {
  178. fontColorItem.properties?.color = fontColor
  179. fontColorItem.reloadData()
  180. }
  181. }
  182. private var compdfFont:CPDFFont?{
  183. didSet {
  184. if(compdfFont != nil) {
  185. let styleName = compdfFont!.styleName
  186. if(styleName?.isEmpty == true) {
  187. fontNameSelect.properties.text = compdfFont!.familyName
  188. } else {
  189. fontNameSelect.properties.text = compdfFont!.familyName + "-" + (compdfFont!.styleName ?? "")
  190. }
  191. } else {
  192. fontNameSelect.properties.text = "-"
  193. }
  194. fontNameSelect.reloadData()
  195. }
  196. }
  197. private var fontAlight:NSTextAlignment = .left {
  198. didSet {
  199. if fontAlight == .center {
  200. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightCenter")
  201. } else if fontAlight == .right {
  202. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightRight")
  203. } else if fontAlight == .justified {
  204. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightJus")
  205. } else {
  206. fontAlightButton.properties.icon = NSImage(named: "KMNImageNameListViewPopAlightLeft")
  207. }
  208. fontAlightButton.reloadData()
  209. }
  210. }
  211. private var objectAlign:ObjectAlignType = .alightLeft {
  212. didSet {
  213. var zeroRect = NSRect.null
  214. var highestRect = NSZeroRect
  215. var widthestRect = NSZeroRect
  216. let objects = editContentPopMode.editAreas
  217. let fristObject : CPDFEditArea = objects.first ?? CPDFEditArea()
  218. var leftestRect = fristObject.bounds
  219. var rightestRect = fristObject.bounds
  220. var topestRect = fristObject.bounds
  221. var bottomestRect = fristObject.bounds
  222. var leftestObject : CPDFEditArea = fristObject
  223. var rightestObject : CPDFEditArea = fristObject
  224. var topestObject : CPDFEditArea = fristObject
  225. var bottomestObject: CPDFEditArea = fristObject
  226. var totalWidth = 0.0
  227. var totalHeight = 0.0
  228. for i in 0 ..< objects.count {
  229. let annotation : CPDFEditArea = objects[i]
  230. zeroRect = zeroRect.union(annotation.bounds)
  231. totalWidth = totalWidth + annotation.bounds.width
  232. totalHeight = totalHeight + annotation.bounds.height
  233. if annotation.bounds.height > highestRect.height {
  234. highestRect = annotation.bounds
  235. }
  236. if annotation.bounds.width > widthestRect.width {
  237. widthestRect = annotation.bounds
  238. }
  239. if leftestRect.minX > annotation.bounds.minX {
  240. leftestRect = annotation.bounds
  241. leftestObject = annotation
  242. }
  243. if annotation.bounds.maxX > rightestRect.maxX {
  244. rightestRect = annotation.bounds
  245. rightestObject = annotation
  246. }
  247. if annotation.bounds.maxY > topestRect.maxY {
  248. topestRect = annotation.bounds
  249. topestObject = annotation
  250. }
  251. if bottomestRect.minY > annotation.bounds.minY {
  252. bottomestRect = annotation.bounds
  253. bottomestObject = annotation
  254. }
  255. }
  256. var resultAreasArray: [CPDFEditArea] = []
  257. var newBoundsArray: [String] = []
  258. switch objectAlign {
  259. case .alightLeft :
  260. for i in 0 ..< objects.count {
  261. let object = objects[i]
  262. var bounds = object.bounds
  263. bounds.origin.x = zeroRect.origin.x
  264. newBoundsArray.append(NSStringFromRect(bounds))
  265. }
  266. resultAreasArray = objects
  267. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightLeft")
  268. break
  269. case .alightRight:
  270. for i in 0 ..< objects.count {
  271. let object = objects[i]
  272. var bounds = object.bounds
  273. bounds.origin.x = zeroRect.maxX - bounds.size.width
  274. newBoundsArray.append(NSStringFromRect(bounds))
  275. }
  276. resultAreasArray = objects
  277. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightRight")
  278. break
  279. case .alightTop:
  280. for i in 0 ..< objects.count {
  281. let object = objects[i]
  282. var bounds = object.bounds
  283. bounds.origin.y = zeroRect.maxY - bounds.size.height
  284. newBoundsArray.append(NSStringFromRect(bounds))
  285. }
  286. resultAreasArray = objects
  287. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightTop")
  288. break
  289. case .alightVer:
  290. for i in 0 ..< objects.count {
  291. let object = objects[i]
  292. var bounds = object.bounds
  293. bounds.origin.x = widthestRect.midX - bounds.width/2
  294. newBoundsArray.append(NSStringFromRect(bounds))
  295. }
  296. resultAreasArray = objects
  297. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightVer")
  298. break
  299. case .alightHor:
  300. for i in 0 ..< objects.count {
  301. let object = objects[i]
  302. var bounds = object.bounds
  303. bounds.origin.y = highestRect.midY - bounds.height/2
  304. newBoundsArray.append(NSStringFromRect(bounds))
  305. }
  306. resultAreasArray = objects
  307. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightHor")
  308. break
  309. case .alightBottom:
  310. for i in 0 ..< objects.count {
  311. let object = objects[i]
  312. var bounds = object.bounds
  313. bounds.origin.y = zeroRect.minY
  314. newBoundsArray.append(NSStringFromRect(bounds))
  315. }
  316. resultAreasArray = objects
  317. alightButton.properties.icon = NSImage(named: "KMNImageNameObjectPopAlightBottom")
  318. break
  319. case .averageVer:
  320. let middleGap = zeroRect.height - topestRect.height - bottomestRect.height
  321. let otherAreasTotalHeight = totalHeight - topestRect.height - bottomestRect.height
  322. let gap = (middleGap - otherAreasTotalHeight)/CGFloat(objects.count - 1)
  323. var areasCopyArray : [CPDFEditArea] = objects
  324. areasCopyArray.sorted(by: { obj1, obj2 in
  325. let area1 = obj1
  326. let area2 = obj2
  327. if area1.bounds.origin.x < area2.bounds.origin.x {
  328. return true
  329. } else {
  330. return false
  331. }
  332. })
  333. if let index = areasCopyArray.firstIndex(of: topestObject) {
  334. areasCopyArray.remove(at: index)
  335. }
  336. if let index = areasCopyArray.firstIndex(of: bottomestObject) {
  337. areasCopyArray.remove(at: index)
  338. }
  339. var bottomStartY = bottomestRect.maxY + gap
  340. for i in 0 ..< areasCopyArray.count {
  341. let areas = areasCopyArray[i]
  342. var bounds = areas.bounds
  343. bounds.origin.y = bottomStartY
  344. newBoundsArray.append(NSStringFromRect(bounds))
  345. bottomStartY = bottomStartY + bounds.height + gap
  346. }
  347. resultAreasArray = areasCopyArray
  348. alightButton.properties.icon = NSImage(named: "KMNImageNameObjecAlignAverageVer")
  349. break
  350. case .averageHor:
  351. let middleGap = zeroRect.width - leftestRect.width - rightestRect.width
  352. let otherAreasTotalWidth = totalWidth - leftestRect.width - rightestRect.width
  353. let gap = (middleGap - otherAreasTotalWidth)/CGFloat(objects.count - 1)
  354. var areasCopyArray : [CPDFEditArea] = objects
  355. areasCopyArray.sorted(by: { obj1, obj2 in
  356. let area1 = obj1
  357. let area2 = obj2
  358. if area1.bounds.origin.x < area2.bounds.origin.x {
  359. return true
  360. } else {
  361. return false
  362. }
  363. })
  364. if let index = areasCopyArray.firstIndex(of: leftestObject) {
  365. areasCopyArray.remove(at: index)
  366. }
  367. if let index = areasCopyArray.firstIndex(of: rightestObject) {
  368. areasCopyArray.remove(at: index)
  369. }
  370. var leftStartX = leftestRect.maxX + gap
  371. for i in 0 ..< areasCopyArray.count {
  372. let areas = areasCopyArray[i]
  373. var bounds = areas.bounds
  374. bounds.origin.x = leftStartX
  375. newBoundsArray.append(NSStringFromRect(bounds))
  376. leftStartX = leftStartX + bounds.width + gap
  377. }
  378. resultAreasArray = areasCopyArray
  379. alightButton.properties.icon = NSImage(named: "KMNImageNameObjecAlignAverageHor")
  380. break
  381. }
  382. alightButton.reloadData()
  383. for i in 0 ..< resultAreasArray.count {
  384. let editArea : CPDFEditArea = resultAreasArray[i]
  385. listView?.setBoundsEditArea(editArea, withBounds: NSRectFromString(newBoundsArray[i]))
  386. }
  387. }
  388. }
  389. private var isBold:Bool = false {
  390. didSet {
  391. fontBoldSelectorItem.properties.state = isBold ? .pressed : .normal
  392. fontBoldSelectorItem.reloadData()
  393. }
  394. }
  395. private var isItalic:Bool = false {
  396. didSet {
  397. fontItalicSelectorItem.properties.state = isItalic ? .pressed : .normal
  398. fontItalicSelectorItem.reloadData()
  399. }
  400. }
  401. private var isStrikeoutLine:Bool = false {
  402. didSet {
  403. fontStrikeoutLineSelectorItem.properties.state = isStrikeoutLine ? .pressed : .normal
  404. fontStrikeoutLineSelectorItem.reloadData()
  405. }
  406. }
  407. private var isUnderLine:Bool = false {
  408. didSet {
  409. fontUnderLineSelectorItem.properties.state = isUnderLine ? .pressed : .normal
  410. fontUnderLineSelectorItem.reloadData()
  411. }
  412. }
  413. static let shared: KMNPopContentEditWindowController = {
  414. let windowC = KMNPopContentEditWindowController(windowNibName: "KMNPopContentEditWindowController")
  415. return windowC
  416. }()
  417. var paneCallback: PaneCallback?
  418. var updatePDFViewCallback: UpdatePDFViewCallback?
  419. @IBOutlet weak var contentBox: NSBox!
  420. @IBOutlet weak var operationBox: NSBox!
  421. @IBOutlet weak var paneBox: NSBox!
  422. @IBOutlet weak var lineBox: NSBox!
  423. @IBOutlet var paneSelectorItem: ComponentCSelectorItem!
  424. @IBOutlet weak var operationWidthConstraint: NSLayoutConstraint!
  425. @IBOutlet weak var rightOffsetConstraint: NSLayoutConstraint!
  426. @IBOutlet var textPopView: NSView!
  427. @IBOutlet var fontColorItem: ComponentCColorItem!
  428. @IBOutlet var fontNameSelect: ComponentSelect!
  429. @IBOutlet var fontBoldSelectorItem: ComponentCSelector!
  430. @IBOutlet var fontItalicSelectorItem: ComponentCSelector!
  431. @IBOutlet var fontStrikeoutLineSelectorItem: ComponentCSelector!
  432. @IBOutlet var fontUnderLineSelectorItem: ComponentCSelector!
  433. @IBOutlet var fontSizeZoomOutButton: ComponentButton!
  434. @IBOutlet var fontSizeZoomInButton: ComponentButton!
  435. @IBOutlet var fontAlightButton: ComponentButton!
  436. @IBOutlet var imagePopView: NSView!
  437. @IBOutlet var rotaLeftButton: ComponentButton!
  438. @IBOutlet var rotaRightButton: ComponentButton!
  439. @IBOutlet var horizontalMirrorButton: ComponentButton!
  440. @IBOutlet var verticalMirrorButton: ComponentButton!
  441. @IBOutlet var cropButton: ComponentButton!
  442. @IBOutlet var replaceButton: ComponentButton!
  443. @IBOutlet var extractButton: ComponentButton!
  444. @IBOutlet weak var rightConstraint: NSLayoutConstraint!
  445. @IBOutlet var alightView: NSView!
  446. @IBOutlet var alightButton: ComponentButton!
  447. @IBOutlet var cropPopView: NSView!
  448. @IBOutlet var cropSureButton: ComponentButton!
  449. @IBOutlet var cropRestButton: ComponentButton!
  450. private var extractGroupView: ComponentGroup?
  451. weak var listView: CPDFListView?
  452. private var fontPopover:NSPopover?
  453. private var ObjectPopover:NSPopover?
  454. override func windowDidLoad() {
  455. super.windowDidLoad()
  456. }
  457. override func initContentView() {
  458. super.initContentView()
  459. paneSelectorItem.properties = ComponentCSelectorProperty(iconImage:NSImage(named: "KMNImageNameListViewPopPane"))
  460. paneSelectorItem.setTarget(self, action: #selector(paneButtonClicked(_ :)))
  461. fontBoldSelectorItem.properties = ComponentCSelectorProperty(
  462. iconImage:NSImage(named: "KMNImageNameContentBold"))
  463. fontBoldSelectorItem.setTarget(self, action: #selector(fontBoldButtonClicked(_ :)))
  464. fontItalicSelectorItem.properties = ComponentCSelectorProperty(
  465. iconImage:NSImage(named: "KMNImageNameContentItalic"))
  466. fontItalicSelectorItem.setTarget(self, action: #selector(fontItalicButtonClicked(_ :)))
  467. fontStrikeoutLineSelectorItem.properties = ComponentCSelectorProperty(
  468. iconImage:NSImage(named: "KMNImageNameContentStrikeoutLine"))
  469. fontStrikeoutLineSelectorItem.setTarget(self, action: #selector(fontStrikeoutLineButtonClicked(_ :)))
  470. fontUnderLineSelectorItem.properties = ComponentCSelectorProperty(iconImage:NSImage(named: "KMNImageNameContentUnderLine"))
  471. fontUnderLineSelectorItem.setTarget(self, action: #selector(fontUnderLineButtonClicked(_ :)))
  472. fontSizeZoomOutButton.properties = ComponentButtonProperty(type: .text_gray,
  473. size: .s,
  474. state: .normal,
  475. onlyIcon: true,
  476. icon:NSImage(named: "KMNImageNameListViewPopFontSizeZoomOut"),
  477. keepPressState: false)
  478. fontSizeZoomOutButton.setTarget(self, action: #selector(fontSizeZoomOutButtonClicked(_ :)))
  479. fontSizeZoomInButton.properties = ComponentButtonProperty(type: .text_gray,
  480. size: .s,
  481. state: .normal,
  482. onlyIcon: true,
  483. icon:NSImage(named: "KMNImageNameListViewPopFontSizeZoomIn"),
  484. keepPressState: false)
  485. fontSizeZoomInButton.setTarget(self, action: #selector(fontSizeZoomInButtonClicked(_ :)))
  486. fontColorItem.properties = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: .clear)
  487. fontColorItem.delegate = self
  488. fontAlightButton.properties = ComponentButtonProperty(type: .text_gray,
  489. size: .s,
  490. state: .normal,
  491. onlyIcon: true,
  492. icon:NSImage(named: "KMNImageNameListViewPopAlightLeft"),
  493. keepPressState: false)
  494. fontAlightButton.setTarget(self, action: #selector(fontAlightButtonClicked(_ :)))
  495. rotaLeftButton.properties = ComponentButtonProperty(type: .text_gray,
  496. size: .s,
  497. state: .normal,
  498. onlyIcon: true,
  499. icon:NSImage(named: "KMNImageNameContentRotateLeft"),
  500. keepPressState: false)
  501. rotaLeftButton.setTarget(self, action: #selector(rotateLeftButtonClicked(_ :)))
  502. rotaRightButton.properties = ComponentButtonProperty(type: .text_gray,
  503. size: .s,
  504. state: .normal,
  505. onlyIcon: true,
  506. icon:NSImage(named: "KMNImageNameContentRotateRight"),
  507. keepPressState: false)
  508. rotaRightButton.setTarget(self, action: #selector(rotateRightButtonClicked(_ :)))
  509. horizontalMirrorButton.properties = ComponentButtonProperty(type: .text_gray,
  510. size: .s,
  511. state: .normal,
  512. onlyIcon: true,
  513. icon:NSImage(named: "KMNImageNameContentHorMirr"),
  514. keepPressState: false)
  515. horizontalMirrorButton.setTarget(self, action: #selector(horizontalMirrorButtonClicked(_ :)))
  516. verticalMirrorButton.properties = ComponentButtonProperty(type: .text_gray,
  517. size: .s,
  518. state: .normal,
  519. onlyIcon: true,
  520. icon:NSImage(named: "KMNImageNameContentVerMirr"),
  521. keepPressState: false)
  522. verticalMirrorButton.setTarget(self, action: #selector(verticalMirrorButtonClicked(_ :)))
  523. alightButton.properties = ComponentButtonProperty(type: .text_gray,
  524. size: .s,
  525. state: .normal,
  526. onlyIcon: true,
  527. icon:NSImage(named: "KMNImageNameObjectPopAlightLeft"))
  528. alightButton.setTarget(self, action: #selector(alightButtonClicked(_ :)))
  529. cropRestButton.properties = ComponentButtonProperty(type: .text_gray,
  530. size: .s,
  531. state: .normal,
  532. onlyIcon: true,
  533. icon:NSImage(named: "KMNImageNameContentCropRest"),keepPressState: false)
  534. cropRestButton.setTarget(self, action: #selector(cropRestClicked(_ :)))
  535. cropSureButton.properties = ComponentButtonProperty(type: .text_gray,
  536. size: .s,
  537. state: .normal,
  538. onlyIcon: true,
  539. icon:NSImage(named: "KMNImageNameContentCropSure"),keepPressState: false)
  540. cropSureButton.setTarget(self, action: #selector(cropSureClicked(_ :)))
  541. }
  542. override func updateUIThemeColor() {
  543. super.updateUIThemeColor()
  544. lineBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/divider")
  545. contentBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/popup")
  546. contentBox.borderColor = ComponentLibrary.shared.getComponentColorFromKey("colorBorder/3-default")
  547. }
  548. override func updateUILanguage() {
  549. super.updateUILanguage()
  550. }
  551. //MARK: - Public
  552. public func updateFrame(listView:CPDFListView) {
  553. let editingAreas = listView.km_EditingAreas()
  554. let page = editingAreas.first?.page
  555. let windowFram = listView.window?.frame ?? CGRectZero
  556. if(page != nil) {
  557. let pageRect = listView.selectionMultipleBounds(withEditArea: editingAreas)
  558. let positioningRect = listView.convert(pageRect, from: page!)
  559. let view: NSView? = nil
  560. let position = listView.convert(positioningRect, to: view)
  561. var positionNew = position.origin
  562. positionNew.x += windowFram.origin.x + position.width/2
  563. positionNew.y += windowFram.origin.y + position.height
  564. var positionRect = self.window?.frame ?? CGRectZero
  565. positionRect.origin.x = positionNew.x - positionRect.width/2
  566. positionRect.origin.y = positionNew.y + popOffSet + CGFloat(truncating: listView.editingConfig().editAreaMargin)
  567. var listViewWindRect = listView.convert(listView.frame, to: view)
  568. listViewWindRect.origin.x += windowFram.origin.x
  569. listViewWindRect.origin.y += windowFram.origin.y
  570. if CGRectGetMaxY(positionRect) > CGRectGetMaxY(listViewWindRect) {
  571. positionRect.origin.y = positionNew.y - popOffSet - position.height - positionRect.size.height
  572. }
  573. if CGRectGetMinX(positionRect) < CGRectGetMinX(listViewWindRect) {
  574. positionRect.origin.x = CGRectGetMinX(listViewWindRect)
  575. }
  576. if CGRectGetMaxX(positionRect) > CGRectGetMaxX(listViewWindRect) {
  577. positionRect.origin.x = CGRectGetMaxX(listViewWindRect) - positionRect.width
  578. }
  579. self.window?.setFrame(positionRect, display: true)
  580. updateUILanguage()
  581. }
  582. }
  583. public func closeWindow(listView:CPDFListView?) {
  584. if self.window?.isVisible == true {
  585. listView?.window?.removeChildWindow(self.window ?? NSWindow())
  586. self.window?.close()
  587. }
  588. if ObjectPopover?.isShown == true {
  589. ObjectPopover?.close()
  590. }
  591. if fontPopover?.isShown == true {
  592. fontPopover?.close()
  593. }
  594. }
  595. //MARK: - private
  596. private func congfigFontPopUI() {
  597. fontNameSelect.properties = ComponentSelectProperties(size: .s,
  598. state: .normal,
  599. isDisabled: false,
  600. isError: false,
  601. leftIcon: false,
  602. placeholder: nil,
  603. errorText: nil,
  604. creatable: false,
  605. text: NSLocalizedString("", comment: ""))
  606. fontNameSelect.delegate = self
  607. var menuItemArr: [ComponentMenuitemProperty] = []
  608. for familyName in CPDFFont.familyNames {
  609. let fontNames = CPDFFont.fontNames(forFamilyName: familyName)
  610. let itemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  611. itemSelected: false,
  612. isDisabled: false,
  613. keyEquivalent: nil,
  614. text: familyName,
  615. identifier: "1")
  616. var subMenuItemArr: [ComponentMenuitemProperty] = []
  617. for fontName in fontNames {
  618. let subItemProperty: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  619. itemSelected: false,
  620. isDisabled: false,
  621. keyEquivalent: nil,
  622. text: fontName,identifier: "2")
  623. subMenuItemArr.append(subItemProperty)
  624. }
  625. itemProperty.subPropertys = subMenuItemArr
  626. menuItemArr.append(itemProperty)
  627. }
  628. fontNameSelect.updateMenuItemsArr(menuItemArr)
  629. }
  630. private func congfigSignImageUI() {
  631. rightConstraint.constant = 36
  632. imagePopView.display()
  633. cropButton.properties = ComponentButtonProperty(type: .text_gray,
  634. size: .s,
  635. state: .normal,
  636. onlyIcon: true,
  637. icon:NSImage(named: "KMNImageNameContentCrop"),
  638. keepPressState: false)
  639. cropButton.setTarget(self, action: #selector(cropImageButtonClicked(_ :)))
  640. replaceButton.properties = ComponentButtonProperty(type: .text_gray,
  641. size: .s,
  642. state: .normal,
  643. onlyIcon: true,
  644. icon:NSImage(named: "KMNImageNameContentReplace"),
  645. keepPressState: false)
  646. replaceButton.setTarget(self, action: #selector(replaceImageButtonClicked(_ :)))
  647. extractButton.properties = ComponentButtonProperty(type: .text_gray,
  648. size: .s,
  649. state: .normal,
  650. onlyIcon: true,
  651. icon:NSImage(named: "KMNImageNameContentExtract"),
  652. keepPressState: false)
  653. extractButton.setTarget(self, action: #selector(extractImageButtonClicked(_ :)))
  654. extractButton.isHidden = false
  655. }
  656. private func congfigMultpleImageUI() {
  657. rightConstraint.constant = 0
  658. imagePopView.display()
  659. cropButton.properties = ComponentButtonProperty(type: .text_gray,
  660. size: .s,
  661. state: .normal,
  662. onlyIcon: true,
  663. icon:NSImage(named: "KMNImageNameContentExtract"),
  664. keepPressState: false)
  665. cropButton.setTarget(self, action: #selector(extractImageButtonClicked(_ :)))
  666. replaceButton.properties = ComponentButtonProperty(type: .text_gray,
  667. size: .s,
  668. state: .normal,
  669. onlyIcon: true,
  670. icon:NSImage(named: "KMNImageNameContentReplace"),
  671. keepPressState: false)
  672. replaceButton.setTarget(self, action: #selector(alightButtonClicked(_ :)))
  673. extractButton.isHidden = true
  674. }
  675. func removeGroupView() {
  676. if extractGroupView != nil {
  677. extractGroupView?.removeFromSuperview()
  678. }
  679. extractButton.properties.state = .normal
  680. extractButton.reloadData()
  681. }
  682. //MARK: - Action
  683. @objc func paneButtonClicked(_ sender: NSView) {
  684. isOpenPane = !isOpenPane
  685. paneCallback?(isOpenPane)
  686. }
  687. @objc func fontBoldButtonClicked(_ sender: NSView) {
  688. listView?.setEditingTextarea_Bold()
  689. updatePDFViewCallback?()
  690. let textEditAreas = listView?.km_editingTextAreas()
  691. let newBolds:[Bool] = listView?.km_editTextAreasFontBolds(textEditAreas ?? []) ?? []
  692. if newBolds.first == false {
  693. fontBoldSelectorItem.properties.state = .normal
  694. fontBoldSelectorItem.reloadData()
  695. }
  696. }
  697. @objc func fontItalicButtonClicked(_ sender: NSView) {
  698. listView?.setEditingTextarea_Italic()
  699. updatePDFViewCallback?()
  700. let textEditAreas = listView?.km_editingTextAreas()
  701. let newItalics:[Bool] = listView?.km_editTextAreasFontItalics(textEditAreas ?? []) ?? []
  702. if newItalics.first == false {
  703. fontItalicSelectorItem.properties.state = .normal
  704. fontItalicSelectorItem.reloadData()
  705. }
  706. }
  707. @objc func fontUnderLineButtonClicked(_ sender: NSView) {
  708. listView?.setEditingTextarea_Under()
  709. updatePDFViewCallback?()
  710. let textEditAreas = listView?.km_editingTextAreas()
  711. let newUnders:[Bool] = listView?.km_editTextAreasFontUnder(textEditAreas ?? []) ?? []
  712. if newUnders.first == false {
  713. fontUnderLineSelectorItem.properties.state = .normal
  714. fontUnderLineSelectorItem.reloadData()
  715. }
  716. }
  717. @objc func fontStrikeoutLineButtonClicked(_ sender: NSView) {
  718. listView?.setEditingTextarea_Strikeout()
  719. updatePDFViewCallback?()
  720. let textEditAreas = listView?.km_editingTextAreas()
  721. let newStrikeouts:[Bool] = listView?.km_editTextAreasFontStrikeout(textEditAreas ?? []) ?? []
  722. if newStrikeouts.first == false {
  723. fontStrikeoutLineSelectorItem.properties.state = .normal
  724. fontStrikeoutLineSelectorItem.reloadData()
  725. }
  726. }
  727. @objc func fontSizeZoomOutButtonClicked(_ sender: NSView) {
  728. let textEditAreas = listView?.km_editingTextAreas()
  729. for i in 0 ..< (textEditAreas?.count ?? 0) {
  730. let textEditArea = textEditAreas?[i]
  731. let fontSize = listView?.editingSelectionFontSize(byRangeEdit: textEditArea) ?? 0
  732. if(fontSize > changeValue) {
  733. listView?.setEditingSelectionFontSize((fontSize - changeValue), with: textEditArea, isAutoSize: false)
  734. }
  735. }
  736. updatePDFViewCallback?()
  737. }
  738. @objc func fontSizeZoomInButtonClicked(_ sender: NSView) {
  739. let textEditAreas = listView?.km_editingTextAreas()
  740. for i in 0 ..< (textEditAreas?.count ?? 0) {
  741. let textEditArea = textEditAreas?[i]
  742. let fontSize = listView?.editingSelectionFontSize(byRangeEdit: textEditArea) ?? 0
  743. listView?.setEditingSelectionFontSize((fontSize + changeValue), with: textEditArea, isAutoSize: false)
  744. }
  745. updatePDFViewCallback?()
  746. }
  747. @objc func alightButtonClicked(_ sender: NSView) {
  748. if ObjectPopover?.isShown == true {
  749. ObjectPopover?.close()
  750. } else {
  751. let vc = KMNPopDetailsViewController(nibName: "KMNPopDetailsViewController", bundle: nil)
  752. let createFilePopover: NSPopover = NSPopover.init()
  753. createFilePopover.contentViewController = vc
  754. createFilePopover.delegate = self
  755. createFilePopover.animates = true
  756. createFilePopover.behavior = .semitransient
  757. createFilePopover.setValue(true, forKey: "shouldHideAnchor")
  758. createFilePopover.show(relativeTo: CGRect(x: sender.bounds.origin.x, y: 20, width: sender.bounds.size.width, height: sender.bounds.size.height), of: sender, preferredEdge: .maxY)
  759. if (editContentPopMode.editAreas.count == 2) {
  760. vc.detailPopType = .doubleObjectAlight
  761. } else if (editContentPopMode.editAreas.count > 2) {
  762. vc.detailPopType = .multpleObjectAlight
  763. }
  764. vc.objectChangeAlighCallback = { [weak self] alight in
  765. self?.objectAlign = alight
  766. self?.updatePDFViewCallback?()
  767. }
  768. ObjectPopover = createFilePopover
  769. vc.objectAlignType = objectAlign
  770. }
  771. }
  772. @objc func fontAlightButtonClicked(_ sender: NSView) {
  773. if fontPopover?.isShown == true {
  774. fontPopover?.close()
  775. } else {
  776. let vc = KMNPopDetailsViewController(nibName: "KMNPopDetailsViewController", bundle: nil)
  777. let createFilePopover: NSPopover = NSPopover.init()
  778. createFilePopover.contentViewController = vc
  779. createFilePopover.delegate = self
  780. createFilePopover.animates = true
  781. createFilePopover.behavior = .semitransient
  782. createFilePopover.setValue(true, forKey: "shouldHideAnchor")
  783. createFilePopover.show(relativeTo: CGRect(x: sender.bounds.origin.x, y: 20, width: sender.bounds.size.width, height: sender.bounds.size.height), of: sender, preferredEdge: .maxY)
  784. vc.detailPopType = .contentEditAlight
  785. vc.fontChangeAlighCallback = { [weak self] alight in
  786. self?.listView?.setEditingTextarea_Alignment(align: .right)
  787. self?.fontAlight = alight
  788. self?.updatePDFViewCallback?()
  789. }
  790. fontPopover = createFilePopover
  791. vc.fontAlight = fontAlight
  792. }
  793. }
  794. @objc func rotateLeftButtonClicked(_ sender: NSView) {
  795. listView?.leftRotateAction()
  796. updatePDFViewCallback?()
  797. }
  798. @objc func rotateRightButtonClicked(_ sender: NSView) {
  799. listView?.rightRotateAction()
  800. updatePDFViewCallback?()
  801. }
  802. @objc func horizontalMirrorButtonClicked(_ sender: NSView) {
  803. listView?.reverseXAction()
  804. updatePDFViewCallback?()
  805. }
  806. @objc func verticalMirrorButtonClicked(_ sender: NSView) {
  807. listView?.reverseYAction()
  808. updatePDFViewCallback?()
  809. }
  810. @objc func cropImageButtonClicked(_ sender: NSView) {
  811. listView?.cropAction()
  812. }
  813. @objc func replaceImageButtonClicked(_ sender: NSView) {
  814. if let areas = listView?.km_editingImageAreas() {
  815. let panel = NSOpenPanel()
  816. panel.allowsMultipleSelection = false
  817. panel.allowedFileTypes = ["png","jpg"]
  818. panel.beginSheetModal(for: NSApp.mainWindow!) { response in
  819. if response == .OK {
  820. let openPath = panel.url?.path
  821. for area in areas {
  822. self.listView?.replace(area, imagePath: openPath!)
  823. }
  824. }
  825. }
  826. }
  827. }
  828. @objc func extractImageButtonClicked(_ sender: NSView) {
  829. if extractGroupView?.superview != nil {
  830. removeGroupView()
  831. } else {
  832. var viewHeight: CGFloat = 8
  833. var menuItemArr: [ComponentMenuitemProperty] = []
  834. for i in ["jpg", "png", "pdf"] {
  835. let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false,
  836. itemSelected: false,
  837. isDisabled: false,
  838. keyEquivalent: nil,
  839. text: KMLocalizedString(i))
  840. menuItemArr.append(properties_Menuitem)
  841. viewHeight += 36
  842. }
  843. if extractGroupView == nil {
  844. extractGroupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle())
  845. }
  846. extractGroupView?.groupDelegate = self
  847. extractGroupView?.frame = CGRectMake(310, 0, 72, viewHeight)
  848. extractGroupView?.updateGroupInfo(menuItemArr)
  849. var point = CGPoint(x: sender.frame.origin.x + sender.frame.size.width/2, y: CGRectGetMaxY(sender.frame))
  850. extractGroupView?.showWithPoint(point, relativeTo: self.window?.contentView)
  851. extractButton.properties.state = .pressed
  852. extractButton.reloadData()
  853. }
  854. }
  855. @objc func cropRestClicked(_ sender: NSView) {
  856. listView?.cropRestAction()
  857. }
  858. @objc func cropSureClicked(_ sender: NSView) {
  859. listView?.cropComfirmAction()
  860. }
  861. @objc func fontColorChange(_ sender: Any) {
  862. if let color = (sender as? NSColorPanel)?.color {
  863. listView?.changeEditingTextarea_Color(color: color)
  864. updatePDFViewCallback?()
  865. }
  866. }
  867. }
  868. //MARK: - ComponentCColorDelegate
  869. extension KMNPopContentEditWindowController: ComponentCColorDelegate {
  870. func componentCColorDidChooseColor(_ view: NSView, _ color: NSColor?) {
  871. if (view == fontColorItem) {
  872. fontColorItem.properties?.state = .normal
  873. fontColorItem.reloadData()
  874. let colorPanel = NSColorPanel.shared
  875. colorPanel.setTarget(self)
  876. colorPanel.showsAlpha = false
  877. colorPanel.setAction(#selector(self.fontColorChange(_:)))
  878. colorPanel.orderFront(nil)
  879. }
  880. }
  881. }
  882. //MARK: - ComponentSelectDelegate
  883. extension KMNPopContentEditWindowController: ComponentSelectDelegate {
  884. func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) {
  885. if(view == fontNameSelect) {
  886. if menuItemProperty?.identifier == "1" {
  887. let familyName = fontNameSelect.properties.text ?? "Helvetica"
  888. let styles = CPDFFont.fontNames(forFamilyName: familyName)
  889. compdfFont = CPDFFont(familyName: familyName, fontStyle: styles.first ?? "")
  890. listView?.setEditingTextarea_font(font: compdfFont ?? CPDFFont(familyName: "Helvetica", fontStyle: ""))
  891. } else if menuItemProperty?.identifier == "2" { //字体样式
  892. compdfFont = CPDFFont(familyName: compdfFont?.familyName ?? "Helvetica", fontStyle: menuItemProperty?.text ?? "")
  893. listView?.setEditingTextarea_font(font: compdfFont ?? CPDFFont(familyName: "Helvetica", fontStyle: ""))
  894. }
  895. }
  896. }
  897. }
  898. //MARK: - ComponentSelectDelegate
  899. extension KMNPopContentEditWindowController: NSPopoverDelegate {
  900. func popoverWillClose(_ notification: Notification) {
  901. if fontPopover == (notification.object as? NSPopover) {
  902. if(fontAlightButton.properties.state == .pressed) {
  903. fontAlightButton.properties.state = .normal
  904. fontAlightButton.reloadData()
  905. }
  906. } else if ObjectPopover == (notification.object as? NSPopover) {
  907. if(alightButton.properties.state == .pressed) {
  908. alightButton.properties.state = .normal
  909. alightButton.reloadData()
  910. }
  911. }
  912. }
  913. }
  914. extension KMNPopContentEditWindowController: ComponentGroupDelegate {
  915. func componentGroupDidDismiss(group: ComponentGroup?) {
  916. removeGroupView()
  917. extractButton.properties.state = .normal
  918. extractButton.reloadData()
  919. }
  920. func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) {
  921. if group == extractGroupView {
  922. if let selItem = menuItemProperty {
  923. let index = group?.menuItemArr.firstIndex(of: selItem)
  924. if index == 0 {
  925. listView?.exportEditingImageAreasAction(format: "jpg")
  926. } else if index == 1 {
  927. listView?.exportEditingImageAreasAction(format: "png")
  928. } else if index == 2 {
  929. listView?.exportEditingImageAreasAction(format: "pdf")
  930. }
  931. }
  932. }
  933. }
  934. }