// // KMGeneralAnnotationViewController.swift // PDF Reader Pro // // Created by wanjun on 2023/12/1. // import Cocoa /** NSString *SKNFreeTextString = @"FreeText"; NSString *SKNTextString = @"Text"; NSString *SKNNoteString = @"Note"; NSString *SKNCircleString = @"Circle"; NSString *SKNSquareString = @"Square"; NSString *SKNMarkUpString = @"MarkUp"; NSString *SKNHighlightString = @"Highlight"; NSString *SKNUnderlineString = @"Underline"; NSString *SKNStrikeOutString = @"StrikeOut"; NSString *SKNLineString = @"Line"; NSString *SKNInkString = @"Ink"; NSString *SKNPDFAnnotationTypeKey = @"type"; NSString *SKNPDFAnnotationBoundsKey = @"bounds"; NSString *SKNPDFAnnotationPageKey = @"page"; NSString *SKNPDFAnnotationPageIndexKey = @"pageIndex"; NSString *SKNPDFAnnotationContentsKey = @"contents"; NSString *SKNPDFAnnotationStringKey = @"string"; NSString *SKNPDFAnnotationColorKey = @"color"; NSString *SKNPDFAnnotationBorderKey = @"border"; NSString *SKNPDFAnnotationLineWidthKey = @"lineWidth"; NSString *SKNPDFAnnotationBorderStyleKey = @"borderStyle"; NSString *SKNPDFAnnotationDashPatternKey = @"dashPattern"; NSString *SKNPDFAnnotationModificationDateKey = @"modificationDate"; NSString *SKNPDFAnnotationUserNameKey = @"userName"; NSString *SKNPDFAnnotationInteriorColorKey = @"interiorColor"; NSString *SKNPDFAnnotationStartLineStyleKey = @"startLineStyle"; NSString *SKNPDFAnnotationEndLineStyleKey = @"endLineStyle"; NSString *SKNPDFAnnotationStartPointKey = @"startPoint"; NSString *SKNPDFAnnotationEndPointKey = @"endPoint"; NSString *SKNPDFAnnotationFontKey = @"font"; NSString *SKNPDFAnnotationFontColorKey = @"fontColor"; NSString *SKNPDFAnnotationFontNameKey = @"fontName"; NSString *SKNPDFAnnotationFontSizeKey = @"fontSize"; NSString *SKNPDFAnnotationAlignmentKey = @"alignment"; NSString *SKNPDFAnnotationRotationKey = @"rotation"; NSString *SKNPDFAnnotationQuadrilateralPointsKey = @"quadrilateralPoints"; NSString *SKNPDFAnnotationIconTypeKey = @"iconType"; NSString *SKNPDFAnnotationPointListsKey = @"pointLists"; */ enum KMActiveAnnotationType: UInt { case highlight = 0 case strikeOut case underline case inkAndLine case text case squareAndCircle case freeText case selfSignFreeText } enum KMFreeTextAnnotationAlignmentType: UInt { case left = 0 case center case right } enum KMRefreshType: UInt { case none = 0 case color case opacity } let KMColorPickerViewHeight: CGFloat = 64 @objcMembers class KMGeneralAnnotationViewController: NSViewController, NSTextViewDelegate { var _annotations: [CPDFAnnotation]? var subType: KMSelfSignAnnotationFreeTextSubType = .none var _activeAnnotationType: KMActiveAnnotationType = .highlight var pdfView: CPDFListView? var annotationModel: CPDFAnnotationModel? { didSet { self.initAnnotationMode() } } // var annotationCallback: ((CPDFAnnotation) -> Void)? @IBOutlet private weak var imageBox: NSBox! @IBOutlet private weak var imageBoxLayoutConstraint: NSLayoutConstraint! @IBOutlet private weak var textImageBoxView: NSView! @IBOutlet private weak var textImageBox: KMBox! @IBOutlet private weak var textAnnotationImageView: NSImageView! @IBOutlet private weak var textImageBoxButton: NSButton! @IBOutlet private weak var textImageUpDateButton: NSButton! @IBOutlet private weak var generalImageBoxView: NSView! @IBOutlet private weak var generalImageView: NSImageView! @IBOutlet private weak var fontView: NSView! // 字体 @IBOutlet private weak var fontLabel: NSTextField! @IBOutlet private weak var fontButton: NSButton! @IBOutlet private weak var fontPopUpButton: KMPopUpButton! @IBOutlet private weak var fontSizeComboBox: KMComboBox! @IBOutlet private weak var fontStylePopUpButton: KMPopUpButton! @IBOutlet private weak var leftAlignButton: NSButton! @IBOutlet private weak var centerAlignButton: NSButton! @IBOutlet private weak var rightAlignButton: NSButton! @IBOutlet private weak var fontViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var fontViewCorloPV: KMColorPickerView! @IBOutlet private weak var fontViewColorPVConstraint: NSLayoutConstraint! @IBOutlet private weak var rotateView: NSView! // 旋转 @IBOutlet private weak var rotateLabel: NSTextField! @IBOutlet private weak var leftRotateBox: KMBox! @IBOutlet private weak var leftRotateButton: NSButton! @IBOutlet private weak var rightRotateBox: KMBox! @IBOutlet private weak var rightRotateButton: NSButton! @IBOutlet private weak var rotateViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var typeView: NSView! // 类型 @IBOutlet private weak var typeLabel: NSTextField! @IBOutlet private weak var tureTypeButton: NSButton! @IBOutlet private weak var falseTypeButton: NSButton! @IBOutlet private weak var circletypeButton: NSButton! @IBOutlet private weak var lineTypeButton: NSButton! @IBOutlet private weak var dotTypeButton: NSButton! @IBOutlet private weak var typeViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var dateView: NSView! // 日期 @IBOutlet private weak var dateLabel: NSTextField! @IBOutlet private weak var datePopUpButton: KMPopUpButton! @IBOutlet private weak var dateCheckButton: NSButton! @IBOutlet private weak var dateViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var iconView: NSView! // 图标 @IBOutlet private weak var iconLabel: NSTextField! @IBOutlet private weak var commentBox: NSBox! @IBOutlet private weak var commentButton: NSButton! @IBOutlet private weak var noteBox: NSBox! @IBOutlet private weak var noteButton: NSButton! @IBOutlet private weak var keyBox: NSBox! @IBOutlet private weak var keyButton: NSButton! @IBOutlet private weak var helpBox: NSBox! @IBOutlet private weak var helpButton: NSButton! @IBOutlet private weak var paragraphBox: NSBox! @IBOutlet private weak var paragraphButton: NSButton! @IBOutlet private weak var insertBox: NSBox! @IBOutlet private weak var insertButton: NSButton! @IBOutlet private weak var addParagraphBox: NSBox! @IBOutlet private weak var addParagraphButton: NSButton! @IBOutlet private weak var iconViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var iconButtonHeightConstant: NSLayoutConstraint! @IBOutlet private weak var borderAndLineView: NSView! // 边框 @IBOutlet private weak var borderLabel: NSTextField! @IBOutlet private weak var borderButton: NSButton! @IBOutlet private weak var lineWidthComboBox: KMComboBox! @IBOutlet private weak var lineWidthSlider: NSSlider! @IBOutlet private weak var lineTypeLabel: NSTextField! @IBOutlet private weak var lineStyleButton: KMButton! @IBOutlet private weak var dottedLineStyleButton: KMButton! @IBOutlet private weak var rightArrowStyleButton: KMButton! @IBOutlet private weak var lineStyleBox: NSBox! @IBOutlet private weak var dottedLineStyleBox: NSBox! @IBOutlet private weak var rightArrowStyleBox: NSBox! @IBOutlet private weak var borderViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var fillColorView: NSView! @IBOutlet private weak var fillColorLabel: NSTextField! @IBOutlet private weak var fillColorPickerView: KMColorPickerView! @IBOutlet private weak var fillColorViewTopConstraint: NSLayoutConstraint! @IBOutlet private weak var opacityView: NSView! // 透明度 @IBOutlet private weak var opacityLabel: NSTextField! @IBOutlet private weak var opacitySlider: NSSlider! @IBOutlet private weak var opacityComboBox: KMComboBox! @IBOutlet private weak var opacityViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var noteView: NSView! // 笔记 @IBOutlet private weak var noteViewLabel: NSTextField! @IBOutlet private var noteTextView: NSTextView! @IBOutlet private weak var noteViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var colorView: NSView! // 颜色 @IBOutlet private weak var colorTitleLabel: NSTextField! @IBOutlet private weak var textColorBox: NSBox! @IBOutlet private weak var textColorBoxConstraint: NSLayoutConstraint! @IBOutlet private weak var textColorPickerView: KMColorPickerView! @IBOutlet private weak var borderColorBox: NSBox! @IBOutlet private weak var borderColorPickerView: KMColorPickerView! @IBOutlet private weak var borderColorBoxConstraint: NSLayoutConstraint! @IBOutlet private weak var lineWidthBox: NSBox! @IBOutlet private weak var widthLabel: NSTextField! @IBOutlet private weak var widthComboBox: KMComboBox! @IBOutlet private weak var widthSlider: NSSlider! @IBOutlet private weak var ColorViewTopConstant: NSLayoutConstraint! @IBOutlet private weak var textColorPickerViewConstant: NSLayoutConstraint! var isannotationMode: Bool = false var selectedAlignmentButtonLayer: CALayer? var iconButtonArray: [NSBox] = [] var lineStyleCount: Int = 0 var isTextEdit: Bool = false var fonts: [[String : [String]]]? var annotationAlignment: KMFreeTextAnnotationAlignmentType = .left var noteIcons: [NSImage?] = [nil, nil, nil, nil, nil, nil, nil] private let kDefaultOpacity_: CGFloat = 1.0 private let kDefaultLineWidth_: CGFloat = 2.0 private let kDefaultFontSize_: CGFloat = 11.0 private func makeNoteIcons() { if noteIcons[0] != nil { return } let bounds = CGRect(origin: .zero, size: NSMakeSize(16, 16)) let annotation = CPDFTextAnnotation() annotation.bounds = bounds annotation.color = NSColor.clear let page = CPDFPage() page.setBounds(bounds, for: .mediaBox) page.addAnnotation(annotation) for i in 0..<7 { annotation.setIconType(CPDFTextAnnotationIconType(rawValue: i) ?? .comment) noteIcons[i] = NSImage.bitmapImage(with: NSMakeSize(16, 16), drawingHandler: { rect in page.draw(with: .mediaBox, to: (NSGraphicsContext.current?.cgContext)) }) } } deinit { NotificationCenter.default.removeObserver(self) DistributedNotificationCenter.default().removeObserver(self) if ((annotationModel?.annotation) != nil) && annotationModel?.annotations.count == 1 { let keys = ["contents", "markupText"] for key in keys { annotationModel?.annotation.removeObserver(self, forKeyPath: key) } } textColorPickerView.target = nil textColorPickerView.action = nil borderColorPickerView.target = nil borderColorPickerView.action = nil fillColorPickerView.target = nil fillColorPickerView.action = nil NSColorPanel.shared.setTarget(nil) NSColorPanel.shared.setAction(nil) } // MARK: View Methods override func loadView() { super.loadView() DispatchQueue.main.async { if NSColorPanel.shared.isVisible { NSColorPanel.shared.close() } } isannotationMode = true fonts = (CPDFAnnotationModel.supportFonts() as? [[String : [String]]]) ?? [] imageBox.borderColor = KMAppearance.Interactive.s0Color() imageBox.borderWidth = 1.0 imageBox.fillColor = KMAppearance.Layout.l1Color() textImageBox.fillColor = KMAppearance.Layout.l1Color() fontLabel.stringValue = NSLocalizedString("Fonts", comment: "") fontLabel.textColor = KMAppearance.Layout.h0Color() colorTitleLabel.stringValue = NSLocalizedString("Color", comment: "") colorTitleLabel.textColor = KMAppearance.Layout.h0Color() opacityLabel.stringValue = NSLocalizedString("Opacity", comment: "") opacityLabel.textColor = KMAppearance.Layout.h1Color() noteViewLabel.stringValue = NSLocalizedString("Note", comment: "") noteViewLabel.textColor = KMAppearance.Layout.h0Color() rotateLabel.stringValue = NSLocalizedString("Rotate", comment: "") rotateLabel.textColor = KMAppearance.Layout.h0Color() typeLabel.stringValue = NSLocalizedString("Type", comment: "") typeLabel.textColor = KMAppearance.Layout.h0Color() dateLabel.stringValue = NSLocalizedString("Date", comment: "") dateLabel.textColor = KMAppearance.Layout.h0Color() iconLabel.stringValue = NSLocalizedString("Icon", comment: "") iconLabel.textColor = KMAppearance.Layout.h0Color() borderLabel.stringValue = NSLocalizedString("Line and Border Style", comment: "") borderLabel.textColor = KMAppearance.Layout.h0Color() fillColorLabel.stringValue = NSLocalizedString("Fill", comment: "") fillColorLabel.textColor = KMAppearance.Layout.h0Color() lineStyleCount = 0 if annotationType == .highlight { activeAnnotationType = .highlight } else if annotationType == .strikeOut { activeAnnotationType = .strikeOut } else if annotationType == .underline { activeAnnotationType = .underline } else if annotationType == .ink || annotationType == .line || annotationType == .arrow { activeAnnotationType = .inkAndLine } else if annotationType == .anchored { activeAnnotationType = .text } else if annotationType == .circle || annotationType == .square { borderColorPickerView.isCallColorPanelAction = isannotationMode textColorPickerView.isCallColorPanelAction = isannotationMode activeAnnotationType = .squareAndCircle } else if annotationType == .freeText { if subType == .date { colorTitleLabel.stringValue = NSLocalizedString("Fill Color", comment: "") activeAnnotationType = .selfSignFreeText } else { activeAnnotationType = .freeText } fontViewCorloPV.isCallColorPanelAction = isannotationMode var alignmentType: KMFreeTextAnnotationAlignmentType = .left if annotationModel?.alignment() == .left { alignmentType = .left } else if annotationModel?.alignment() == .center { alignmentType = .center } else if annotationModel?.alignment() == .right { alignmentType = .right } alignmentTypeSelected(alignmentType) } else if annotationType == .signDate { colorTitleLabel.stringValue = NSLocalizedString("Fill Color", comment: "") activeAnnotationType = .selfSignFreeText fontViewCorloPV.isCallColorPanelAction = isannotationMode var alignmentType: KMFreeTextAnnotationAlignmentType = .left if annotationModel?.alignment() == .left { alignmentType = .left } else if annotationModel?.alignment() == .center { alignmentType = .center } else if annotationModel?.alignment() == .right { alignmentType = .right } alignmentTypeSelected(alignmentType) } fillColorPickerView.isCallColorPanelAction = isannotationMode textColorPickerView.isCallColorPanelAction = isannotationMode borderColorPickerView.isCallColorPanelAction = isannotationMode if annotationType == .freeText { fontViewCorloPV.isFreeText = true } else { fontViewCorloPV.isFreeText = false } if annotationType == .ink || annotationType == .line || annotationType == .arrow || annotationType == .square || annotationType == .circle { let lineType = annotationModel?.style() if lineType == .dashed { let lineType = annotationModel?.dashPattern() // if lineType.count == 0 { // let number = NSNumber(value: Float(4)) // annotation.setDashPattern([number]) // // let userDefaults = UserDefaults.standard // if annotationType == .ink { // userDefaults.set(annotationModel?.dashPattern(), forKey: SKInkNoteDashPatternKey) // } else if annotationType == .line { // userDefaults.set(annotationModel?.dashPattern(), forKey: SKLineNoteDashPatternKey) // } else if annotationType == .square { // userDefaults.set(annotationModel?.dashPattern(), forKey: SKSquareNoteDashPatternKey) // } else if annotationType == .circle { // userDefaults.set(annotationModel?.dashPattern(), forKey: SKCircleNoteDashPatternKey) // } else if annotationType == .freeText { // userDefaults.set(annotationModel?.dashPattern(), forKey: CFreeTextNoteDashPatternKey) // } // } } } opacityComboBox.type = .none opacityComboBox.comboxRect = opacityComboBox.bounds lineWidthComboBox.type = .none lineWidthComboBox.comboxRect = lineWidthComboBox.bounds widthComboBox.type = .none widthComboBox.comboxRect = widthComboBox.bounds fontPopUpButton.type = .arrowDown fontSizeComboBox.type = .none fontSizeComboBox.comboxRect = fontSizeComboBox.bounds fontStylePopUpButton.type = .arrowUpDown datePopUpButton.type = .arrowUpDown noteTextView.backgroundColor = KMAppearance.Layout.l1Color() let views: [NSView] = [fontPopUpButton, fontSizeComboBox, fontStylePopUpButton, lineWidthComboBox, opacityComboBox, widthComboBox, datePopUpButton, noteTextView] for view in views { view.wantsLayer = true view.layer?.borderWidth = 1.0 view.layer?.cornerRadius = 1.0 } refreshLineTypeUI() rightArrowStyleButton.isHidden = true rightArrowStyleBox.isHidden = true annotationFontReload() reloadData() updateViewColor() if ((annotationModel?.annotation) != nil) && annotationModel?.annotations.count == 1 { let annotation = annotationModel?.annotation let keys = ["contents", "markupText"] for key in keys { annotation?.addObserver(self, forKeyPath: key, options: [.new, .old], context: nil) } } // NotificationCenter.default.addObserver(self, selector: #selector(alignmentTypeNotification(_:)), name: "KMAnnotationAlignmentTypeNotification1", object: nil) // NotificationCenter.default.addObserver(self, selector: #selector(loadingUIAndLocalization(_:)), name: "KMPreferenceDidChangeNotificationName", object: nil) NotificationCenter.default.addObserver(self, selector: #selector(annotationChangeNotification(_:)), name: NSNotification.Name(rawValue: "CPDFListViewAnnotationsAttributeHasChangeNotification"), object: nil) } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. } override func viewDidAppear() { super.viewDidAppear() let showConvertDetails = KMPropertiesViewPopController.showChangeColorDetails() let fileURL = (self.view.window?.windowController?.document as? NSDocument)?.fileURL if showConvertDetails && (fileURL != nil) { KMPropertiesViewPopController.defaultManager.showChangeColorDetailsView(self.textColorPickerView.firstButton) } DistributedNotificationCenter.default().addObserver(self, selector: #selector(themeChanged(notification:)), name: NSNotification.Name("AppleInterfaceThemeChangedNotification"), object: nil) } func reloadData() { var annotationColor = annotationModel?.color() if annotationType == .signFalse || annotationType == .signTure || annotationType == .signDot || annotationType == .signCircle || annotationType == .signLine { annotationColor = annotationModel?.color() } else if annotationType == .square || annotationType == .circle { annotationColor = annotationModel?.color() } else if annotationType == .freeText || annotationType == .signDate || annotationType == .signText { annotationColor = annotationModel?.interiorColor() } else { annotationColor = annotationModel?.color() } let color = annotationColor ?? NSColor.black // guard let color = annotationColor else { return } var opacity: CGFloat = 1.0 color.usingColorSpaceName(.calibratedRGB)?.getRed(nil, green: nil, blue: nil, alpha: &opacity) if annotationType == .signFalse || annotationType == .signTure || annotationType == .signDot || annotationType == .signCircle || annotationType == .signLine { opacity = (annotationModel?.opacity()) ?? self.kDefaultOpacity_ } else if annotationType == .square || annotationType == .circle { opacity = (annotationModel?.opacity()) ?? self.kDefaultOpacity_ } else if annotationType == .freeText || annotationType == .signDate || annotationType == .signText { opacity = (annotationModel?.interiorOpacity()) ?? self.kDefaultOpacity_ } else { opacity = (annotationModel?.opacity()) ?? self.kDefaultOpacity_ } opacitySlider.floatValue = Float(opacity) opacitySlider.toolTip = "\(Int(opacity * 100))%" opacityComboBox.stringValue = "\(Int(opacity * 100))%" if annotationModel?.annotations != nil { let contextString = annotation.string() ?? "" noteTextView.string = contextString noteTextView.textColor = NSColor.labelColor noteTextView.delegate = self } if annotationType == .freeText { imageBox.contentView = textImageBoxView textAnnotationImageView.image = annotationModel?.annotationImage } else if annotationType == .signText || annotationType == .signDate { imageBox.contentView = generalImageBoxView generalImageView.image = annotationModel?.annotationImage } else { imageBox.contentView = generalImageBoxView generalImageView.image = annotationModel?.annotationImage } if annotationType == .square || annotationType == .circle || annotationType == .line || annotationType == .arrow || annotationType == .ink { if annotationType == .ink { textColorPickerView.setColor(color) } else if annotationType == .square || annotationType == .circle { var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 let modelColor = annotationModel?.interiorColor() ?? .black modelColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) let interiorColor = NSColor(red: red, green: green, blue: blue, alpha: (annotationModel?.interiorOpacity()) ?? self.kDefaultOpacity_) textColorPickerView.setColor(interiorColor) textColorPickerView.isFillColor = true borderColorPickerView.setColor(color) } else if annotationType == .line || annotationType == .arrow { var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 let modelColor = annotationModel?.interiorColor() ?? .black modelColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) let interiorColor = NSColor(red: red, green: green, blue: blue, alpha: (annotationModel?.interiorOpacity()) ?? self.kDefaultOpacity_) textColorPickerView.setColor(interiorColor) textColorPickerView.isFillColor = true borderColorPickerView.setColor(color) } lineWidthSlider.floatValue = Float(annotationModel?.lineWidth() ?? 1.0) lineWidthSlider.toolTip = "\(annotationModel?.lineWidth() ?? 1.0) pt" lineWidthComboBox.stringValue = String(format: "%0.1f pt", (annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) } else if annotationType == .freeText || annotationType == .signText || annotationType == .signDate { if annotationType == .signText || annotationType == .signDate { if subType == .date { dateView.isHidden = false datePopUpButton.removeAllItems() datePopUpButton.addItems(withTitles: KMSelfSignAnnotationFreeText.fetchAllDateString(includeTime: false)) if let data = annotationModel?.dateFormatIndex(), data >= 0 && data < datePopUpButton.numberOfItems { datePopUpButton.selectItem(at: (annotationModel?.dateFormatIndex())!) } else { datePopUpButton.selectItem(at: 0) } dateCheckButton.state = (annotationModel?.includeTime() ?? true) ? NSControl.StateValue.on : NSControl.StateValue.off textColorPickerView.setColor((annotationModel?.color() ?? .black)) } } else { lineWidthSlider.minValue = 0.0 lineWidthSlider.floatValue = Float((annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) lineWidthSlider.toolTip = String(format: "%0.1f pt", (annotationModel?.lineWidth() ?? self.kDefaultLineWidth_)) lineWidthComboBox.stringValue = String(format: "%0.1f pt", (annotationModel?.lineWidth() ?? self.kDefaultLineWidth_)) var alignmentType: KMFreeTextAnnotationAlignmentType = .left if annotationModel?.alignment() == .left { alignmentType = .left } else if annotationModel?.alignment() == .center { alignmentType = .center } else if annotationModel?.alignment() == .right { alignmentType = .right } alignmentTypeSelected(alignmentType) annotationFontReload() fillColorPickerView.color = annotationModel?.color() } fontViewCorloPV.color = annotationModel?.fontColor() fontSizeComboBox.stringValue = String(format: "%.f pt", (annotationModel?.fontSize() ?? self.kDefaultFontSize_)) } else if annotationType == .highlight || annotationType == .strikeOut || annotationType == .underline || annotationType == .anchored { textColorPickerView.setColor(color) } // noteView.isHidden = isannotationMode if annotationType == .signText || annotationType == .signDate { if subType == .date { // noteView.isHidden = true isannotationMode = true } else { // noteView.isHidden = false isannotationMode = false } } else { if annotationModel?.annotations != nil { // noteView.isHidden = annotationModel?.annotation==nil if (annotationModel?.annotations.count)! > 1 { isannotationMode = true } else { isannotationMode = annotationModel?.annotation==nil } } else { if annotationType == .stamp || annotationType == .ink || annotationType == .square || annotationType == .circle || annotationType == .arrow || annotationType == .line || annotationType == .highlight || annotationType == .strikeOut || annotationType == .underline || annotationType == .freeText { // noteView.isHidden = true isannotationMode = true } else { // noteView.isHidden = annotationModel?.annotation==nil isannotationMode = annotationModel?.annotation==nil } } } if isannotationMode { if noteView.isHidden == false { noteView.isHidden = isannotationMode } } else { if noteView.isHidden { noteView.isHidden = isannotationMode } } } // MARK: Set & Get var annotations: [CPDFAnnotation] { set { print(annotations) } get { return annotationModel?.annotations as? [CPDFAnnotation] ?? [] } } var annotation: CPDFAnnotation { get { return annotationModel?.annotation ?? CPDFAnnotation() } } var annotationType: CAnnotationType { get { return (annotationModel?.annotationType as? CAnnotationType) ?? .unkown } } func initAnnotationMode() { if annotationModel?.annotationType == .freeText { let sud = UserDefaults.standard let bounds = NSMakeRect(0, 0, 50, 50) let annotation = CPDFFreeTextAnnotation() // defaults.safe_setColor(annotation.color, forKey: CFreeTextNoteColorKey) // defaults.safe_setColor((annotation as! CPDFFreeTextAnnotation).fontColor, forKey: CFreeTextNoteFontColorKey) // defaults.set((annotation as! CPDFFreeTextAnnotation).alignment.rawValue, forKey: CFreeTextNoteAlignmentKey) // defaults.set((annotation as! CPDFFreeTextAnnotation).fontName(), forKey: CFreeTextNoteFontNameKey) // defaults.set((annotation as! CPDFFreeTextAnnotation).fontSize(), forKey: CFreeTextNoteFontSizeKey) // defaults.set(annotation.lineWidth(), forKey: CFreeTextNoteLineWidthKey) // defaults.set(annotation.borderStyle().rawValue, forKey: CFreeTextNoteLineStyleKey) // defaults.set(annotation.dashPattern(), forKey: CFreeTextNoteDashPatternKey) annotation.bounds = bounds; annotation.color = sud.color(forKey: CFreeTextNoteColorKey) annotation.fontColor = sud.color(forKey: CFreeTextNoteFontColorKey) annotation.alignment = NSTextAlignment(rawValue: sud.integer(forKey: CFreeTextNoteAlignmentKey)) ?? .left let font = sud.font(forNameKey: CFreeTextNoteFontNameKey, sizeKey: CFreeTextNoteFontSizeKey) if (font != nil) { annotation.font = font } annotation.setLineWidth(CGFloat(sud.float(forKey: CFreeTextNoteLineWidthKey))) annotation.setDashPattern(sud.array(forKey: CFreeTextNoteDashPatternKey) ?? []) annotation.setBorderStyle(CPDFBorderStyle(rawValue: sud.integer(forKey: CFreeTextNoteLineStyleKey)) ?? .solid) // annotationModel?.annotations = [annotation] } } func updateannotationMode() { let defaults = UserDefaults.standard if annotationType == .freeText { // if ([annotation isKindOfClass:[SKNPDFAnnotationNote class]]) { // [sud setColor:self.annotation.color forKey:SKNPDFAnnotationColorKey]; // [sud setInteger:self.annotation.iconType forKey:SKAnchoredNoteIconTypeKey]; // } if annotation.isKind(of: CPDFFreeTextAnnotation.self) { defaults.safe_setColor(annotation.color, forKey: CFreeTextNoteColorKey) defaults.safe_setColor((annotation as! CPDFFreeTextAnnotation).fontColor, forKey: CFreeTextNoteFontColorKey) defaults.set((annotation as! CPDFFreeTextAnnotation).alignment.rawValue, forKey: CFreeTextNoteAlignmentKey) defaults.set((annotation as! CPDFFreeTextAnnotation).fontName(), forKey: CFreeTextNoteFontNameKey) defaults.set((annotation as! CPDFFreeTextAnnotation).fontSize(), forKey: CFreeTextNoteFontSizeKey) defaults.set(annotation.lineWidth(), forKey: CFreeTextNoteLineWidthKey) defaults.set(annotation.borderStyle().rawValue, forKey: CFreeTextNoteLineStyleKey) defaults.set(annotation.dashPattern(), forKey: CFreeTextNoteDashPatternKey) } } else if annotationType == .circle { defaults.safe_setColor(annotation.color, forKey: CCircleNoteColorKey) defaults.safe_setColor((annotation as? CPDFCircleAnnotation)?.interiorColor ?? .black, forKey: CCircleNoteInteriorColorKey) defaults.set(annotation.lineWidth(), forKey: CCircleNoteLineWidthKey) if let data = annotation as? CPDFCircleAnnotation { defaults.set(data.borderStyle().rawValue, forKey: CCircleNoteLineStyleKey) defaults.set(data.dashPattern(), forKey: CCircleNoteDashPatternKey) } } else if annotationType == .square { defaults.safe_setColor(annotation.color, forKey: CSquareNoteColorKey) defaults.safe_setColor((annotation as? CPDFSquareAnnotation)?.interiorColor ?? .black, forKey: CSquareNoteInteriorColorKey) defaults.set(annotation.lineWidth(), forKey: CSquareNoteLineWidthKey) if let data = annotation as? CPDFSquareAnnotation { defaults.set(data.borderStyle().rawValue, forKey: CSquareNoteLineStyleKey) defaults.set(data.dashPattern(), forKey: CSquareNoteDashPatternKey) } } else if annotationType == .highlight { defaults.safe_setColor(annotation.color, forKey: CHighlightNoteColorKey) } else if annotationType == .underline { defaults.safe_setColor(annotation.color, forKey: CUnderlineNoteColorKey) } else if annotationType == .strikeOut { defaults.safe_setColor(annotation.color, forKey: CStrikeOutNoteColorKey) } else if annotationType == .line || annotationType == .arrow { defaults.safe_setColor(annotation.color, forKey: CLineNoteColorKey) defaults.set(annotation.lineWidth(), forKey: CLineNoteLineWidthKey) defaults.set(annotation.borderStyle().rawValue, forKey: CLineNoteLineStyleKey) defaults.set(annotation.dashPattern(), forKey: CLineNoteDashPatternKey) if let data = annotation as? CPDFLineAnnotation { defaults.safe_setColor(data.interiorColor, forKey: CLineNoteInteriorColorKey) defaults.set(data.startLineStyle.rawValue, forKey: CLineNoteStartLineStyleKey) defaults.set(data.endLineStyle.rawValue, forKey: CLineNoteEndLineStyleKey) } } else if annotationType == .ink { defaults.safe_setColor(annotation.color, forKey: CInkNoteColorKey) defaults.set(annotation.lineWidth(), forKey: CInkNoteLineWidthKey) defaults.set(annotation.borderStyle().rawValue, forKey: CInkNoteLineStyleKey) defaults.set(annotation.dashPattern(), forKey: CInkNoteDashPatternKey) } else if annotationType == .anchored { // [sud setColor:self.annotation.color forKey:SKNPDFAnnotationColorKey]; // [sud setInteger:self.annotation.iconType forKey:SKAnchoredNoteIconTypeKey]; } } var activeAnnotationType: KMActiveAnnotationType { set { _activeAnnotationType = newValue switch self.activeAnnotationType { case .highlight, .strikeOut, .underline: self.fontView.isHidden = true self.borderAndLineView.isHidden = true self.fillColorView.isHidden = true self.rotateView.isHidden = true self.typeView.isHidden = true self.dateView.isHidden = true self.iconView.isHidden = true self.createMarkupProperties() case .inkAndLine: self.fontView.isHidden = true self.fillColorView.isHidden = true self.rotateView.isHidden = true self.typeView.isHidden = true self.dateView.isHidden = true self.iconView.isHidden = true self.createInkAndLineProperties() case .text: self.fontView.isHidden = true self.borderAndLineView.isHidden = true self.fillColorView.isHidden = true self.rotateView.isHidden = true self.typeView.isHidden = true self.dateView.isHidden = true self.createTextProperties() case .squareAndCircle: self.fontView.isHidden = true self.rotateView.isHidden = true self.typeView.isHidden = true self.dateView.isHidden = true self.iconView.isHidden = true self.fillColorView.isHidden = true self.createSquareAndCircleProperties() case .freeText: self.colorView.isHidden = true self.rotateView.isHidden = true self.typeView.isHidden = true self.dateView.isHidden = true self.iconView.isHidden = true self.createFreeTextProperties() case .selfSignFreeText: self.rotateView.isHidden = true self.borderAndLineView.isHidden = true self.fillColorView.isHidden = true self.typeView.isHidden = true self.iconView.isHidden = true self.createSelfSignFreeTextProperties() default: break } } get { return _activeAnnotationType } } // MARK: private func updateViewColor() { if KMAppearance.isDarkMode() { let darkColor = NSColor(red: 57/255.0, green: 60/255.0, blue: 62/255.0, alpha: 1.0).cgColor let borderColor = NSColor(red: 86/255.0, green: 88/255.0, blue: 90/255.0, alpha: 1.0).cgColor setViewColor(fontPopUpButton, darkColor, borderColor) setViewColor(fontSizeComboBox, darkColor, borderColor) setViewColor(fontStylePopUpButton, darkColor, borderColor) setViewColor(lineWidthComboBox, darkColor, borderColor) setViewColor(opacityComboBox, darkColor, borderColor) setViewColor(datePopUpButton, darkColor, borderColor) setViewColor(widthComboBox, darkColor, borderColor) setViewColor(noteTextView, darkColor, borderColor) } else { let lightColor = NSColor.white.cgColor let borderColor = NSColor(red: 218/255.0, green: 219/255.0, blue: 222/255.0, alpha: 1.0).cgColor setViewColor(fontPopUpButton, lightColor, borderColor) setViewColor(fontSizeComboBox, lightColor, borderColor) setViewColor(fontStylePopUpButton, lightColor, borderColor) setViewColor(lineWidthComboBox, lightColor, borderColor) setViewColor(opacityComboBox, lightColor, borderColor) setViewColor(datePopUpButton, lightColor, borderColor) setViewColor(widthComboBox, lightColor, borderColor) setViewColor(noteTextView, lightColor, borderColor) } } func setViewColor(_ view: NSView, _ backgroundColor: CGColor, _ borderColor: CGColor) { view.layer?.backgroundColor = backgroundColor view.layer?.borderColor = borderColor } func refreshLineTypeUI() { lineStyleBox.borderColor = KMAppearance.Interactive.s0Color() dottedLineStyleBox.borderColor = KMAppearance.Interactive.s0Color() rightArrowStyleBox.borderColor = KMAppearance.Interactive.s0Color() lineStyleBox.fillColor = KMAppearance.Layout.l1Color() dottedLineStyleBox.fillColor = KMAppearance.Layout.l1Color() rightArrowStyleBox.fillColor = KMAppearance.Layout.l1Color() lineStyleBox.borderWidth = 1 dottedLineStyleBox.borderWidth = 1 rightArrowStyleBox.borderWidth = 1 if lineStyleCount == 0 { lineStyleBox.fillColor = KMAppearance.Status.selColor() lineStyleBox.borderWidth = 0.0 } else if lineStyleCount == 1 { dottedLineStyleBox.fillColor = KMAppearance.Status.selColor() dottedLineStyleBox.borderWidth = 0 } else if lineStyleCount == 2 { rightArrowStyleBox.fillColor = KMAppearance.Status.selColor() rightArrowStyleBox.borderWidth = 0 } } func hiddenSubviews() { fontViewTopConstant.constant = fontView.isHidden ? -(fontView.bounds.size.height) - 20 : 10 ColorViewTopConstant.constant = colorView.isHidden ? -(colorView.bounds.size.height) : 10 borderViewTopConstant.constant = borderAndLineView.isHidden ? -(borderAndLineView.bounds.size.height) : 20 opacityViewTopConstant.constant = opacityView.isHidden ? -opacityView.bounds.size.height : 20 rotateViewTopConstant.constant = rotateView.isHidden ? -(rotateView.bounds.size.height) : 20 typeViewTopConstant.constant = typeView.isHidden ? -(typeView.bounds.size.height) : 20 dateViewTopConstant.constant = dateView.isHidden ? -(dateView.bounds.size.height) : 20 iconViewTopConstant.constant = iconView.isHidden ? -(iconView.bounds.size.height) : 20 noteViewTopConstant.constant = noteView.isHidden ? -(noteView.bounds.size.height) : 20 fillColorViewTopConstraint.constant = fillColorView.isHidden ? -fillColorView.bounds.size.height : 20 fontViewColorPVConstraint.constant = fontViewCorloPV.isHidden ? -fontViewCorloPV.bounds.size.height : 10 } func setActiveAnnotationType(_ activeAnnotationType: KMActiveAnnotationType) { self.activeAnnotationType = activeAnnotationType switch activeAnnotationType { case .highlight, .strikeOut, .underline: fontView.isHidden = true borderAndLineView.isHidden = true fillColorView.isHidden = true rotateView.isHidden = true typeView.isHidden = true dateView.isHidden = true iconView.isHidden = true createMarkupProperties() case .inkAndLine: fontView.isHidden = true fillColorView.isHidden = true rotateView.isHidden = true typeView.isHidden = true dateView.isHidden = true iconView.isHidden = true createInkAndLineProperties() case .text: fontView.isHidden = true borderAndLineView.isHidden = true fillColorView.isHidden = true rotateView.isHidden = true typeView.isHidden = true dateView.isHidden = true createTextProperties() case .squareAndCircle: fontView.isHidden = true rotateView.isHidden = true typeView.isHidden = true dateView.isHidden = true iconView.isHidden = true fillColorView.isHidden = true createSquareAndCircleProperties() case .freeText: colorView.isHidden = true rotateView.isHidden = true typeView.isHidden = true dateView.isHidden = true iconView.isHidden = true createFreeTextProperties() case .selfSignFreeText: rotateView.isHidden = true borderAndLineView.isHidden = true fillColorView.isHidden = true typeView.isHidden = true iconView.isHidden = true createSelfSignFreeTextProperties() default: break } } func createMarkupProperties() { let colorViewHeight = colorTitleLabel.frame.height + KMColorPickerViewHeight + 30 colorView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: colorViewHeight) textColorBoxConstraint.constant = 10 borderColorBoxConstraint.constant = 0 textColorBox.isHidden = true lineWidthBox.isHidden = true imageBoxLayoutConstraint.constant = generalImageBoxView.frame.height hiddenSubviews() textColorPickerView.noContentString = true if activeAnnotationType == .highlight { textColorPickerView.annotationTypeString = NSLocalizedString("Highlight", comment: "Description for export") } else if activeAnnotationType == .strikeOut { textColorPickerView.annotationTypeString = NSLocalizedString("Strikethrough", comment: "Description for export") } else if activeAnnotationType == .underline { textColorPickerView.annotationTypeString = NSLocalizedString("Underline", comment: "Description for export") } textColorPickerView.annotationType = (activeAnnotationType == .highlight) ? .markupHighlightColors : .markupOtherColors } func openFreeTextStylesViewController() { let vc = KMFreeTextStylesViewController() vc.annotations = annotations vc.annotationModel = self.annotationModel vc.view.frame = CGRect(x: 0, y: 0, width: 280, height: NSHeight(self.view.window?.frame ?? CGRect.zero) - 300) vc.didSelect = { [weak self] data in self?.updateAnnotation() } let createFilePopover = NSPopover() createFilePopover.contentViewController = vc createFilePopover.animates = true createFilePopover.behavior = .transient createFilePopover.show(relativeTo: CGRect(x: textImageBox.bounds.origin.x, y: 10, width: textImageBox.bounds.size.width, height: textImageBox.bounds.size.height), of: textImageBox, preferredEdge: .minY) // Assuming _textImageBox is an NSView instance createFilePopover.show(relativeTo: textImageBox.bounds, of: textImageBox, preferredEdge: .minY) // Release is not needed in Swift due to automatic reference counting (ARC) } func changeStoredFontInfo(_ sender: Any) { // if let senderFont = sender as? NSFont { // for tAnnotation in self.annotations { // tAnnotation.removeAllAppearanceStreams() // let font = senderFont.convert(tAnnotation.font) // if let validFont = font { // tAnnotation.font = validFont // } // } // } } private func updateAnnotation(_ type: KMRefreshType = .none) { if annotationModel?.annotation != nil { if annotation is CPDFFreeTextAnnotation { let textNote = (annotation as! CPDFFreeTextAnnotation) if let isEdit = pdfView?.isEdit(withCurrentFreeText: textNote), isEdit { pdfView?.commitEditAnnotationFreeText(textNote) // pdfView?.editAnnotationFreeText(textNote) } pdfView?.setNeedsDisplay(pdfView?.activeAnnotation) } else if annotationModel?.annotation is CSelfSignAnnotationFreeText { let textNote = (annotation as! CSelfSignAnnotationFreeText) if let isEdit = pdfView?.isEdit(withCurrentFreeText: textNote), isEdit { pdfView?.editAnnotationFreeText(textNote) } pdfView?.setNeedsDisplay(pdfView?.activeAnnotation) } for tAnnotation in annotations { if tAnnotation is CPDFStampAnnotation { (tAnnotation as? KMSelfSignAnnotation)?.updateAppearanceStream() } if tAnnotation is CPDFMarkupAnnotation { pdfView?.setNeedsDisplayFor(tAnnotation.page) } else { pdfView?.setNeedsDisplayAnnotationViewFor(tAnnotation.page) } } } refreshColorPickerView(type) if annotationType == .freeText { textAnnotationImageView.image = annotationModel?.annotationImage } else { generalImageView.image = annotationModel?.annotationImage } } private func refreshColorPickerView(_ type: KMRefreshType) { if type == .color { var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 if annotationType == .highlight || annotationType == .underline || annotationType == .strikeOut || annotationType == .ink || annotationType == .freeText || annotationType == .anchored || annotationType == .square || annotationType == .circle || annotationType == .line || annotationType == .arrow { let modelOpcity = annotationModel?.opacity() ?? 1.0 opacitySlider.floatValue = Float(modelOpcity) opacitySlider.toolTip = "\(Int(modelOpcity * 100))%" opacityComboBox.stringValue = "\(Int(modelOpcity * 100))%" } } else if type == .opacity { var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 if annotationType == .highlight || annotationType == .underline || annotationType == .strikeOut || annotationType == .ink || annotationType == .anchored { let modelColor = annotationModel?.color() ?? .red modelColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) let modelOpcity = annotationModel?.opacity() ?? 1.0 textColorPickerView.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) opacitySlider.floatValue = Float(modelOpcity) opacitySlider.toolTip = "\(Int(modelOpcity * 100))%" opacityComboBox.stringValue = "\(Int(modelOpcity * 100))%" } else if annotationType == .freeText { let modelOpcity = annotationModel?.opacity() ?? 1.0 let fontColor = annotationModel?.fontColor() ?? .black fontColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) fontViewCorloPV.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) let fillColor = annotationModel?.color() ?? .red fillColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) fillColorPickerView.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) } else if annotationType == .square || annotationType == .circle { let modelOpcity = annotationModel?.opacity() ?? 1.0 let lineColor = annotationModel?.interiorColor() ?? .red lineColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) textColorPickerView.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) let fillColor = annotationModel?.color() ?? .clear fillColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) borderColorPickerView.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) } else if annotationType == .line || annotationType == .arrow { let modelOpcity = annotationModel?.opacity() ?? 1.0 let lineColor = annotationModel?.color() ?? .red lineColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) borderColorPickerView.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) let fillColor = annotationModel?.interiorColor() ?? .clear fillColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) textColorPickerView.setColor(NSColor(red: red, green: green, blue: blue, alpha: modelOpcity)) } } } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if self.annotation.isEqual(to: object) == false { return } let newValue = change?[NSKeyValueChangeKey.newKey] as? NSObject let oldValue = change?[NSKeyValueChangeKey.oldKey] if let data = newValue?.isEqual(to: oldValue), data { return } if keyPath == "string" || keyPath == "contents"{ if newValue == nil || newValue is NSNull { return } //处理编辑时光标后移 if self.isTextEdit == false { self.noteTextView.string = newValue as? String ?? "" } self.isTextEdit = false } else { self.reloadData() if self.isannotationMode { self.updateannotationMode() } } } func updateDateView() -> Void { datePopUpButton.removeAllItems() let includeTime = annotationModel?.includeTime() ?? false datePopUpButton.addItems(withTitles: KMSelfSignAnnotationFreeText.fetchAllDateString(includeTime: includeTime)) let dateFormatIndex = annotationModel?.dateFormatIndex() ?? 0 if dateFormatIndex >= 0 && dateFormatIndex < datePopUpButton.numberOfItems { datePopUpButton.selectItem(at: dateFormatIndex) } else { datePopUpButton.selectItem(at: 0) } dateCheckButton.state = includeTime ? .on : .off } // MARK: Line Note func createInkAndLineProperties() { if annotationType == .ink { let colorViewHeight = NSHeight(colorTitleLabel.frame) + KMColorPickerViewHeight + 30 colorView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: colorViewHeight) textColorBoxConstraint.constant = 10 borderColorBoxConstraint.constant = 0 textColorBox.isHidden = true lineWidthBox.isHidden = true imageBoxLayoutConstraint.constant = NSHeight(generalImageBoxView.frame) hiddenSubviews() textColorPickerView.noContentString = true textColorPickerView.annotationTypeString = NSLocalizedString("Line Color", comment: "") textColorPickerView.annotationType = .inkColors } else if annotationType == .line || annotationType == .arrow { let colorViewHeight = NSHeight(colorTitleLabel.frame) + KMColorPickerViewHeight * 2 + 40 colorView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: colorViewHeight) textColorBoxConstraint.constant = KMColorPickerViewHeight + 20 borderColorBoxConstraint.constant = 0 lineWidthBox.isHidden = true textColorPickerViewConstant.constant = 57 imageBoxLayoutConstraint.constant = NSHeight(generalImageBoxView.frame) hiddenSubviews() borderColorPickerView.annotationTypeString = NSLocalizedString("Line Color", comment: "") textColorPickerView.annotationTypeString = NSLocalizedString("Fill Color", comment: "") borderColorPickerView.annotationType = .lineColors textColorPickerView.annotationType = .lineFillColors } lineTypeLabel.stringValue = NSLocalizedString("Line and Border Style", comment: "") lineTypeLabel.textColor = KMAppearance.Layout.h0Color() lineWidthSlider.floatValue = Float((annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) lineWidthComboBox.stringValue = String(format: "%0.1f pt", (annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) lineStyleButton.wantsLayer = true dottedLineStyleButton.wantsLayer = true rightArrowStyleButton.wantsLayer = true lineStyleButton.image = borderStyleSolid(false) dottedLineStyleButton.image = borderStyleDashed(false) rightArrowStyleButton.image = lineStyleRightArrow(false) if annotationModel?.style() == .solid { lineStyleCount = 0 lineStyleButton.image = borderStyleSolid(true) lineStyleBox.borderWidth = 0 lineStyleBox.fillColor = KMAppearance.Status.selColor() } else if annotationModel?.style() == .dashed { lineStyleCount = 1 dottedLineStyleButton.image = borderStyleDashed(true) dottedLineStyleBox.borderWidth = 0 dottedLineStyleBox.fillColor = KMAppearance.Status.selColor() } if (annotationType == .line || annotationType == .arrow) && annotationModel?.endLineStyle() == .closedArrow { lineStyleCount = 2 rightArrowStyleButton.image = lineStyleRightArrow(true) rightArrowStyleBox.borderWidth = 0 rightArrowStyleBox.fillColor = KMAppearance.Status.selColor() } } func createTextProperties() { makeNoteIcons() let colorViewHeight = colorTitleLabel.frame.height + KMColorPickerViewHeight + 30 colorView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: colorViewHeight) textColorBoxConstraint.constant = 10 borderColorBoxConstraint.constant = 0 textColorBox.isHidden = true lineWidthBox.isHidden = true imageBoxLayoutConstraint.constant = generalImageBoxView.frame.height hiddenSubviews() textColorPickerView.annotationTypeString = NSLocalizedString("Anchored Note", comment: "Description for export") commentButton.title = NSLocalizedString("Comment", comment: "") commentButton.toolTip = NSLocalizedString("Comment", comment: "") commentButton.setTitleColor(KMAppearance.Layout.h0Color()) paragraphButton.title = NSLocalizedString("Paragraph", comment: "") paragraphButton.toolTip = NSLocalizedString("Paragraph", comment: "") paragraphButton.setTitleColor(KMAppearance.Layout.h0Color()) insertButton.title = NSLocalizedString("Insert", comment: "") insertButton.toolTip = NSLocalizedString("Insert", comment: "") insertButton.setTitleColor(KMAppearance.Layout.h0Color()) addParagraphButton.title = NSLocalizedString("New Paragraph", comment: "") addParagraphButton.toolTip = NSLocalizedString("New Paragraph", comment: "") addParagraphButton.setTitleColor(KMAppearance.Layout.h0Color()) keyButton.title = NSLocalizedString("Key", comment: "") keyButton.toolTip = NSLocalizedString("Key", comment: "") keyButton.setTitleColor(KMAppearance.Layout.h0Color()) noteButton.title = NSLocalizedString("Note", comment: "") noteButton.toolTip = NSLocalizedString("Note", comment: "") noteButton.setTitleColor(KMAppearance.Layout.h0Color()) helpButton.title = NSLocalizedString("Help", comment: "") helpButton.toolTip = NSLocalizedString("Help", comment: "") helpButton.setTitleColor(KMAppearance.Layout.h0Color()) // let languages = NSLocale.preferredLanguages var currentLocaleLanguageCode = NSLocalizedString("en-new", comment: "") // if let firstLanguage = languages.first { // currentLocaleLanguageCode = firstLanguage // if currentLocaleLanguageCode.hasPrefix("zh") { // currentLocaleLanguageCode = "zh" // } // } let buttonArray: [NSButton] = [commentButton, keyButton, noteButton, helpButton, addParagraphButton, paragraphButton, insertButton] for button in buttonArray { button.wantsLayer = true button.layer?.cornerRadius = 6.0 if currentLocaleLanguageCode == "zh" { iconButtonHeightConstant.constant = 56.0 button.imagePosition = .imageAbove } else { iconButtonHeightConstant.constant = 50.0 button.imagePosition = .imageOnly } } iconButtonArray = [commentBox, keyBox, noteBox, helpBox, addParagraphBox, paragraphBox, insertBox] if let data = annotationModel?.anchoredIconType().rawValue { let iconType = UInt(data) clickAnnotationTextIconButtonAction(iconType: iconType, boxArr: iconButtonArray) } else { clickAnnotationTextIconButtonAction(iconType: 0, boxArr: iconButtonArray) } textColorPickerView.annotationType = .anchoredNoteColors textColorPickerView.isCallColorPanelAction = true } func clickAnnotationTextIconButtonAction(iconType: UInt, boxArr buttonArr: [NSBox]) { for i in 0.. NSImage { let size = NSSize(width: 49.0, height: 12.0) let image = NSImage(size: size, flipped: false, drawingHandler: { rect in let path = NSBezierPath(rect: NSRect(x: 15.0, y: 5.0, width: 20.0, height: 1.0)) path.lineWidth = 2.0 isSelect ? KMAppearance.Layout.m_1Color().setStroke() : KMAppearance.Layout.m_1Color().setStroke() path.stroke() return true }) return image } func borderStyleDashed(_ isSelect: Bool) -> NSImage { let size = NSSize(width: 49.0, height: 12.0) let image = NSImage(size: size, flipped: false, drawingHandler: { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 15.0, y: 5.0)) path.line(to: NSPoint(x: 19.0, y: 5.0)) path.move(to: NSPoint(x: 23.0, y: 5.0)) path.line(to: NSPoint(x: 27.0, y: 5.0)) path.move(to: NSPoint(x: 31.0, y: 5.0)) path.line(to: NSPoint(x: 35.0, y: 5.0)) path.lineWidth = 2.0 isSelect ? KMAppearance.Layout.m_1Color().setStroke() : KMAppearance.Layout.m_1Color().setStroke() path.stroke() return true }) return image } func lineStyleRightArrow(_ isSelect: Bool) -> NSImage { let size = NSSize(width: 49.0, height: 12.0) let image = NSImage(size: size, flipped: false, drawingHandler: { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 43.0, y: 6.0)) path.move(to: NSPoint(x: 32.0, y: 3.0)) path.line(to: NSPoint(x: 43.0, y: 6.0)) path.line(to: NSPoint(x: 32.0, y: 9.0)) path.close() path.lineWidth = 2.0 if isSelect { KMAppearance.Layout.l0Color().setStroke() } else { KMAppearance.Interactive.s0Color().setStroke() } path.stroke() return true }) return image } // MARK: SKSquareNote、SKCircleNote、SKArrowNote Properties func createSquareAndCircleProperties() { let colorViewHeight = NSHeight(colorTitleLabel.frame) + KMColorPickerViewHeight * 2 + 40 colorView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: colorViewHeight) textColorBoxConstraint.constant = KMColorPickerViewHeight + 20 borderColorBoxConstraint.constant = 0 lineWidthBox.isHidden = true textColorPickerViewConstant.constant = 57 imageBoxLayoutConstraint.constant = NSHeight(generalImageBoxView.frame) hiddenSubviews() lineTypeLabel.stringValue = NSLocalizedString("Line and Border Style", comment: "") lineTypeLabel.textColor = KMAppearance.Layout.h0Color() lineWidthSlider.floatValue = Float((annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) lineWidthComboBox.stringValue = String(format: "%0.1f pt", (annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) textColorPickerView.annotationTypeString = NSLocalizedString("Fill Color", comment: "") borderColorPickerView.annotationTypeString = NSLocalizedString("Line Color", comment: "") textColorPickerView.annotationType = .lineFillColors borderColorPickerView.annotationType = .lineColors lineStyleButton.wantsLayer = true dottedLineStyleButton.wantsLayer = true rightArrowStyleButton.wantsLayer = true lineStyleButton.image = borderStyleSolid(false) dottedLineStyleButton.image = borderStyleDashed(false) if annotationModel?.annotation != nil { if annotationModel?.annotation.borderStyle() == .solid { lineStyleCount = 0 lineStyleButton.image = borderStyleSolid(true) lineStyleBox.borderWidth = 0 lineStyleBox.fillColor = KMAppearance.Status.selColor() } else if annotationModel?.annotation.borderStyle() == .dashed { lineStyleCount = 1 dottedLineStyleButton.image = borderStyleDashed(true) dottedLineStyleBox.borderWidth = 1 dottedLineStyleBox.fillColor = KMAppearance.Status.selColor() } } else { if annotationModel?.style() == .solid { lineStyleCount = 0 lineStyleButton.image = borderStyleSolid(true) lineStyleBox.borderWidth = 0 lineStyleBox.fillColor = KMAppearance.Status.selColor() } else if annotationModel?.style() == .dashed { lineStyleCount = 1 dottedLineStyleButton.image = borderStyleDashed(true) dottedLineStyleBox.borderWidth = 1 dottedLineStyleBox.fillColor = KMAppearance.Status.selColor() } } } // MARK: SKFreeTextNote、PDFAnnotationFreeText Properties func createFreeTextProperties() { imageBox.fillColor = KMAppearance.Layout.w0Color() textColorBox.isHidden = true lineWidthBox.isHidden = true imageBoxLayoutConstraint.constant = NSHeight(textImageBoxView.frame) textImageBox.downCallback = { [weak self] downEntered, mouseBox, event in if downEntered { self?.openFreeTextStylesViewController() } } textImageUpDateButton.wantsLayer = true textImageBoxButton.image = NSImage(named: KMImageNameUXIconBtnTriDownNor) textImageBoxButton.isEnabled = true textImageUpDateButton.title = NSLocalizedString("Click to refresh", comment: "") textImageUpDateButton.setTitleColor(KMAppearance.Layout.w0Color()) textImageUpDateButton.layer?.cornerRadius = 1.0 textImageUpDateButton.layer?.backgroundColor = KMAppearance.Interactive.m0Color().cgColor textImageUpDateButton.isHidden = true hiddenSubviews() fontViewCorloPV.noContentString = true fontViewCorloPV.annotationTypeString = NSLocalizedString("Color", comment: "") fillColorPickerView.noContentString = true fillColorPickerView.annotationTypeString = NSLocalizedString("Color", comment: "") lineTypeLabel.stringValue = NSLocalizedString("Line and Border Style", comment: "") lineTypeLabel.textColor = KMAppearance.Layout.h0Color() leftAlignButton.toolTip = NSLocalizedString("Left Alignment", comment: "") centerAlignButton.toolTip = NSLocalizedString("Center", comment: "") rightAlignButton.toolTip = NSLocalizedString("Right Alignment", comment: "") lineWidthSlider.floatValue = Float((annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) lineWidthComboBox.stringValue = String(format: "%0.1f pt", Float((annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_)) leftRotateBox.borderColor = KMAppearance.Interactive.s0Color() leftRotateBox.borderWidth = 0.5 leftRotateButton.image = NSImage(named: KMImageNameUXIconPropertybarRotateCounterclockwiseNor) leftRotateBox.downCallback = { [weak self] downEntered, mouseBox, event in if downEntered { self?.leftRotateBox.fillColor = KMAppearance.Status.selColor() self?.leftRotateButton.image = NSImage(named: KMImageNameUXIconPropertybarRotateCounterclockwisePre) } else { self?.leftRotateBox.fillColor = KMAppearance.Layout.w0Color() self?.leftRotateButton.image = NSImage(named: KMImageNameUXIconPropertybarRotateCounterclockwiseNor) } } rightRotateBox.borderColor = KMAppearance.Interactive.s0Color() rightRotateBox.borderWidth = 0.5 rightRotateButton.image = NSImage(named: KMImageNameUXIconPropertybarRotateClockwiseNor) rightRotateBox.downCallback = { [weak self] downEntered, mouseBox, event in if downEntered { self?.rightRotateBox.fillColor = KMAppearance.Status.selColor() self?.rightRotateButton.image = NSImage(named: KMImageNameUXIconPropertybarRotateClockwisePre) } else { self?.rightRotateBox.fillColor = KMAppearance.Layout.w0Color() self?.rightRotateButton.image = NSImage(named: KMImageNameUXIconPropertybarRotateClockwiseNor) } } lineStyleButton.wantsLayer = true dottedLineStyleButton.wantsLayer = true rightArrowStyleButton.wantsLayer = true lineStyleButton.image = borderStyleSolid(false) dottedLineStyleButton.image = borderStyleDashed(false) if annotationModel?.style() == .solid { lineStyleCount = 0 lineStyleButton.image = borderStyleSolid(true) lineStyleBox.borderWidth = 0 lineStyleBox.fillColor = KMAppearance.Status.selColor() lineStyleBox.borderWidth = 0 } else if annotationModel?.style() == .dashed { lineStyleCount = 1 dottedLineStyleButton.image = borderStyleDashed(true) dottedLineStyleBox.fillColor = KMAppearance.Status.selColor() dottedLineStyleBox.borderWidth = 0 } else { lineStyleCount = 0 lineStyleButton.image = borderStyleSolid(true) lineStyleBox.borderWidth = 0 lineStyleBox.fillColor = KMAppearance.Status.selColor() lineStyleBox.borderWidth = 0 } fontViewCorloPV.annotationType = .freeTextColors fillColorPickerView.annotationType = .freeTextFillColors } func alignmentTypeSelected(_ type: KMFreeTextAnnotationAlignmentType) { annotationAlignment = type selectedAlignmentButtonLayer?.removeFromSuperlayer() selectedAlignmentButtonLayer = CALayer() selectedAlignmentButtonLayer?.cornerRadius = 6.0 leftAlignButton.wantsLayer = true centerAlignButton.wantsLayer = true rightAlignButton.wantsLayer = true selectedAlignmentButtonLayer?.bounds = leftAlignButton.layer?.bounds ?? CGRect.zero selectedAlignmentButtonLayer?.anchorPoint = CGPoint(x: 0, y: 0) var color = NSColor(red: 71/255.0, green: 126/255.0, blue: 222/255.0, alpha: 0.16) if #available(macOS 10.14, *) { let appearanceName = NSApp.effectiveAppearance.bestMatch(from: [.aqua, .darkAqua]) if appearanceName == .darkAqua { color = NSColor(red: 34/255.0, green: 122/255.0, blue: 255/255.0, alpha: 0.3) } } selectedAlignmentButtonLayer?.backgroundColor = color.cgColor leftAlignButton.image = NSImage(named: KMImageNameUXIconPropertybarTextalignLeftNor) centerAlignButton.image = NSImage(named: KMImageNameUXIconPropertybarTextalignCenterNor) rightAlignButton.image = NSImage(named: KMImageNameUXIconPropertybarTextalignRightNor) if type == .left { leftAlignButton.image = NSImage(named: KMImageNameUXIconPropertybarTextalignLeftSel) } else if type == .center { centerAlignButton.image = NSImage(named: KMImageNameUXIconPropertybarTextalignCenterSel) } else if type == .right { rightAlignButton.image = NSImage(named: KMImageNameUXIconPropertybarTextalignRightSel) } DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { [weak self] in guard let self = self else { return } guard let data = self.selectedAlignmentButtonLayer else { return } if type == .left { self.leftAlignButton.layer?.insertSublayer(data, at: 0) } else if type == .center { self.centerAlignButton.layer?.insertSublayer(data, at: 0) } else if type == .right { self.rightAlignButton.layer?.insertSublayer(data, at: 0) } } } // MARK: SKFreeTextNote、KMSelfSignAnnotationFreeText Properties func createSelfSignFreeTextProperties() { let colorViewHeight = NSHeight(colorTitleLabel.frame) + KMColorPickerViewHeight + 30 colorView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: colorViewHeight) textColorBoxConstraint.constant = 10 borderColorBoxConstraint.constant = 0 textColorBox.isHidden = true lineWidthBox.isHidden = true imageBoxLayoutConstraint.constant = NSHeight(generalImageBoxView.frame) hiddenSubviews() fontViewTopConstant.constant = colorView.frame.size.height + opacityView.frame.size.height - 10 + 10 ColorViewTopConstant.constant = -(fontView.frame.size.height + fontViewTopConstant.constant) dateViewTopConstant.constant = fontView.frame.size.height + 30 fontViewCorloPV.noContentString = true fontViewCorloPV.annotationTypeString = "" textColorPickerView.annotationTypeString = NSLocalizedString("Background", comment: "") dateCheckButton.title = NSLocalizedString("Time", comment: "") if let attrTitle = dateCheckButton.attributedTitle.mutableCopy() as? NSMutableAttributedString { let len = attrTitle.length let range = NSRange(location: 0, length: len) attrTitle.addAttribute(.foregroundColor, value: KMAppearance.Layout.h1Color(), range: range) attrTitle.fixAttributes(in: range) dateCheckButton.attributedTitle = attrTitle } if activeAnnotationType == .selfSignFreeText { // 添加日期 字体默认颜色不要透明色 textColorPickerView.annotationType = .freeTextFillColors fontViewCorloPV.annotationType = .freeTextColors } else { textColorPickerView.annotationType = .freeTextColors fontViewCorloPV.annotationType = .freeTextFillColors } } func setFontStyle(fontName: String, currentStyle style: String?) -> UInt { var selectIndex: UInt = 0 let menu = NSMenu() if let fontFamily = NSFontManager.shared.availableMembers(ofFontFamily: fontName) { for i in 0.. 18 { lineWidth = 18 } else if lineWidth < 0.5 { lineWidth = 0.5 } annotationModel?.setLineWidth(CGFloat(lineWidth)) lineWidthSlider.floatValue = Float((annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_) updateAnnotation() } @IBAction func alignButtonAction(_ sender: NSButton) { var alignmentType: KMFreeTextAnnotationAlignmentType = .left if annotationModel?.annotations != nil { for tAnnotation in self.annotations { switch sender.tag { case 0: if tAnnotation is CPDFFreeTextAnnotation { (tAnnotation as! CPDFFreeTextAnnotation).alignment = .left } alignmentType = .left case 1: if tAnnotation is CPDFFreeTextAnnotation { (tAnnotation as! CPDFFreeTextAnnotation).alignment = .center } alignmentType = .center case 2: if tAnnotation is CPDFFreeTextAnnotation { (tAnnotation as! CPDFFreeTextAnnotation).alignment = .right } alignmentType = .right default: break } } } else { switch sender.tag { case 0: annotationModel?.setAlignment(.left) alignmentType = .left case 1: annotationModel?.setAlignment(.center) alignmentType = .center case 2: annotationModel?.setAlignment(.right) alignmentType = .right default: break } } alignmentTypeSelected(alignmentType) updateAnnotation() NotificationCenter.default.post(name: NSNotification.Name("KMAnnotationAlignmentTypeNotification"), object: "\(alignmentType.rawValue)") } @IBAction func currentFontColorButtonAction(_ sender: NSButton) { // if ([_annotation isKindOfClass:[PDFAnnotationFreeText class]]) { // KMFontColorViewController *vc = [[[KMFontColorViewController alloc] initWithNibName:@"KMFontColorViewController" bundle:[NSBundle mainBundle]] autorelease]; // vc.annotationFontColor = _annotation.fontColor; // __block typeof(self) blockSelf = self; // vc.fontColorChangeCallback = ^(NSColor *fontColor) { // for (PDFAnnotation *tAnnotation in blockSelf.annotations) { // tAnnotation.fontColor = fontColor; // } // }; // NSPopover *popover = [[NSPopover alloc] init]; // popover.delegate = self; // popover.contentViewController = vc; // popover.animates = YES; // popover.behavior = NSPopoverBehaviorTransient; // [popover showRelativeToRect:CGRectMake([sender bounds].origin.x, 0, [sender bounds].size.width, [sender bounds].size.height) ofView:sender preferredEdge:CGRectMaxYEdge]; // [popover release]; // } } @IBAction func borderButtonAction(_ sender: NSButton) { var lineWidth: CGFloat = 0.0 var lineStype: CPDFBorderStyle = .solid var startingPoint: CPDFLineStyle = .none var endPoint: CPDFLineStyle = .none var dashPattern: [NSNumber] = [] var isLineAnnotation: Bool = false if annotationModel?.annotations != nil { for tAnnotation in self.annotations { lineWidth = tAnnotation.lineWidth() lineStype = tAnnotation.borderStyle() dashPattern = tAnnotation.dashPattern() as? [NSNumber] ?? [] if tAnnotation is CPDFLineAnnotation { isLineAnnotation = true startingPoint = (tAnnotation as! CPDFLineAnnotation).startLineStyle endPoint = (tAnnotation as! CPDFLineAnnotation).endLineStyle } else { isLineAnnotation = false } } } else { lineWidth = (annotationModel?.lineWidth()) ?? self.kDefaultLineWidth_ lineStype = (annotationModel?.style()) as? CPDFBorderStyle ?? .solid dashPattern = (annotationModel?.dashPattern()) as? [NSNumber] ?? [] if annotationModel?.annotationType == .line { isLineAnnotation = true startingPoint = (annotationModel?.startLineStyle()) as? CPDFLineStyle ?? .none endPoint = (annotationModel?.endLineStyle()) as? CPDFLineStyle ?? .none } else { isLineAnnotation = false } } let lineModel = KMLineModel(lineWidth: lineWidth, lineStype: lineStype, startingPoint: startingPoint, endPoint: endPoint, dashPattern: dashPattern, isLineAnnotation: isLineAnnotation) let fontWindowController = KMAnnotationLineWindowController.initWindowController(lineModel) guard let window = fontWindowController.window else { return } fontWindowController.callback = { [self] model in if annotationType == .ink { lineWidthSlider.floatValue = Float(model.lineWidth) lineWidthComboBox.stringValue = String(format: "%0.1f pt", Float(model.lineWidth)) } annotationModel?.setLineWidth(model.lineWidth) annotationModel?.setStyle(model.lineStype) if model.lineStype == .solid { lineTypeButtonAction(lineStyleButton) } else if model.lineStype == .dashed { lineTypeButtonAction(dottedLineStyleButton) for tAnnotation in self.annotations { tAnnotation.setDashPattern(model.dashPattern) } } annotationModel?.setStart(model.startingPoint) annotationModel?.setEnd(model.endPoint) } window.orderFront(sender) } func lineTypePopAction() { annotationModel?.setStyle(CPDFBorderStyle(rawValue: lineStyleCount) ?? .solid) updateAnnotation() } @IBAction func lineTypeButtonAction(_ sender: NSButton) { let tag = sender.tag switch tag { case 0: lineStyleCount = 0 refreshLineTypeUI() lineStyleButton.image = borderStyleSolid(true) dottedLineStyleButton.image = borderStyleDashed(false) rightArrowStyleButton.image = lineStyleRightArrow(false) lineTypePopAction() case 1: lineStyleCount = 1 refreshLineTypeUI() lineStyleButton.image = borderStyleSolid(false) dottedLineStyleButton.image = borderStyleDashed(true) rightArrowStyleButton.image = lineStyleRightArrow(false) lineTypePopAction() case 2: lineStyleCount = 2 refreshLineTypeUI() lineStyleButton.image = borderStyleSolid(false) dottedLineStyleButton.image = borderStyleDashed(false) rightArrowStyleButton.image = lineStyleRightArrow(true) for tAnnotation in annotations { if tAnnotation is CPDFLineAnnotation { (tAnnotation as! CPDFLineAnnotation).endLineStyle = .closedArrow } } default: break } } @IBAction func iconButtonAction(_ sender: NSButton) { var type: CPDFTextAnnotationIconType = .comment switch sender.tag { case 0: type = .comment case 1: type = .key case 2: type = .note case 3: type = .help case 4: type = .newParagraph case 5: type = .paragraph case 6, _: type = .insert } if annotationModel?.annotations != nil { for tAnnotation in self.annotations { if tAnnotation is CPDFTextAnnotation { (tAnnotation as! CPDFTextAnnotation).setIconType(type) } } self.updateAnnotation() } else { annotationModel?.setAnchoredIconType(type) } generalImageView.image = annotationModel?.annotationImage updateannotationMode() clickAnnotationTextIconButtonAction(iconType: UInt(sender.tag), boxArr: iconButtonArray) } @IBAction func textImageBoxButtonAction(_ sender: Any) { openFreeTextStylesViewController() } // MARK: Font、FontSize Action @IBAction func fontButtonAction(_ sender: NSButton) { let selectItem = self.fontPopUpButton.selectedItem guard let selectItem = selectItem else { return } let resultAtt = NSMutableAttributedString(attributedString: selectItem.attributedTitle!) let familyString = resultAtt.string let styleString = self.fontStylePopUpButton.selectedItem?.title ?? "" let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [.family: familyString, .face: styleString as Any]) let fontSizeString = fontSizeComboBox.stringValue.replacingOccurrences(of: " pt", with: "") let newFont = NSFont(descriptor: attributeFontDescriptor, size: fontSizeString.stringToCGFloat()) let fontModel = KMFontModel(fontName: familyString, fontWeight: styleString, fontSize: fontSizeString.stringToCGFloat(), fontColor: textColorPickerView.color ?? .black, fontAlignment: annotationAlignment, annotationType: annotationModel?.annotationType ?? .unkown) let fontWindowController = KMAnnotationFontWindowController.initWindowController(fontModel) let window = fontWindowController.window fontWindowController.callback = { [weak self] model in self?.alignmentTypeSelected(model.fontAlignment) self?.textColorPickerView.color = model.fontColor DispatchQueue.global(qos: .default).async { [self] let fonts = NSFontManager.shared.availableFontFamilies let menu = NSMenu() var selectedIndex = 0 for (index, fontName) in fonts.enumerated() { if let font = NSFont(name: fontName, size: 12.0) { let attributedString = NSAttributedString(string: fontName, attributes: [.font: font]) let item = NSMenuItem() item.attributedTitle = attributedString menu.addItem(item) if let family = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String, let style = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.face) as? String { if model.fontName == family { selectedIndex = index } } } } DispatchQueue.main.async { self?.fontPopUpButton.menu = menu self?.fontPopUpButton.selectItem(at: selectedIndex) } } let selectedStyleIndex = self?.setFontStyle(fontName: model.fontName, currentStyle: model.fontWeight) ?? 0 self?.fontStylePopUpButton.selectItem(at: Int(selectedStyleIndex)) self?.fontSizeComboBox.stringValue = String(format: "%.f pt", model.fontSize) if self?.annotationModel?.annotations != nil { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [.family: model.fontName, .face: model.fontWeight]) let annotationFont = NSFont(descriptor: attributeFontDescriptor, size: model.fontSize) for tAnnotation in self?.annotations ?? [] { if tAnnotation is CPDFFreeTextAnnotation { (tAnnotation as! CPDFFreeTextAnnotation).font = annotationFont (tAnnotation as! CPDFFreeTextAnnotation).fontColor = model.fontColor if model.fontAlignment == .left { (tAnnotation as! CPDFFreeTextAnnotation).alignment = .left } else if model.fontAlignment == .center { (tAnnotation as! CPDFFreeTextAnnotation).alignment = .center } else if model.fontAlignment == .right { (tAnnotation as! CPDFFreeTextAnnotation).alignment = .right } } } self?.updateAnnotation() } else { self?.annotationModel?.setFontName(model.fontName) self?.annotationModel?.setFontSize(model.fontSize) self?.annotationModel?.setFontColor(model.fontColor) if model.fontAlignment == .left { self?.annotationModel?.setAlignment(.left) } else if model.fontAlignment == .center { self?.annotationModel?.setAlignment(.center) } else if model.fontAlignment == .right { self?.annotationModel?.setAlignment(.right) } } } window?.orderFront(sender) } @IBAction func fontPopUpButtonAction(_ sender: NSPopUpButton) { guard let selectedItem = fontPopUpButton.selectedItem else { return } let resultAtt = NSMutableAttributedString(attributedString: selectedItem.attributedTitle!) let familyString = resultAtt.string let selectIndex = setFontStyle(fontName: familyString, currentStyle: nil) guard let styleString = fontStylePopUpButton.selectedItem?.title else { return } fontStylePopUpButton.selectItem(at: Int(selectIndex)) if annotationModel?.annotations != nil { for tAnnotation in annotations { if tAnnotation is CPDFFreeTextAnnotation { let newAnnotation = (tAnnotation as! CPDFFreeTextAnnotation) if let font = newAnnotation.font { if let fontSize = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? Int { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [NSFontDescriptor.AttributeName.family: familyString, NSFontDescriptor.AttributeName.face: styleString]) if let newFont = NSFont(descriptor: attributeFontDescriptor, size: CGFloat(fontSize)) { newAnnotation.font = newFont } } if let tFont = newAnnotation.font { if let family = tFont.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String, let style = tFont.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.face) as? String { DispatchQueue.main.async { let selectedStyleIndex = self.setFontStyle(fontName: family, currentStyle: style) self.fontStylePopUpButton.selectItem(at: Int(selectedStyleIndex)) } } } } } else if tAnnotation is KMSelfSignAnnotationFreeText { let newAnnotation = (tAnnotation as! KMSelfSignAnnotationFreeText) if let font = newAnnotation.font { if let fontSize = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? Int { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [NSFontDescriptor.AttributeName.family: familyString, NSFontDescriptor.AttributeName.face: styleString]) if let newFont = NSFont(descriptor: attributeFontDescriptor, size: CGFloat(fontSize)) { newAnnotation.font = newFont } } newAnnotation.updateBounds() if let tFont = newAnnotation.font { if let family = tFont.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String, let style = tFont.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.face) as? String { DispatchQueue.main.async { let selectedStyleIndex = self.setFontStyle(fontName: family, currentStyle: style) self.fontStylePopUpButton.selectItem(at: Int(selectedStyleIndex)) } } } } } } } else { if annotationType == .freeText || annotationType == .signText || annotationType == .signDate { if let data = annotationModel?.fontName() { let font = NSFont(name: data, size: (annotationModel?.fontSize()) ?? self.kDefaultFontSize_) ?? NSFont.systemFont(ofSize: 16) if let fontSize = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? Int { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [NSFontDescriptor.AttributeName.family: familyString, NSFontDescriptor.AttributeName.face: styleString]) if let newFont = NSFont(descriptor: attributeFontDescriptor, size: CGFloat(fontSize)) { annotationModel?.setFontName(newFont.fontName) annotationModel?.setFontSize(newFont.pointSize) } } let tFont = NSFont(name: data, size: (annotationModel?.fontSize() ?? self.kDefaultFontSize_)) ?? NSFont.systemFont(ofSize: 16) if let family = tFont.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String, let style = tFont.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.face) as? String { DispatchQueue.main.async { let selectedStyleIndex = self.setFontStyle(fontName: family, currentStyle: style) self.fontStylePopUpButton.selectItem(at: Int(selectedStyleIndex)) } } } } } updateannotationMode() updateAnnotation() } @IBAction func fontSizeComboBoxAction(_ sender: NSComboBox) { if annotationModel?.annotations != nil { for tAnnotation in annotations { if tAnnotation is CPDFFreeTextAnnotation { let newAnnotation = (tAnnotation as! CPDFFreeTextAnnotation) if let font = newAnnotation.font { let newFont = NSFont(name: font.fontName, size: CGFloat(fontSizeComboBox.floatValue)) if let newFont = newFont { newAnnotation.font = newFont } } } else if tAnnotation is KMSelfSignAnnotationFreeText { let newAnnotation = (tAnnotation as! KMSelfSignAnnotationFreeText) if let font = newAnnotation.font { let newFont = NSFont(name: font.fontName, size: CGFloat(fontSizeComboBox.floatValue)) if let newFont = newFont { newAnnotation.font = newFont } } newAnnotation.updateBounds() } } } else { if annotationType == .freeText || annotationType == .signText || annotationType == .signDate { if let data = annotationModel?.fontName() { let font = NSFont(name: data, size: (annotationModel?.fontSize() ?? self.kDefaultFontSize_)) ?? NSFont.systemFont(ofSize: 16) let newFont = NSFont(name: font.fontName, size: CGFloat(fontSizeComboBox.floatValue)) if let newFont = newFont { annotationModel?.setFontName(newFont.fontName) annotationModel?.setFontSize(newFont.pointSize) } } } } updateAnnotation() NotificationCenter.default.post(name: NSNotification.Name("KMAnnotationFontTypeNotification"), object: pdfView) adjustFreeText() } //字重 NSFontWeight @IBAction func fontStylePopUpButtonAction(_ sender: NSPopUpButton) { if let styleString = self.fontStylePopUpButton.selectedItem?.title { if annotationModel?.annotations != nil { for tAnnotation in self.annotations { if tAnnotation is CPDFFreeTextAnnotation { let newAnnotation = (tAnnotation as! CPDFFreeTextAnnotation) if let font = newAnnotation.font { if let fontSize = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? Int, let familyString = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [NSFontDescriptor.AttributeName.family: familyString, NSFontDescriptor.AttributeName.face: styleString]) if let newFont = NSFont(descriptor: attributeFontDescriptor, size: CGFloat(fontSize)) { newAnnotation.font = newFont } } } } else if tAnnotation is KMSelfSignAnnotationFreeText { let newAnnotation = (tAnnotation as! KMSelfSignAnnotationFreeText) if let font = newAnnotation.font { if let fontSize = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? Int, let familyString = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [NSFontDescriptor.AttributeName.family: familyString, NSFontDescriptor.AttributeName.face: styleString]) if let newFont = NSFont(descriptor: attributeFontDescriptor, size: CGFloat(fontSize)) { newAnnotation.font = newFont } newAnnotation.updateBounds() } } } } } else { if annotationType == .freeText || annotationType == .signText || annotationType == .signDate { if let data = annotationModel?.fontName() { let font = NSFont(name: data, size: (annotationModel?.fontSize() ?? self.kDefaultFontSize_)) ?? NSFont.systemFont(ofSize: 16) if let fontSize = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.size) as? Int, let familyString = font.fontDescriptor.object(forKey: NSFontDescriptor.AttributeName.family) as? String { let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [NSFontDescriptor.AttributeName.family: familyString, NSFontDescriptor.AttributeName.face: styleString]) if let newFont = NSFont(descriptor: attributeFontDescriptor, size: CGFloat(fontSize)) { annotationModel?.setFontName(newFont.fontName) annotationModel?.setFontSize(newFont.pointSize) } } } } } } updateAnnotation() } @IBAction func buttonClicked_SwitchIncludeTime(_ sender: NSButton) { annotationModel?.setIncludeTime(sender.state == .on ? true:false) self.updateDateView() updateAnnotation() } @IBAction func dateCheckButtonAction(_ sender: NSPopUpButton) { annotationModel?.setDateFormatIndex(sender.indexOfSelectedItem) updateAnnotation() } func annotationFontReload() { DispatchQueue.global(qos: .default).async { [weak self] in guard let self = self else { return } let fonts = NSFontManager.shared.availableFontFamilies let menu = NSMenu() var selectedIndex = 0 for (index, fontName) in fonts.enumerated() { if let font = NSFont(name: fontName, size: 12.0) { let attributedString = NSAttributedString(string: fontName, attributes: [.font: font]) let item = NSMenuItem() item.attributedTitle = attributedString menu.addItem(item) if [.freeText, .signText, .signDate].contains(self.annotationType), let modelFontName = self.annotationModel?.fontName(), modelFontName == font.fontName { selectedIndex = index } } } if [.freeText, .signText, .signDate].contains(self.annotationType), let data = self.annotationModel?.fontName() { let freetextFont = NSFont(name: data, size: 16) ?? NSFont.systemFont(ofSize: 16) if let family = freetextFont.fontDescriptor.object(forKey: .family) as? String, let style = freetextFont.fontDescriptor.object(forKey: .face) as? String { DispatchQueue.main.async { [weak self] in guard let self = self else { return } self.fontPopUpButton.menu = menu self.fontPopUpButton.selectItem(at: selectedIndex) let selectedStyleIndex = self.setFontStyle(fontName: family, currentStyle: style) self.fontStylePopUpButton.selectItem(at: Int(selectedStyleIndex)) } } } } } func adjustFreeText() { if annotationModel?.annotations != nil { if annotationType == .freeText || annotationType == .signText || annotationType == .signDate { for an in (annotationModel?.annotations) ?? [] { if let freeTextAn = an as? CPDFFreeTextAnnotation { let font = freeTextAn.font var attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font as Any] let style = NSMutableParagraphStyle() style.alignment = freeTextAn.alignment attributes[NSAttributedString.Key.paragraphStyle] = style let contents = freeTextAn.contents ?? "" let textViewSize = contents.boundingRect(with: CGSize(width: freeTextAn.bounds.size.width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: attributes).size var rect = freeTextAn.bounds if textViewSize.height != freeTextAn.bounds.size.height { rect.origin.y -= (textViewSize.height - rect.size.height) rect.size.height = textViewSize.height } if textViewSize.width < freeTextAn.bounds.size.width { rect.size.width = textViewSize.width } freeTextAn.bounds = rect } } } } } // MARK: NSNotification @objc func textDidChange(_ notification: Notification) { self.isTextEdit = true if self.subType == KMSelfSignAnnotationFreeTextSubType.freeText && isannotationMode { if let obj = notification.object as? NSObject { for tAnnotation in annotations { tAnnotation.setString(noteTextView.string) } if obj.isEqual(to: noteTextView) { UserDefaults.standard.set(noteTextView.string, forKey: SKAnnotationSelfSignPlaceHolderStringKey) } if annotation.isKind(of: CPDFFreeTextAnnotation.self) { textAnnotationImageView.image = annotationModel?.annotationImage } else { generalImageView.image = annotationModel?.annotationImage } } } else { if let obj = notification.object as? NSObject, obj.isEqual(to: noteTextView) { for tAnnotation in self.annotations { if let markupNote = tAnnotation as? CPDFMarkupAnnotation { markupNote.setMarkupText(noteTextView.string) } else { tAnnotation.setString(noteTextView.string) } } } } } @objc func themeChanged(notification: NSNotification) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [self] in updateViewColor() } } @objc func annotationChangeNotification(_ notification: NSNotification) { if notification.object != nil { let anno: [String : Any] = notification.object as? [String : Any] ?? [:] if let textAnno: CPDFAnnotation = anno["object"] as? CPDFAnnotation { if textAnno.isKind(of: CPDFTextAnnotation.self) { textColorPickerView.setColor(textAnno.color) } } } } } class KMGeneralAnnotationColorButton: NSButton { var _circleColor: NSColor = .clear var _buttonBorderColor: NSColor = .clear // MARK: Get & Set var circleColor: NSColor { set { _circleColor = newValue needsDisplay = true } get { return _circleColor } } var buttonBorderColor: NSColor { set { _buttonBorderColor = newValue needsDisplay = true } get { return _buttonBorderColor } } // MARK: Init required init?(coder: NSCoder) { super.init(coder: coder) wantsLayer = true layer?.cornerRadius = 12.0 layer?.masksToBounds = true layer?.borderColor = NSColor.clear.cgColor } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let path3 = NSBezierPath(ovalIn: NSMakeRect(3, 3, dirtyRect.size.width - 6, dirtyRect.size.height - 6)) } } class KMNoteIconButtonCell: NSButtonCell { override func drawImage(_ image: NSImage, withFrame frame: NSRect, in controlView: NSView) { let titleSize = self.attributedTitle.size() let imageSize = self.image?.size ?? .zero var rect = NSZeroRect let leftGap = (controlView.bounds.size.width - image.size.width) / 2.0 rect.origin.x = leftGap if self.imagePosition == .imageAbove { rect.origin.y = 6 } else { rect.origin.y = (controlView.frame.size.height - image.size.height) / 2.0 } rect.size = imageSize if let data = self.image { super.drawImage(data, withFrame: rect, in: controlView) } } override func drawTitle(_ title: NSAttributedString, withFrame frame: NSRect, in controlView: NSView) -> NSRect { let titleSize = self.attributedTitle.size() let imageSize = self.image?.size ?? .zero let totalHeight = titleSize.height + imageSize.height + 1 var rect = NSZeroRect rect.origin.x = (controlView.bounds.size.width - titleSize.width) / 2.0 rect.origin.y = (controlView.bounds.size.height - totalHeight) / 2.0 + imageSize.height + 1 rect.size = titleSize return super.drawTitle(title, withFrame: rect, in: controlView) } }