// // KMEditPDFTextPropertyViewController.swift // PDF Reader Pro // // Created by lxy on 2022/12/27. // import Cocoa import KMComponentLibrary class KMEditPDFTextPropertyViewController: NSViewController { @IBOutlet weak var contentView: NSClipView! @IBOutlet weak var backgroundView: NSView! @IBOutlet var fontBGView: NSView! @IBOutlet var fontLabel: NSTextField! @IBOutlet var fontTitleSelect: ComponentSelect! @IBOutlet var fontTitleButton: ComponentButton! @IBOutlet var fontNameSelect: ComponentSelect! @IBOutlet var fontStyleSelect: ComponentSelect! @IBOutlet var fontSizeSelect: ComponentSelect! @IBOutlet var fontStyleGroup: ComponentCSelectorGroup! @IBOutlet var fontAlignmentGroup: ComponentCSelectorGroup! @IBOutlet var colorBGView: NSView! @IBOutlet var colorLabel: NSTextField! @IBOutlet var colorGroup: ComponentCColorGroup! @IBOutlet var colorSlider: ComponentSlider! @IBOutlet var colorOpacitySelect: ComponentSelect! @IBOutlet var alignmentBGView: NSView! private var fontTitleGroup: ComponentGroup? private var alignmentController: KMNAlignmentController? private var familyNames = CPDFFont.familyNames private let fontStyle_boldItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontStyle_bold"), identifier: "fontStyle_bold") private let fontStyle_ItalityItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontStyle_Itality"), identifier: "fontStyle_Itality") private let fontStyle_CenterItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontStyle_Center"), identifier: "fontStyle_Center") private let fontStyle_Underline: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontStyle_Underline"), identifier: "fontStyle_Underline") private let fontAlign_leftItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontAlign_left"), identifier: "fontAlign_left") private let fontAlign_centerItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontAlign_center"), identifier: "fontAlign_center") private let fontAlign_rightItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontAlign_right"), identifier: "fontAlign_right") private let fontAlign_justifyItem: ComponentCSelectorProperty = ComponentCSelectorProperty.init(size: .m, state: .normal, iconImage: NSImage(named: "fontAlign_justify"), identifier: "fontAlign_justify") var pdfView: CPDFListView? private var currentArea: CPDFEditTextArea? //自定义 private var customTextModel: KMEditPDFTextFontModel = KMEditPDFTextFontModel() private var selCustomFontType: KMEditPDFTextFontType = .customize //MARK: - func override func viewDidAppear() { super.viewDidAppear() colorSlider.reloadData() } override func viewDidLoad() { super.viewDidLoad() setupProperty() } func setupProperty() { //Font fontLabel.stringValue = KMLocalizedString("Font") fontLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") fontLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") fontTitleSelect.properties = ComponentSelectProperties(size: .s, state: .normal, text: "") if true { var menuItemArr: [ComponentMenuitemProperty] = [] var ids = [Customize_USERDEFAULTS, H1_USERDEFAULTS, H2_USERDEFAULTS, H3_USERDEFAULTS, B1_USERDEFAULTS, B2_USERDEFAULTS, B3_USERDEFAULTS] var strings = KMEditPDFTextFontTypeWrapper.allValues() for i in 0...strings.count - 1 { let string = strings[i] var id = string if i < ids.count { id = ids[i] } let item = ComponentMenuitemProperty(type: .normal, text: string, identifier: id) menuItemArr.append(item) } fontTitleSelect.updateMenuItemsArr(menuItemArr) } fontTitleSelect.delegate = self fontTitleButton.properties = ComponentButtonProperty(type: .text_gray, size: .s, onlyIcon: true, icon: NSImage(named: "toolbar_more"), keepPressState: false) fontTitleButton.setTarget(self, action: #selector(buttonClicked(_:))) fontNameSelect.properties = ComponentSelectProperties(size: .s, state: .normal, text: "") if true { var menuItemArr: [ComponentMenuitemProperty] = [] for string in familyNames { let item = ComponentMenuitemProperty(type: .normal, text: string, identifier: string) menuItemArr.append(item) } fontNameSelect.updateMenuItemsArr(menuItemArr) } fontNameSelect.delegate = self fontStyleSelect.properties = ComponentSelectProperties(size: .s, state: .normal, text: "") fontStyleSelect.delegate = self fontSizeSelect.properties = ComponentSelectProperties(size: .s, state: .normal, creatable: true, text: "12 pt", textUnit: " pt", regexString: "0123456789") if true { var sizeItemArr: [ComponentMenuitemProperty] = [] for string in KMHeaderFooterManager.getFontSize() { let item = ComponentMenuitemProperty(type: .normal, text: string + " pt", identifier: string) sizeItemArr.append(item) } fontSizeSelect.updateMenuItemsArr(sizeItemArr) } fontSizeSelect.delegate = self if true { let itemArr: [ComponentCSelectorProperty] = [fontStyle_boldItem, fontStyle_ItalityItem] fontStyleGroup.updateItemProperty(itemArr) fontStyleGroup.delegate = self } if true { let itemArr: [ComponentCSelectorProperty] = [fontAlign_leftItem, fontAlign_centerItem, fontAlign_rightItem, fontAlign_justifyItem] fontAlignmentGroup.updateItemProperty(itemArr) fontAlignmentGroup.delegate = self } //Color colorLabel.stringValue = KMLocalizedString("Font") colorLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") colorLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") let colorAProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMAnnotationPropertiesColorManager.manager.edit_Text_Colors[0]) let colorBProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMAnnotationPropertiesColorManager.manager.edit_Text_Colors[1]) let colorCProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMAnnotationPropertiesColorManager.manager.edit_Text_Colors[2]) let colorDProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: false, color: KMAnnotationPropertiesColorManager.manager.edit_Text_Colors[3]) let colorEProperty = ComponentCColorProperty(colorType: .color, state: .normal, isCustom: true, color: KMAnnotationPropertiesColorManager.manager.edit_Text_Colors[4]) colorGroup.setUpWithColorPropertys([colorAProperty, colorBProperty, colorCProperty, colorDProperty], customItemProperty: colorEProperty) colorGroup.delegate = self colorSlider.properties = ComponentSliderProperty(size: .m, percent: 1) colorSlider.delegate = self colorOpacitySelect.properties = ComponentSelectProperties(size: .s, state: .normal, creatable: true, text: "100%", textUnit: "%", regexString: "0123456789%") if true { var opacityItems: [ComponentMenuitemProperty] = [] for string in ["25%", "50%", "75%", "100%"] { let item = ComponentMenuitemProperty(type: .normal, text: string) opacityItems.append(item) } colorOpacitySelect.updateMenuItemsArr(opacityItems) } colorOpacitySelect.delegate = self if alignmentController == nil { alignmentController = KMNAlignmentController.init() } alignmentController?.view.frame = alignmentBGView.bounds alignmentController?.view.autoresizingMask = [.width, .height] alignmentController?.delegate = self alignmentBGView.addSubview(alignmentController!.view) } //文字块变化时调用 func currentAreaChanged() { fontTitleSelect.selectItemAtIndex(0) fontTitleButton.properties.isDisabled = true fontTitleButton.reloadData() selCustomFontType = .customize } func reloadData() { let areas = pdfView?.km_editingTextAreas() ?? [] if areas.count == 0 { if let _ = currentArea { currentArea = nil currentAreaChanged() } } else if areas.count == 1 { if let area = areas.first, currentArea != area { currentArea = area currentAreaChanged() } alignmentBGView.isHidden = true } else if areas.count > 1 { alignmentBGView.isHidden = false if areas.count == 2 { alignmentController?.updateMulti(false) } else { alignmentController?.updateMulti(true) } if let area = areas.first, currentArea != area { currentArea = area currentAreaChanged() } } var fontName: String? var fontStyle: String? var fontSize: CGFloat? var isBold: Bool = false var isItality: Bool = false var alignment: NSTextAlignment? var color: NSColor? var opacity: CGFloat? if let currentArea = self.currentArea { //Font if let value = pdfView?.editingSelectionCFont(with: currentArea)?.familyName { fontName = value if let value = pdfView?.editingSelectionCFont(with: currentArea)?.styleName { fontStyle = value.count > 0 ? value : "Regular" } } if let value = pdfView?.editingSelectionFontSize(byRangeEdit: currentArea) { fontSize = value } isBold = pdfView?.isBoldCurrentSelection(byRangeEdit: currentArea) ?? false isItality = pdfView?.isItalicCurrentSelection(byRangeEdit: currentArea) ?? false if let value = pdfView?.currentSelectionAlignment(byRangeEdit: currentArea) { alignment = value } //Color if let colors = pdfView?.km_editTextAreasFontColors([currentArea]) { color = colors.first } if let opacitys = pdfView?.km_editAreasOpacitys([currentArea]) { if var value = opacitys.first { value = min(1, value) value = max(0, value) opacity = value } } } if areas.count > 1 { if CPDFEditArea.isMultiFontFamilyNames(areas, inPDFView: pdfView) { fontName = nil } if CPDFEditArea.isMultiFontStyles(areas, inPDFView: pdfView) { fontStyle = nil } if CPDFEditArea.isMultiFontSizes(areas, inPDFView: pdfView) { fontSize = nil } if CPDFEditArea.isMultiFontBolds(areas, inPDFView: pdfView) { isBold = false } if CPDFEditArea.isMultiFontItalitys(areas, inPDFView: pdfView) { isItality = false } if CPDFEditArea.isMultiFontAlignment(areas, inPDFView: pdfView) { alignment = nil } if CPDFEditArea.isMultiColors(areas, inPDFView: pdfView) { color = nil } if CPDFEditArea.isMultiOpacity(areas, inPDFView: pdfView) { opacity = nil } } //Font if let value = fontName { fontNameSelect.properties.text = value var styles: [String] = CPDFFont.fontNames(forFamilyName: value) if styles.isEmpty == true { styles.append("Regular") } var menuItemArr: [ComponentMenuitemProperty] = [] for string in styles { let item = ComponentMenuitemProperty(type: .normal, text: string, identifier: string) menuItemArr.append(item) } fontStyleSelect.updateMenuItemsArr(menuItemArr) } else { fontNameSelect.properties.text = "-" fontStyleSelect.updateMenuItemsArr([]) } fontNameSelect.reloadData() if let value = fontStyle { fontStyleSelect.properties.text = value } else { fontStyleSelect.properties.text = "Regular" fontStyleSelect.updateMenuItemsArr([]) } fontStyleSelect.reloadData() if let value = fontSize { fontSizeSelect.properties.text = String(format: "%.0f", value) } else { fontSizeSelect.properties.text = "-" } fontSizeSelect.reloadData() fontStyle_boldItem.state = isBold ? .pressed : .normal fontStyle_ItalityItem.state = isItality ? .pressed : .normal fontStyle_CenterItem.state = .normal fontStyle_Underline.state = .normal fontStyleGroup.reloadData() fontAlign_leftItem.state = .normal fontAlign_centerItem.state = .normal fontAlign_rightItem.state = .normal fontAlign_justifyItem.state = .normal if let value = alignment { if value == .left { fontAlign_leftItem.state = .pressed } else if value == .center { fontAlign_centerItem.state = .pressed } else if value == .right { fontAlign_rightItem.state = .pressed } else if value == .justified { fontAlign_justifyItem.state = .pressed } } fontAlignmentGroup.reloadData() //Color colorGroup.currentColor = color colorGroup.refreshUI() if var value = opacity { value = min(1, value) value = max(0, value) colorOpacitySelect.properties.text = String(format: "%.0f", value*100) colorSlider.properties.percent = value } else { colorSlider.properties.percent = 0 colorOpacitySelect.properties.text = "-" } colorSlider.reloadData() colorOpacitySelect.reloadData() self.checkFontTitleInfo() } func checkFontTitleInfo() { if self.fontTitleSelect.indexOfSelect() == 0 { return } var type: KMEditPDFTextFontType = .customize if self.fontTitleSelect.indexOfSelect() == 1 { type = .h1 } else if self.fontTitleSelect.indexOfSelect() == 2 { type = .h2 } else if self.fontTitleSelect.indexOfSelect() == 3 { type = .h3 } else if self.fontTitleSelect.indexOfSelect() == 4 { type = .b1 } else if self.fontTitleSelect.indexOfSelect() == 5 { type = .b2 } else if self.fontTitleSelect.indexOfSelect() == 6 { type = .b3 } if type == .customize { return } let fontName = fontNameSelect.properties.text ?? "" let fontStyle = fontStyleSelect.properties.text ?? "" var fontSize = 12.0 let bold = fontStyle_boldItem.state == .pressed let italic = fontStyle_ItalityItem.state == .pressed var alignment: NSTextAlignment = .left if fontAlign_centerItem.state == .pressed { alignment = .center } else if fontAlign_rightItem.state == .pressed { alignment = .right } else if fontAlign_justifyItem.state == .pressed { alignment = .justified } if let text = fontSizeSelect.properties.text, let textUnit = fontSizeSelect.properties.textUnit { let result = text.stringByDeleteCharString(textUnit) fontSize = result.stringToCGFloat() } let isChanged = KMEditPDFTextManager.manager.isModelChanged(type: type, fontName: fontName, fontStyle: fontStyle, fontSize: fontSize, bold: bold, italic: italic, alignment: alignment) var fontTitleText = fontTitleSelect.properties.text ?? "" if isChanged { if fontTitleText.hasPrefix("* ") == false { fontTitleText = "* " + fontTitleText } } else { if fontTitleText.hasPrefix("* ") == true { fontTitleText = fontTitleText.substring(form: 2) } } fontTitleSelect.properties.text = fontTitleText fontTitleSelect.reloadData() } func updateAreaInfoWithCustomType(type: KMEditPDFTextFontType) { var selModel: KMEditPDFTextFontModel? if type != .customize { selModel = KMEditPDFTextManager.manager.fetchUserDefaultData(type: type) } if let model = selModel { let fontName = model.fontName let fontStyle = model.fontStyle let fontSize = model.fontSize let bold = model.bold let italic = model.italic let alignment = model.alignment let font = CPDFFont(familyName: fontName, fontStyle: fontStyle) pdfView?.setEditingTextarea_font(font: font) pdfView?.setEditingTextarea_FontSize(size: fontSize) pdfView?.setEditingTextarea(isBold: bold) pdfView?.setEditingTextarea(isItalic: italic) pdfView?.setEditingTextarea_Alignment(align: alignment) } } //MARK: - Action @objc func buttonClicked(_ sender: ComponentButton) { if sender == fontTitleButton { var viewHeight: CGFloat = 8 var menuItemArr: [ComponentMenuitemProperty] = [] for i in ["Redefine", "Reset"] { let properties_Menuitem: ComponentMenuitemProperty = ComponentMenuitemProperty(multipleSelect: false, itemSelected: false, isDisabled: false, keyEquivalent: nil, text: KMLocalizedString(i), identifier: i) menuItemArr.append(properties_Menuitem) viewHeight += 36 } if fontTitleGroup == nil { fontTitleGroup = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) } fontTitleGroup?.groupDelegate = self fontTitleGroup?.frame = CGRectMake(310, 0, 140, viewHeight) fontTitleGroup?.updateGroupInfo(menuItemArr) var point = fontTitleButton.superview?.convert(fontTitleButton.frame.origin, to: nil) ?? CGPointZero point.y -= viewHeight fontTitleGroup?.showWithPoint(point, relativeTo: fontTitleButton) } } override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) view.window?.makeFirstResponder(nil) } } //MARK: - ComponentSelectDelegate extension KMEditPDFTextPropertyViewController: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { if var result = menuItemProperty?.text { if let textUnit = view?.properties.textUnit { result = result.stringByDeleteCharString(textUnit) } if view == fontTitleSelect { if menuItemProperty?.identifier == Customize_USERDEFAULTS { fontTitleButton.properties.isDisabled = true selCustomFontType = .customize } else { fontTitleButton.properties.isDisabled = false var type: KMEditPDFTextFontType = .customize if menuItemProperty?.identifier == H1_USERDEFAULTS { type = .h1 } else if menuItemProperty?.identifier == H2_USERDEFAULTS { type = .h2 } else if menuItemProperty?.identifier == H3_USERDEFAULTS { type = .h3 } else if menuItemProperty?.identifier == B1_USERDEFAULTS { type = .b1 } else if menuItemProperty?.identifier == B2_USERDEFAULTS { type = .b2 } else if menuItemProperty?.identifier == B3_USERDEFAULTS { type = .b3 } selCustomFontType = type self.updateAreaInfoWithCustomType(type: type) } fontTitleButton.reloadData() } else if view == fontNameSelect { var styleName = "Regular" let styleNames = CPDFFont.fontNames(forFamilyName: result) if let first = styleNames.first { styleName = first } pdfView?.setEditingTextarea_font(font: CPDFFont(familyName: result, fontStyle: styleName)) } else if view == fontStyleSelect { let fontName = fontNameSelect.properties.text ?? "Helvetica" pdfView?.setEditingTextarea_font(font: CPDFFont.init(familyName: fontName, fontStyle: result)) } else if view == fontSizeSelect { if let text = menuItemProperty?.text { let fontSize = result.stringToCGFloat() pdfView?.setEditingTextarea_FontSize(size: fontSize) } } else if view == colorOpacitySelect { let opacity = max(0, min(1, result.stringToCGFloat()/100)) pdfView?.setEditingAreasOpacity(opacity) } } reloadData() } func componentSelectTextDidEndEditing(_ view: ComponentSelect) { if var result = view.properties.text { if let textUnit = view.properties.textUnit { result = result.stringByDeleteCharString(textUnit) } if view == fontSizeSelect { let size = result.stringToCGFloat() let fontSize = min(size, 100) pdfView?.setEditingTextarea_FontSize(size: fontSize) } else if view == colorOpacitySelect { let opacity = max(0, min(1, result.stringToCGFloat()/100)) pdfView?.setEditingAreasOpacity(opacity) } } reloadData() } } //MARK: - ComponentCColorDelegate extension KMEditPDFTextPropertyViewController: ComponentCColorDelegate { func componentCColorDidChooseColor(_ view: NSView, _ color: NSColor?) { if view == colorGroup { pdfView?.changeEditingTextarea_Color(color: color) } } } //MARK: - ComponentSliderDelegate extension KMEditPDFTextPropertyViewController: ComponentSliderDelegate { func componentSliderDidUpdate(_ view: ComponentSlider) { let percent = view.properties.percent self.pdfView?.setEditingAreasOpacity(percent) reloadData() } } //MARK: - ComponentCSelectorGroupDelegate extension KMEditPDFTextPropertyViewController: ComponentCSelectorGroupDelegate { func componentCSelectorGroupDidChoose(_ view: ComponentCSelectorGroup, _ item: ComponentCSelectorItem) { if view == fontStyleGroup { if item.properties.identifier == "fontStyle_bold" { pdfView?.setEditingTextarea_Bold() } else if item.properties.identifier == "fontStyle_Itality" { pdfView?.setEditingTextarea_Italic() } else if item.properties.identifier == "fontStyle_Center" { } else if item.properties.identifier == "fontStyle_Underline" { } } else if view == fontAlignmentGroup { if item.properties.identifier == "fontAlign_left" { pdfView?.setEditingTextarea_Alignment(align: .left) } else if item.properties.identifier == "fontAlign_center" { pdfView?.setEditingTextarea_Alignment(align: .center) } else if item.properties.identifier == "fontAlign_right" { pdfView?.setEditingTextarea_Alignment(align: .right) } else if item.properties.identifier == "fontAlign_justify" { pdfView?.setEditingTextarea_Alignment(align: .justified) } } reloadData() } } //MARK: - KMNAlignmentControllerDelegate extension KMEditPDFTextPropertyViewController: KMNAlignmentControllerDelegate { func alignmentControllerDidClick(_ controller: KMNAlignmentController, _ alignmentType: KMPDFActiveFormsAlignType) { pdfView?.changeEditingAreas(alignmentType) } } //MARK: - ComponentGroupDelegate extension KMEditPDFTextPropertyViewController: ComponentGroupDelegate { func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) { if menuItemProperty?.identifier == "Redefine" { self.redefineCustomFontType() } else if menuItemProperty?.identifier == "Reset" { if selCustomFontType != .customize { KMEditPDFTextManager.manager.resetTextPresupposition(type: selCustomFontType) self.updateAreaInfoWithCustomType(type: selCustomFontType) } } reloadData() } func redefineCustomFontType() { if selCustomFontType == .customize { return } let fontName = fontNameSelect.properties.text ?? "" let fontStyle = fontStyleSelect.properties.text ?? "" var fontSize = 12.0 let bold = fontStyle_boldItem.state == .pressed let italic = fontStyle_ItalityItem.state == .pressed var alignment: NSTextAlignment = .left if fontAlign_centerItem.state == .pressed { alignment = .center } else if fontAlign_rightItem.state == .pressed { alignment = .right } else if fontAlign_justifyItem.state == .pressed { alignment = .justified } if let text = fontSizeSelect.properties.text, let textUnit = fontSizeSelect.properties.textUnit { let result = text.stringByDeleteCharString(textUnit) fontSize = result.stringToCGFloat() } KMEditPDFTextManager.manager.reDefineTextPresupposition(type: selCustomFontType, fontName: fontName, fontStyle: fontStyle, fontSize: fontSize, bold: bold, italic: italic, alignment: alignment) } }