// // KMEditPDFTextPropertyViewController.swift // PDF Master // // Created by lxy on 2022/12/27. // import Cocoa let CEditPDFTextDefaultFontName = "CEditPDFTextDefaultFontName" let CEditPDFTextDefaultFontStyle = "CEditPDFTextDefaultFontStyle" let CEditPDFTextDefaultFontSize = "CEditPDFTextDefaultFontSize" let CEditPDFTextDefaultFontColor = "CEditPDFTextDefaultFontColor" let CEditPDFTextDefaultFontAlign = "CEditPDFTextDefaultFontAlign" enum CPDFActiveAreasAlignType : Int { case Left case Vertical case Right case Top case Horizontally case Bottom case DisHorizontally case DisVertical } class KMEditPDFTextPropertyViewController: NSViewController { @IBOutlet weak var headerBox: NSBox! @IBOutlet weak var propertyTitle: NSTextField! @IBOutlet weak var preViewBox: NSBox! @IBOutlet weak var preViewHeight: NSLayoutConstraint! @IBOutlet weak var preImageView: NSImageView! @IBOutlet weak var useButton: NSButton! @IBOutlet weak var styleBox: NSComboBox! @IBOutlet weak var fontTitleLabel: NSTextField! @IBOutlet weak var fontSetBox: NSBox! @IBOutlet weak var fontStyleComboBox: NSComboBox! @IBOutlet weak var alignRightButton: NSButton! @IBOutlet weak var alignCenterButton: NSButton! @IBOutlet weak var alignLeftButton: NSButton! @IBOutlet weak var currentFontColor: NSImageView! @IBOutlet weak var fontSizeComboBox: NSComboBox! @IBOutlet weak var fontStyleTComboBox: NSComboBox! @IBOutlet weak var fontTopConstraint: NSLayoutConstraint! @IBOutlet weak var alignTitleLabel: NSTextField! @IBOutlet weak var areasLeftButton: NSButton! @IBOutlet weak var areasVerticalCenterButton: NSButton! @IBOutlet weak var areasHorzontalButton: NSButton! @IBOutlet weak var areasVerticalButton: NSButton! @IBOutlet weak var areasBotoomButton: NSButton! @IBOutlet weak var areasHorizontalCenterButton: NSButton! @IBOutlet weak var areasTopButton: NSButton! @IBOutlet weak var areasRightButton: NSButton! var textsAreas : [CPDFEditTextArea] = [] var listView : CPDFListView! var fonts = NSMutableArray() var currentColor : NSColor = NSColor.black var alignment : NSTextAlignment = .left override func viewDidLoad() { super.viewDidLoad() self.currentFontColor.wantsLayer = true self.currentFontColor.layer?.cornerRadius = 9 self.currentFontColor.layer?.masksToBounds = true self.currentFontColor.image = self.swatchWithColor(color: NSColor.black, size: NSSize(width: 18, height: 18)) self.preImageView.wantsLayer = true self.preImageView.layer?.backgroundColor = NSColor.white.cgColor self.preViewBox.isHidden = true self.preViewHeight.constant = 0 self.propertyTitle.stringValue = NSLocalizedString("Text", comment: "") self.fontTitleLabel.stringValue = NSLocalizedString("Font", comment: "") self.alignTitleLabel.stringValue = NSLocalizedString("Align", comment: "") self.fontReload() self.setDefaultProperty() self.formAearsAlignIcon() self.imageWithTextSet() } func refreshSelectAreaProperty() { if self.listView.editingAreas()?.count == 1 { let areas = self.listView.editingAreas().first if areas is CPDFEditTextArea { self.fontSizeComboBox.stringValue = "\(self.listView.editingSelectionFontSize())" let font = self.listView.editingSelectionFontName() let result : [String] = font?.components(separatedBy: " - ") ?? [] var fontName = "" var fontStyle = "" if result.count == 1 { fontName = result[0] } if result.count == 2 { fontStyle = result[1] } self.fontStyleComboBox.stringValue = fontName self.fontStyleTComboBox.stringValue = fontStyle self.currentColor = self.listView.editingSelectionFontColor() ?? NSColor.black NSColorPanel.shared.color = self.currentColor self.currentFontColor.image = self.swatchWithColor(color: self.currentColor, size: NSSize(width: 18, height: 18)) self.alignment = self.listView.editingSelectionAlignment() self.updateAlignIcon() self.imageWithTextSet() } } } func reloadData() { self.formAearsAlignIcon() textsAreas = [] if self.listView.editingAreas()?.count ?? 0 < 1 { return } let areas = self.listView.editingAreas() for i in 0 ... areas!.count-1 { if areas![i] is CPDFEditTextArea { textsAreas.append(areas![i] as! CPDFEditTextArea) } } if textsAreas.count == 1 { self.headerBox.isHidden = false self.fontTitleLabel.isHidden = false self.fontTopConstraint.constant = 5; } else if textsAreas.count > 1 { self.headerBox.isHidden = true self.fontTitleLabel.isHidden = true self.fontTopConstraint.constant = -135; } self.refreshSelectAreaProperty() } func setDefaultProperty() { let fontName : String = UserDefaults.standard.object(forKey: CEditPDFTextDefaultFontName) as? String ?? "Helvetica" let fontStyle : String = UserDefaults.standard.object(forKey: CEditPDFTextDefaultFontStyle) as? String ?? "Bold" let fontSize : String = UserDefaults.standard.object(forKey: CEditPDFTextDefaultFontSize) as? String ?? "12" let fontColor : NSColor = UserDefaults.standard.pdfListViewColor(forKey: CEditPDFTextDefaultFontColor) ?? NSColor.black let fontAlign : String = UserDefaults.standard.object(forKey: CEditPDFTextDefaultFontAlign) as? String ?? "2" self.fontStyleComboBox.stringValue = fontName self.fontStyleTComboBox.stringValue = fontStyle self.fontSizeComboBox.stringValue = fontSize self.alignment = NSTextAlignment.init(rawValue: Int(fontAlign)!)! self.currentColor = fontColor NSColorPanel.shared.color = self.currentColor self.currentFontColor.image = self.swatchWithColor(color: self.currentColor, size: NSSize(width: 18, height: 18)) self.updateAlignIcon() } func fontReload() { self.fonts = NSFont.supportFonts() var selectedIndex = 0 for dic in fonts { let fontName = (dic as! NSDictionary).allKeys.first let font = NSFont(name: fontName as! String, size: 12.0) let attrited : [NSAttributedString.Key : Any] = [NSAttributedString.Key.font:font!] let string : NSAttributedString = NSAttributedString(string: fontName as! String, attributes: attrited) self.fontStyleComboBox.addItem(withObjectValue:string) } self.fontStyleComboBox.selectItem(at: selectedIndex) self.fontStyleComboBox.font = NSFont.systemFont(ofSize: 12) self.fontStyleTComboBox.font = NSFont.systemFont(ofSize: 12) self.fontSizeComboBox.removeAllItems() let fontsize = ["6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "24", "36", "48", "72", "96", "144", "288"] for str in fontsize { self.fontSizeComboBox.addItem(withObjectValue: str) } selectedIndex = 6 self.fontSizeComboBox.selectItem(at: selectedIndex) self.setFontStyleWithFontName(fontName: self.fontStyleComboBox.stringValue, currentStyle: "") } func setFontStyleWithFontName(fontName:String, currentStyle style:String) -> NSInteger { let selctIndex = 0 for i in 0 ... self.fonts.count-1 { let dic : NSDictionary = self.fonts.object(at: i) as! NSDictionary let familyString = dic.allKeys.first as! String if fontName == familyString { let styles : NSArray = dic.object(forKey: fontName) as! NSArray self.fontStyleTComboBox.removeAllItems() for j in 0 ... styles.count-1 { let style = styles.object(at: j) as! String let attributeFontDescriptor = NSFontDescriptor.init(fontAttributes: [NSFontDescriptor.AttributeName.family : fontName,NSFontDescriptor.AttributeName.face : style]) let font = NSFont.init(descriptor: attributeFontDescriptor, size: 12) let attrited : [NSAttributedString.Key : Any] = [NSAttributedString.Key.font:font!] let string : NSAttributedString = NSAttributedString(string: style, attributes: attrited) self.fontStyleTComboBox.addItem(withObjectValue:string) } break } } self.fontStyleTComboBox.selectItem(at: 0) return selctIndex } //MARK: Button Action @IBAction func fontColorAction(_ sender: Any) { let color = self.listView.editingSelectionFontColor() let panel = NSColorPanel.shared panel.setTarget(self) panel.setAction(#selector(fontColorChangeAction)) panel.orderFront(nil) panel.showsAlpha = false panel.color = color ?? NSColor.black } @IBAction func fontNameAction(_ sender: Any) { self.setFontStyleWithFontName(fontName: self.fontStyleComboBox.stringValue, currentStyle: "") if self.listView.editingAreas()?.count ?? 0 > 0 { self.listView.setEditingSelectionFontName("\(self.fontStyleComboBox.stringValue)-\(self.fontStyleTComboBox.stringValue)") } else { UserDefaults.standard.set(self.fontStyleComboBox.stringValue, forKey: CEditPDFTextDefaultFontName) UserDefaults.standard.set(self.fontStyleTComboBox.stringValue, forKey: CEditPDFTextDefaultFontStyle) } self.imageWithTextSet() } @IBAction func fontNameStyleAction(_ sender: Any) { if self.listView.editingAreas()?.count ?? 0 > 0 { self.listView.setEditingSelectionFontName("\(self.fontStyleComboBox.stringValue)-\(self.fontStyleTComboBox.stringValue)") } else { UserDefaults.standard.set(self.fontStyleComboBox.stringValue, forKey: CEditPDFTextDefaultFontName) UserDefaults.standard.set(self.fontStyleTComboBox.stringValue, forKey: CEditPDFTextDefaultFontStyle) } self.imageWithTextSet() } @IBAction func fontSizeAction(_ sender: Any) { let size : String = self.fontSizeComboBox.objectValueOfSelectedItem as? String ?? "12" if self.listView.editingAreas()?.count ?? 0 > 0 { self.listView.setEditingSelectionFontSize(CGFloat(Int(size)!)) } else { UserDefaults.standard.set(self.fontSizeComboBox.stringValue, forKey: CEditPDFTextDefaultFontSize) } self.imageWithTextSet() } @objc func fontColorChangeAction() { self.currentColor = NSColorPanel.shared.color self.currentFontColor.image = self.swatchWithColor(color: NSColorPanel.shared.color, size: NSSize(width: 18, height: 18)) if self.listView.editingAreas()?.count ?? 0 > 0 { self.listView.setEditingSelectionFontColor(NSColorPanel.shared.color) } else { UserDefaults.standard.setPDFListViewColor(self.currentColor, forKey: CEditPDFTextDefaultFontColor) } self.imageWithTextSet() } @IBAction func aglinSegmentedAction(_ sender: NSButton) { if sender.tag == 0 { self.alignment = .left } else if sender.tag == 1 { self.alignment = .center } else { self.alignment = .right } self.updateAlignIcon() if self.listView.editingAreas()?.count ?? 0 > 0 { self.listView.setCurrentSelectionAlignment(self.alignment) } else { UserDefaults.standard.set("\(self.alignment.rawValue)", forKey: CEditPDFTextDefaultFontAlign) } self.imageWithTextSet() } @IBAction func areasAlignStyleAction(_ sender: NSButton) { self.formAearsAlignMangent(stype: CPDFActiveAreasAlignType.init(rawValue: sender.tag) ?? .Left) } override func mouseDown(with event: NSEvent) { } //MARK: ToolAction private func swatchWithColor(color:NSColor,size:NSSize) -> NSImage { let image = NSImage(size: size) image.lockFocus() color.drawSwatch(in: NSRect(x: 0, y: 0, width: size.width, height: size.height)) image.unlockFocus() return image } private func imageWithTextSet() { var string = NSLocalizedString("example", comment: "") let style = NSMutableParagraphStyle() style.alignment = self.alignment if self.listView.editingAreas()?.count == 1 { let areas = self.listView.editingAreas().first if areas is CPDFEditTextArea { string = self.listView.editingSelectionString() ?? NSLocalizedString("example", comment: "") style.alignment = self.listView.editingSelectionAlignment() } } var attributeFontDescriptor = NSFontDescriptor.init(fontAttributes: [NSFontDescriptor.AttributeName.family : self.fontStyleComboBox.stringValue,NSFontDescriptor.AttributeName.face : self.fontStyleTComboBox.stringValue]) var font = NSFont.init(descriptor: attributeFontDescriptor, size: CGFloat(Float(self.fontSizeComboBox.stringValue)!)) var red : CGFloat = 0.0 var green : CGFloat = 0.0 var blue : CGFloat = 0.0 var alpha : CGFloat = 0.0 var color : NSColor = NSColor.white if self.currentColor != nil { self.currentColor.usingColorSpaceName(NSColorSpaceName.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &alpha) color = NSColor(red: red, green: green, blue: blue, alpha: alpha) } else { color = NSColor(white: 1.0, alpha: 1.0) } if font == nil { self.fontStyleComboBox.stringValue = "" self.fontStyleTComboBox.stringValue = "" attributeFontDescriptor = NSFontDescriptor.init(fontAttributes: [NSFontDescriptor.AttributeName.family : self.fontStyleComboBox.menu?.item(at: 0)?.title ?? "Helvetica",NSFontDescriptor.AttributeName.face : self.fontStyleTComboBox.menu?.item(at: 0)?.title ?? "Bold"]) font = NSFont.init(descriptor: attributeFontDescriptor, size: CGFloat(Float(self.fontSizeComboBox.stringValue)!)) } let attributes = [NSAttributedString.Key.font:font,NSAttributedString.Key.foregroundColor:color,NSAttributedString.Key.paragraphStyle:style] let size = string.size(withAttributes:attributes as [NSAttributedString.Key : Any]) let image = NSImage(size: NSSize(width: self.preImageView.frame.size.width, height: size.height)) image.lockFocus() NSGraphicsContext.current?.imageInterpolation = .high NSString(string: string).draw(in: NSRect(x: 0, y: 0, width: self.preImageView.frame.size.width, height: image.size.height), withAttributes: attributes) NSGraphicsContext.current?.imageInterpolation = .default image.unlockFocus() self.preImageView.image = image } func updateAlignIcon() { if(self.alignment == .left) { self.alignLeftButton.image = NSImage(named: "KMImageNameEditPDFAlignLeftSelect") self.alignCenterButton.image = NSImage(named: "KMImageNameEditPDFAlignCenter") self.alignRightButton.image = NSImage(named: "KMImageNameEditPDFAlignRight") }else if(self.alignment == .center) { self.alignCenterButton.image = NSImage(named: "KMImageNameEditPDFAlignCenterSelect") self.alignRightButton.image = NSImage(named: "KMImageNameEditPDFAlignRight") self.alignLeftButton.image = NSImage(named: "KMImageNameEditPDFAlignLeft") } else if(self.alignment == .right) { self.alignCenterButton.image = NSImage(named: "KMImageNameEditPDFAlignCenter") self.alignLeftButton.image = NSImage(named: "KMImageNameEditPDFAlignLeft") self.alignRightButton.image = NSImage(named: "KMImageNameEditPDFAlignRightSelect") } } func formAearsAlignIcon() { let norIcons : [String] = ["KMImageNameEditPDFImage20","KMImageNameEditPDFImage21","KMImageNameEditPDFImage45","KMImageNameEditPDFImage46", "KMImageNameEditPDFImage47","KMImageNameEditPDFImage48","KMImageNameEditPDFImage49","KMImageNameEditPDFImage50"] let selectIcons : [String] = ["KMImageNameEditPDFImage20_1","KMImageNameEditPDFImage21_1","KMImageNameEditPDFImage45_1","KMImageNameEditPDFImage46_1", "KMImageNameEditPDFImage47_1","KMImageNameEditPDFImage48_1","KMImageNameEditPDFImage49_1","KMImageNameEditPDFImage50_1"] let areasButtons : [NSButton] = [self.areasVerticalButton,self.areasHorzontalButton,self.areasLeftButton,self.areasVerticalCenterButton, self.areasRightButton,self.areasTopButton,self.areasHorizontalCenterButton,self.areasBotoomButton] if self.listView.editingAreas()?.count ?? 0 < 2 { for i in 0 ... areasButtons.count-1 { areasButtons[i].image = NSImage(named: norIcons[i]) } } else if self.listView.editingAreas()?.count ?? 0 == 2 { for i in 0 ... areasButtons.count-1 { if i == 0 || i == 1 { areasButtons[i].image = NSImage(named: norIcons[i]) } else { areasButtons[i].image = NSImage(named: selectIcons[i]) } } } else if self.listView.editingAreas()?.count ?? 0 > 2 { for i in 0 ... areasButtons.count-1 { areasButtons[i].image = NSImage(named: selectIcons[i]) } } } func formAearsAlignMangent(stype:CPDFActiveAreasAlignType) { if self.listView.editingAreas().count < 2 { return } var zeroRect = NSRect.null var highestRect = NSZeroRect var widthestRect = NSZeroRect let fristArea : CPDFEditArea = self.listView.editingAreas().first as! CPDFEditArea var leftestRect = fristArea.bounds var rightestRect = fristArea.bounds var topestRect = fristArea.bounds var bottomestRect = fristArea.bounds var leftestArea : CPDFEditArea = fristArea var rightestArea : CPDFEditArea = fristArea var topestArea : CPDFEditArea = fristArea var bottomestArea : CPDFEditArea = fristArea var totalWidth = 0.0 var totalHeight = 0.0 for i in 0 ... self.listView.editingAreas().count-1 { let area : CPDFEditArea = self.listView.editingAreas()[i] as! CPDFEditArea zeroRect = zeroRect.union(area.bounds) totalWidth = totalWidth + area.bounds.width totalHeight = totalHeight + area.bounds.height if area.bounds.height > highestRect.height { highestRect = area.bounds } if area.bounds.width > widthestRect.width { widthestRect = area.bounds } if leftestRect.minX > area.bounds.minX { leftestRect = area.bounds leftestArea = area } if area.bounds.maxX > rightestRect.maxX { rightestRect = area.bounds rightestArea = area } if area.bounds.maxY > topestRect.maxY { topestRect = area.bounds topestArea = area } if bottomestRect.minY > area.bounds.minY { bottomestRect = area.bounds bottomestArea = area } } if stype == .Left { var newBoundsArray : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.x = zeroRect.origin.x newBoundsArray.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBoundsArray) } else if stype == .Right { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.x = zeroRect.maxX - bounds.size.width newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Top { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.y = zeroRect.maxY - bounds.size.height newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Bottom { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.y = zeroRect.minY newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Horizontally { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.y = highestRect.midY - bounds.height/2 newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .Vertical { var newBounds : [String] = [] for i in 0 ... self.listView.editingAreas().count-1 { let areas = self.listView.editingAreas()[i] as! CPDFEditArea var bounds = areas.bounds bounds.origin.x = widthestRect.midX - bounds.width/2 newBounds.append(NSStringFromRect(bounds)) } self.changeAreasAlign(areas: self.listView.editingAreas(), newBounds: newBounds) } else if stype == .DisHorizontally { let middleGap = zeroRect.width - leftestRect.width - rightestRect.width let otherAreasTotalWidth = totalWidth - leftestRect.width - rightestRect.width let gap = (middleGap - otherAreasTotalWidth)/CGFloat(self.listView.editingAreas().count - 1) var areasCopyArray : [CPDFEditArea] = self.listView.editingAreas() as! [CPDFEditArea] areasCopyArray.sorted(by: { obj1, obj2 in let area1 = obj1 let area2 = obj2 if area1.bounds.origin.x < area2.bounds.origin.x { return true } else { return false } }) if let index = areasCopyArray.firstIndex(of: leftestArea) { areasCopyArray.remove(at: index) } if let index = areasCopyArray.firstIndex(of: rightestArea) { areasCopyArray.remove(at: index) } var newBounds : [String] = [] var leftStartX = leftestRect.maxX + gap for i in 0 ... areasCopyArray.count-1 { let areas = areasCopyArray[i] var bounds = areas.bounds bounds.origin.x = leftStartX newBounds.append(NSStringFromRect(bounds)) leftStartX = leftStartX + bounds.width + gap } self.changeAreasAlign(areas: areasCopyArray, newBounds: newBounds) } else if stype == .DisVertical { let middleGap = zeroRect.height - topestRect.height - bottomestRect.height let otherAreasTotalHeight = totalHeight - topestRect.height - bottomestRect.height let gap = (middleGap - otherAreasTotalHeight)/CGFloat(self.listView.editingAreas().count - 1) var areasCopyArray : [CPDFEditArea] = self.listView.editingAreas() as! [CPDFEditArea] areasCopyArray.sorted(by: { obj1, obj2 in let area1 = obj1 let area2 = obj2 if area1.bounds.origin.x < area2.bounds.origin.x { return true } else { return false } }) if let index = areasCopyArray.firstIndex(of: topestArea) { areasCopyArray.remove(at: index) } if let index = areasCopyArray.firstIndex(of: bottomestArea) { areasCopyArray.remove(at: index) } var newBounds : [String] = [] var bottomStartY = bottomestRect.maxY + gap for i in 0 ... areasCopyArray.count-1 { let areas = areasCopyArray[i] var bounds = areas.bounds bounds.origin.y = bottomStartY newBounds.append(NSStringFromRect(bounds)) bottomStartY = bottomStartY + bounds.height + gap } self.changeAreasAlign(areas: areasCopyArray, newBounds: newBounds) } } private func changeAreasAlign(areas:[Any],newBounds:[String]) { var oldBounds : [String] = [] for i in 0 ... areas.count-1 { let area : CPDFEditArea = areas[i] as! CPDFEditArea oldBounds.append(NSStringFromRect(area.bounds)) self.listView.setBoundsEditArea(area, withBounds: NSRectFromString(newBounds[i])) } self.listView.setNeedsDisplayForVisiblePages() } }