// // KMMeasureSideVC.swift // Cisdem PDFMaster // // Created by wanjun on 2024/7/15. // import Cocoa private enum KMMeasureType: Int { case line = 0 case multilines case polygon case rectangle } @objcMembers class KMMeasureSideVC: NSViewController { // Preview @IBOutlet private weak var previewImageBox: NSBox! @IBOutlet private weak var previewImageView: NSImageView! // Type @IBOutlet private weak var typeView: NSView! @IBOutlet weak var typeBoxView: NSView! @IBOutlet private weak var typeSubView1: NSView! @IBOutlet private weak var typeButton1: NSButton! @IBOutlet private weak var typeSubView2: NSView! @IBOutlet private weak var typeButton2: NSButton! @IBOutlet private weak var typeSubView3: NSView! @IBOutlet private weak var typeButton3: NSButton! @IBOutlet private weak var typeSubView4: NSView! @IBOutlet private weak var typeButton4: NSButton! @IBOutlet private weak var verticalLine1: NSBox! @IBOutlet private weak var verticalLine2: NSBox! @IBOutlet private weak var verticalLine3: NSBox! @IBOutlet private weak var type_TopConstant: NSLayoutConstraint! // Border & Fill Color @IBOutlet private weak var fillColorView: NSView! @IBOutlet private weak var fillColorLabel: NSTextField! @IBOutlet private weak var fillColorPickerView: KMColorPickerView! @IBOutlet private weak var fillColorViewTopConstraint: NSLayoutConstraint! // Opacity @IBOutlet private weak var opacityView: NSView! // 透明度 @IBOutlet private weak var opacityLabel: NSTextField! @IBOutlet private weak var opacitySlider: NSSlider! @IBOutlet private weak var opacityComboBox: KMComboBox! // Color @IBOutlet private weak var colorView: NSView! // 颜色 @IBOutlet private weak var colorTitleLabel: NSTextField! @IBOutlet private weak var borderColorLabel: NSTextField! @IBOutlet private weak var borderColorBox: NSBox! @IBOutlet private weak var borderColorPickerView: KMColorPickerView! // Thickness @IBOutlet private weak var borderAndLineView: NSView! // 边框 @IBOutlet private weak var borderLabel: NSTextField! @IBOutlet private weak var lineWidthSlider: NSSlider! @IBOutlet private weak var lineWidthComboBox: KMComboBox! // Line Style @IBOutlet private weak var lineStyle_View: NSView! @IBOutlet private weak var lineStyle_Label: NSTextField! @IBOutlet private weak var lineStyle_SolidButton: NSButton! @IBOutlet private weak var lineStyle_SolidImageView: NSImageView! @IBOutlet private weak var lineStyle_DottedButton: NSButton! @IBOutlet private weak var lineStyle_DottedImageView: NSImageView! @IBOutlet private weak var lineStyle_DashComBox: KMComboBox! @IBOutlet private weak var lineStyle_TopConstant: NSLayoutConstraint! // Start & End @IBOutlet private weak var startEnd_View: NSView! @IBOutlet private weak var startEnd_Label: NSTextField! @IBOutlet private weak var startEnd_StartPopUpButton: KMPopUpButton! @IBOutlet private weak var startEnd_EndPopUpButton: KMPopUpButton! @IBOutlet private weak var startEnd_TopConstant: NSLayoutConstraint! // Font @IBOutlet private weak var font_View: NSView! @IBOutlet private weak var font_Label: NSTextField! @IBOutlet private weak var font_PopUpButton: KMPopUpButton! @IBOutlet private weak var fontColorPickerView: KMColorPickerView! @IBOutlet private weak var font_StylePopUpButton: KMPopUpButton! @IBOutlet private weak var font_SizeComboBox: KMComboBox! var annotation: CPDFAnnotation? weak var pdfView: CPDFListView? var _annotationModel: CPDFAnnotationModel? var _annotations: [Any] = [] private var measureType: KMMeasureType = .line deinit { NotificationCenter.default.removeObserver(self) borderColorPickerView.target = nil borderColorPickerView.action = nil fillColorPickerView.target = nil fillColorPickerView.action = nil fontColorPickerView.target = nil fontColorPickerView.action = nil NSColorPanel.shared.setTarget(nil) NSColorPanel.shared.setAction(nil) } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. if annotations.count > 0 { if annotationType == .line { if pdfView?.toolMode == .measureToolMode { measureType = .line } } else if annotationType == .square { if pdfView?.toolMode == .measureToolMode { measureType = .rectangle } } else if annotationType == .polyGon { measureType = .polygon } else if annotationType == .polyLine { measureType = .multilines } } else { if annotationModel.annotationType == .line { measureType = .line } else if annotationModel.annotationType == .square { measureType = .rectangle } else if annotationModel.annotationType == .polyGon { measureType = .polygon } else if annotationModel.annotationType == .polyLine { measureType = .multilines } } languageLocalization() uiInitialize() layoutConstraintRefresh() updateViewColor() DistributedNotificationCenter.default().addObserver(self, selector: #selector(themeChanged(notification:)), name: NSNotification.Name("AppleInterfaceThemeChangedNotification"), object: nil) } @objc func themeChanged(notification: NSNotification) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [self] in updateViewColor() } } // MARK: Privately Methods private func languageLocalization() -> Void { colorTitleLabel.stringValue = NSLocalizedString("Color", comment: "") borderColorLabel.stringValue = NSLocalizedString("Line Color", comment: "") fillColorLabel.stringValue = NSLocalizedString("Fill Color", comment: "") opacityLabel.stringValue = NSLocalizedString("Opacity", comment: "") borderLabel.stringValue = NSLocalizedString("Line", comment: "") lineStyle_Label.stringValue = NSLocalizedString("Line Style", comment: "") startEnd_Label.stringValue = NSLocalizedString("Start & End", comment: "") font_Label.stringValue = NSLocalizedString("Font", comment: "") } private func uiInitialize() -> Void { borderColorPickerView.annotationType = .lineColors fillColorPickerView.annotationType = .lineFillColors borderColorPickerView.isCallColorPanelAction = true fillColorPickerView.isCallColorPanelAction = true fontColorPickerView.annotationType = .freeTextColors fontColorPickerView.isCallColorPanelAction = true self.typeView.isHidden = true borderColorLabel.textColor = KMAppearance.Layout.h0Color() borderColorLabel.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) fillColorLabel.textColor = KMAppearance.Layout.h0Color() fillColorLabel.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) opacityLabel.textColor = KMAppearance.Layout.h0Color() opacityLabel.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) borderLabel.textColor = KMAppearance.Layout.h0Color() borderLabel.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) lineStyle_Label.textColor = KMAppearance.Layout.h0Color() lineStyle_Label.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) startEnd_Label.textColor = KMAppearance.Layout.h0Color() startEnd_Label.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) font_Label.textColor = KMAppearance.Layout.h0Color() font_Label.font = NSFont(descriptor: NSFontDescriptor(name: "Segoe UI", size: 14.0).withSymbolicTraits(.bold), size: 14.0) ?? NSFont(name: "Segoe UI", size: 14.0) opacityComboBox.type = .none opacityComboBox.comboxRect = opacityComboBox.bounds lineWidthComboBox.type = .none lineWidthComboBox.comboxRect = lineWidthComboBox.bounds lineStyle_DashComBox.type = .none lineStyle_DashComBox.comboxRect = lineStyle_DashComBox.bounds font_PopUpButton.type = .arrowDown font_PopUpButton.removeAllItems() font_StylePopUpButton.type = .arrowDown font_StylePopUpButton.removeAllItems() font_SizeComboBox.type = .none font_SizeComboBox.comboxRect = font_SizeComboBox.bounds lineStyle_SolidImageView.image = NSImage(named: "KMImageNameLifeStyle") lineStyle_DottedImageView.image = NSImage(named: "KMImageNameLifeStyle2") lineStyle_DashComBox.isEnabled = false if annotationModel.measureDashPattern().count > 0 { lineStyle_DashComBox.stringValue = (annotationModel.measureDashPattern().first as! NSNumber).description } else { lineStyle_DashComBox.stringValue = "5" } annotationFontReload() if measureType == .line { previewImageView.image = NSImage(named: "ImageNameToolbarMeasureLine") startEnd_StartPopUpButton.type = .arrowDown startEnd_StartPopUpButton.removeAllItems() startEnd_EndPopUpButton.type = .arrowDown startEnd_EndPopUpButton.removeAllItems() let startMenu = NSMenu() _ = startMenu.addItem(withTitle: "", action: #selector(startMenuItemAction(_:)), target: self, tag: 0) _ = startMenu.addItem(withTitle: "", action: #selector(startMenuItemAction(_:)), target: self, tag: 1) _ = startMenu.addItem(withTitle: "", action: #selector(startMenuItemAction(_:)), target: self, tag: 2) _ = startMenu.addItem(withTitle: "", action: #selector(startMenuItemAction(_:)), target: self, tag: 3) _ = startMenu.addItem(withTitle: "", action: #selector(startMenuItemAction(_:)), target: self, tag: 4) _ = startMenu.addItem(withTitle: "", action: #selector(startMenuItemAction(_:)), target: self, tag: 5) startEnd_StartPopUpButton.menu = startMenu let endMenu = NSMenu() _ = endMenu.addItem(withTitle: "", action: #selector(endMenuItemAction(_:)), target: self, tag: 0) _ = endMenu.addItem(withTitle: "", action: #selector(endMenuItemAction(_:)), target: self, tag: 1) _ = endMenu.addItem(withTitle: "", action: #selector(endMenuItemAction(_:)), target: self, tag: 2) _ = endMenu.addItem(withTitle: "", action: #selector(endMenuItemAction(_:)), target: self, tag: 3) _ = endMenu.addItem(withTitle: "", action: #selector(endMenuItemAction(_:)), target: self, tag: 4) _ = endMenu.addItem(withTitle: "", action: #selector(endMenuItemAction(_:)), target: self, tag: 5) startEnd_EndPopUpButton.menu = endMenu let startPopMenu = startEnd_StartPopUpButton.menu let endPopMenu = startEnd_EndPopUpButton.menu let startLineStyle = annotationModel.measureStartLineStyle() let endLineStyle = annotationModel.measureEndLineStyle() let startArr = self.startLineStyle() let endArr = self.endLineStyle() for i in 0.. Void { verticalLine1.isHidden = false verticalLine2.isHidden = false verticalLine3.isHidden = false typeSubView1.backgroundColor(.clear) typeSubView2.backgroundColor(.clear) typeSubView3.backgroundColor(.clear) typeSubView4.backgroundColor(.clear) typeButton1.image = NSImage(named: "ImageNameToolbarMeasureLine") typeButton2.image = NSImage(named: "ImageNameToolbarPolyline") typeButton3.image = NSImage(named: "ImageNameToolbarPolygon") typeButton4.image = NSImage(named: "ImageNameToolbarMeasureSquare") // typeButton1.isEnabled = false // typeButton2.isEnabled = false // typeButton3.isEnabled = false // typeButton4.isEnabled = false if measureType == .line { verticalLine1.isHidden = true typeSubView1.backgroundColor(NSColor.km_init(hex: "#477EDE", alpha: 0.1)) typeButton1.isEnabled = true } else if measureType == .multilines { verticalLine1.isHidden = true verticalLine2.isHidden = true typeSubView2.backgroundColor(NSColor.km_init(hex: "#477EDE", alpha: 0.1)) typeButton2.isEnabled = true } else if measureType == .polygon { verticalLine2.isHidden = true verticalLine3.isHidden = true typeSubView3.backgroundColor(NSColor.km_init(hex: "#477EDE", alpha: 0.1)) typeButton3.isEnabled = false } else if measureType == .rectangle { verticalLine3.isHidden = true typeSubView4.backgroundColor(NSColor.km_init(hex: "#477EDE", alpha: 0.1)) } } private func borderColorViewRefresh() -> Void { borderColorPickerView.color = annotationModel.measureBorderColor() } private func lineColorViewRefresh() -> Void { fillColorPickerView.color = annotationModel.measureLineColor() } private func fontColorViewRefresh() -> Void { fontColorPickerView.color = annotationModel.measureFontColor() } private func opacityViewRefresh() -> Void { opacitySlider.floatValue = Float(annotationModel.measureOpacity()) opacitySlider.toolTip = "\(Int(Float(annotationModel.measureOpacity()) * 100))%" opacityComboBox.stringValue = "\(Int(Float(annotationModel.measureOpacity()) * 100))%" } private func thicknessViewRefresh() -> Void { lineWidthSlider.floatValue = Float(annotationModel.measureLineWidth()) lineWidthSlider.toolTip = String(format: "%.1f", Float(annotationModel.measureLineWidth())) lineWidthComboBox.stringValue = String(format: "%.1f", Float(annotationModel.measureLineWidth())) } private func lineStyleViewRefresh() -> Void { if annotationModel.measureLineStyle() == .solid { lineStyle_SolidButton.image = NSImage(named: "KMImageNameCheckboxRadiSel") lineStyle_DottedButton.image = NSImage(named: "KMImageNameCheckboxRadi") lineStyle_DashComBox.isEnabled = false } else { lineStyle_SolidButton.image = NSImage(named: "KMImageNameCheckboxRadi") lineStyle_DottedButton.image = NSImage(named: "KMImageNameCheckboxRadiSel") lineStyle_DashComBox.isEnabled = true } } private func layoutConstraintRefresh() -> Void { colorView.isHidden = false fillColorView.isHidden = false opacityView.isHidden = false borderAndLineView.isHidden = false lineStyle_View.isHidden = false startEnd_View.isHidden = false font_View.isHidden = false if measureType == .line { fillColorView.isHidden = true } else if measureType == .multilines { fillColorView.isHidden = true startEnd_View.isHidden = true } else if measureType == .polygon { startEnd_View.isHidden = true } else if measureType == .rectangle { startEnd_View.isHidden = true } fillColorViewTopConstraint.constant = !fillColorView.isHidden ? 92.0 : 10.0 lineStyle_TopConstant.constant = !lineStyle_View.isHidden ? 0.0 : -CGRectGetHeight(lineStyle_View.bounds) startEnd_TopConstant.constant = !startEnd_View.isHidden ? 0.0 : -CGRectGetHeight(startEnd_View.bounds) } private func setFontStyle(fontName: String, currentStyle style: String?) -> UInt { var selectIndex: UInt = 0 let menu = NSMenu() let fontStyleNames = CPDFFont.fontNames(forFamilyName: fontName) for i in 0.. [NSImage] { let size = NSSize(width: 100.0, height: 12.0) let image1 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 6.0, y: 6.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image2 = NSImage.image(with: size) { dstRect in let path = NSBezierPath() path.move(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 12.0, y: 6.0)) path.appendRect(NSRect(x: 6.0, y: 3.0, width: 6.0, height: 6.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image3 = NSImage.image(with: size) { dstRect in let path = NSBezierPath() path.move(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 12.0, y: 6.0)) path.appendOval(in: NSRect(x: 6.0, y: 3.0, width: 6.0, height: 6.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image4 = NSImage.image(with: size) { dstRect in let path = NSBezierPath() path.move(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 14.0, y: 6.0)) path.move(to: NSPoint(x: 14.0, y: 6.0)) path.line(to: NSPoint(x: 10.0, y: 10.0)) path.line(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 10.0, y: 2.0)) path.close() NSColor.labelColor.setStroke() path.lineWidth = 2.0 path.stroke() return true } let image5 = NSImage.image(with: size) { dstRect in let path = NSBezierPath() path.move(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 6.0, y: 6.0)) path.move(to: NSPoint(x: 15.0, y: 3.0)) path.line(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 15.0, y: 9.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image6 = NSImage.image(with: size) { dstRect in let path = NSBezierPath() path.move(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 6.0, y: 6.0)) path.move(to: NSPoint(x: 15.0, y: 3.0)) path.line(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 15.0, y: 9.0)) path.close() path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } return [image1, image5, image6, image2, image3, image4] } private func endLineStyle() -> [NSImage] { let size = NSSize(width: 100.0, height: 12.0) let image1 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 93.0-4, y: 6.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image2 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 87.0-4, y: 6.0)) path.appendRect(NSRect(x: 87.0-4, y: 3.0, width: 6.0, height: 6.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image3 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 87.0-4, y: 6.0)) path.appendOval(in: NSRect(x: 87.0-4, y: 3.0, width: 6.0, height: 6.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image4 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 87.0-4, y: 6.0)) path.move(to: NSPoint(x: 87.0-4, y: 6.0)) path.line(to: NSPoint(x: 91.0-4, y: 10.0)) path.line(to: NSPoint(x: 95.0-4, y: 6.0)) path.line(to: NSPoint(x: 91.0-4, y: 2.0)) path.close() NSColor.labelColor.setStroke() path.lineWidth = 2.0 path.stroke() return true } let image5 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 93.0-4, y: 6.0)) path.move(to: NSPoint(x: 84.0-4, y: 3.0)) path.line(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 84.0-4, y: 9.0)) path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } let image6 = NSImage.image(with: size) { rect in let path = NSBezierPath() path.move(to: NSPoint(x: 6.0, y: 6.0)) path.line(to: NSPoint(x: 93.0-4, y: 6.0)) path.move(to: NSPoint(x: 84.0-4, y: 3.0)) path.line(to: NSPoint(x: 93.0-4, y: 6.0)) path.line(to: NSPoint(x: 84.0-4, y: 9.0)) path.close() path.lineWidth = 2.0 NSColor.labelColor.setStroke() path.stroke() return true } return [image1, image5, image6, image2, image3, image4] } private func isNumericUsingNSRegularExpression(_ input: String) -> Bool { let pattern = "^[0-9]+$" do { let regex = try NSRegularExpression(pattern: pattern) let matches = regex.matches(in: input, range: NSRange(location: 0, length: input.utf16.count)) return matches.count > 0 } catch { print("Invalid regex pattern") return false } } // MARK: Publicly Methods // MARK: Action @IBAction func typeButtonAction(_ sender: NSButton) { } @IBAction func borderColorPickerViewAction(_ sender: Any) { var fillColor = NSColor.clear var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 if let borderColor = borderColorPickerView.color { borderColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) let color = NSColor(calibratedRed: red, green: green, blue: blue, alpha: opacity) fillColor = color } annotationModel.setMeasureBorderColor(fillColor) annotationModel.setMeasureOpacity(opacity) opacityViewRefresh() updateAnnotation() } @IBAction func fillColorPickerViewAction(_ sender: Any) { var fillColor = NSColor.clear var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 if let borderColor = fillColorPickerView.color { borderColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) let color = NSColor(calibratedRed: red, green: green, blue: blue, alpha: opacity) fillColor = color } if opacity == 0 { annotationModel.setMeasureLineColor(nil) } else { annotationModel.setMeasureLineColor(fillColor) } opacityViewRefresh() lineColorViewRefresh() updateAnnotation() } @IBAction func fontColorPickerViewAction(_ sender: Any) { var fillColor = NSColor.clear var red: CGFloat = 0.0, green: CGFloat = 0.0, blue: CGFloat = 0.0, opacity: CGFloat = 0.0 if let borderColor = fontColorPickerView.color { borderColor.usingColorSpaceName(.calibratedRGB)?.getRed(&red, green: &green, blue: &blue, alpha: &opacity) let color = NSColor(calibratedRed: red, green: green, blue: blue, alpha: opacity) fillColor = color } fontColorViewRefresh() annotationModel.setMeasureFontColor(fillColor) updateAnnotation() } @IBAction func customColorAction(_ sender: NSButton) { NSColorPanel.shared.setAction(nil) NSColorPanel.shared.setTarget(nil) NSColorPanel.shared.setTarget(self) NSColorPanel.shared.showsAlpha = true if sender.tag == 0 { NSColorPanel.shared.setAction(#selector(colorPanelAction1(_:))) } else if sender.tag == 1 { NSColorPanel.shared.setAction(#selector(colorPanelAction2(_:))) } else if sender.tag == 2 { NSColorPanel.shared.setAction(#selector(colorPanelAction3(_:))) } NSColorPanel.shared.orderFront(nil) } @IBAction func opacitySliderAction(_ sender: Any) { var opcity = CGFloat(opacitySlider.floatValue) if opcity == 0 { opcity = 0.0001 } annotationModel.setMeasureOpacity(opcity) opacityViewRefresh() updateAnnotation() } @IBAction func opacityComboBoxAction(_ sender: Any) { opacitySlider.floatValue = Float(opacityComboBox.floatValue / 100) var opcity = CGFloat(opacitySlider.floatValue) if opcity == 0 { opcity = 0.0001 } annotationModel.setMeasureOpacity(opcity) opacityViewRefresh() updateAnnotation() } @IBAction func thicknessSliderAction(_ sender: Any) { var thickness = CGFloat(lineWidthSlider.floatValue) annotationModel.setMeasureLineWidth(thickness) thicknessViewRefresh() updateAnnotation() } @IBAction func thicknessComboBoxAction(_ sender: Any) { lineWidthSlider.floatValue = Float(lineWidthComboBox.floatValue) let thickness = CGFloat(lineWidthSlider.floatValue) annotationModel.setMeasureLineWidth(thickness) thicknessViewRefresh() updateAnnotation() } @IBAction func lineStyleButtonAction(_ sender: NSButton) { if sender.tag == 0 { annotationModel.setMeasureLineStyle(.solid) } else { annotationModel.setMeasureLineStyle(.dashed) annotation?.setDashPattern(annotationModel.measureDashPattern()) } lineStyleViewRefresh() updateAnnotation() } @IBAction func startMenuItemAction(_ sender: NSMenuItem) { let startType: CPDFLineStyle = (CPDFLineStyle(rawValue: sender.tag) ?? CPDFLineStyle(rawValue: 0))! annotationModel.setMeasureStart(startType) updateAnnotation() } @IBAction func endMenuItemAction(_ sender: NSMenuItem) { let endType: CPDFLineStyle = (CPDFLineStyle(rawValue: sender.tag) ?? CPDFLineStyle(rawValue: 0))! annotationModel.setMeasureEnd(endType) updateAnnotation() } @IBAction func fontButtonAction(_ sender: NSButton) { let selectItem = font_PopUpButton.selectedItem guard let selectItem = selectItem else { return } let resultAtt = NSMutableAttributedString(attributedString: selectItem.attributedTitle!) let familyString = resultAtt.string let styleString = font_StylePopUpButton.selectedItem?.title ?? "" let attributeFontDescriptor = NSFontDescriptor(fontAttributes: [.family: familyString, .face: styleString as Any]) let fontSizeString = font_SizeComboBox.stringValue.replacingOccurrences(of: " pt", with: "") let fontModel = KMFontModel(fontName: familyString, fontWeight: styleString, fontSize: fontSizeString.stringToCGFloat(), fontColor: fontColorPickerView.color ?? .black, fontAlignment: .left, annotationType: annotationModel.annotationType) let fontWindowController = KMAnnotationFontWindowController.initWindowController(fontModel) fontWindowController.isHidenAlignmentLabel = true let window = fontWindowController.window fontWindowController.callback = { [weak self] model in self?.fontColorPickerView.color = model.fontColor DispatchQueue.global(qos: .default).async { [self] let fonts = CPDFFont.familyNames 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?.font_PopUpButton.menu = menu self?.font_PopUpButton.selectItem(at: selectedIndex) } } let selectedStyleIndex = self?.setFontStyle(fontName: model.fontName, currentStyle: model.fontWeight) ?? 0 self?.font_StylePopUpButton.selectItem(at: Int(selectedStyleIndex)) self?.font_SizeComboBox.stringValue = String(format: "%.f pt", model.fontSize) self?.annotationModel.setMeasureFontName(model.fontName) self?.annotationModel.setMeasureFontSize(model.fontSize) self?.annotationModel.setMeasureFontColor(model.fontColor) if self?.annotationModel.annotations != nil { self?.updateAnnotation() } } window?.orderFront(sender) } @IBAction func fontPopUpButtonAction(_ sender: NSPopUpButton) { guard let selectedItem = font_PopUpButton.selectedItem else { return } let resultAtt = NSMutableAttributedString(attributedString: selectedItem.attributedTitle!) let familyString = resultAtt.string let selectIndex = setFontStyle(fontName: familyString, currentStyle: nil) guard let styleString = font_StylePopUpButton.selectedItem?.title else { return } font_StylePopUpButton.selectItem(at: Int(selectIndex)) for tAnnotation in annotations { if tAnnotation is CPDFLineAnnotation { let newAnnotation = (tAnnotation as! CPDFLineAnnotation) newAnnotation.cFont = CPDFFont(familyName: familyString, fontStyle: styleString) } else if tAnnotation is CPDFPolygonAnnotation { let newAnnotation = (tAnnotation as! CPDFPolygonAnnotation) newAnnotation.cFont = CPDFFont(familyName: familyString, fontStyle: styleString) } else if tAnnotation is CPDFPolylineAnnotation { let newAnnotation = (tAnnotation as! CPDFPolylineAnnotation) newAnnotation.cFont = CPDFFont(familyName: familyString, fontStyle: styleString) } } self.annotationModel.setMeasureFontName(familyString) if annotations.count > 0 { pdfView?.setNeedsDisplay(annotation) } } @IBAction func fontSizeComboBoxAction(_ sender: NSComboBox) { if annotationModel.annotations != nil { for tAnnotation in annotations { if tAnnotation is CPDFLineAnnotation { let newAnnotation = (tAnnotation as! CPDFLineAnnotation) newAnnotation.fontSize = CGFloat(font_SizeComboBox.floatValue) } else if tAnnotation is CPDFPolygonAnnotation { let newAnnotation = (tAnnotation as! CPDFPolygonAnnotation) newAnnotation.fontSize = CGFloat(font_SizeComboBox.floatValue) } else if tAnnotation is CPDFPolylineAnnotation { let newAnnotation = (tAnnotation as! CPDFPolylineAnnotation) newAnnotation.fontSize = CGFloat(font_SizeComboBox.floatValue) } } } else { if annotationType == .line || annotationType == .polyGon || annotationType == .polyLine { if let data = annotationModel.measureFontName() { let font = NSFont(name: data, size: annotationModel.measureFontSize()) ?? NSFont.systemFont(ofSize: 16) let newFont = NSFont(name: font.fontName, size: CGFloat(font_SizeComboBox.floatValue)) if let newFont = newFont { annotationModel.setMeasureFontName(newFont.fontName) annotationModel.setMeasureFontSize(newFont.pointSize) } } } } updateAnnotation() } //字重 NSFontWeight @IBAction func fontStylePopUpButtonAction(_ sender: NSPopUpButton) { if let styleString = font_StylePopUpButton.selectedItem?.title { if annotationModel.annotations != nil { for tAnnotation in self.annotations { if tAnnotation is CPDFLineAnnotation { let newAnnotation = (tAnnotation as! CPDFLineAnnotation) newAnnotation.cFont = CPDFFont(familyName: newAnnotation.cFont.familyName, fontStyle: styleString) } else if tAnnotation is CPDFPolygonAnnotation { let newAnnotation = (tAnnotation as! CPDFPolygonAnnotation) newAnnotation.cFont = CPDFFont(familyName: newAnnotation.cFont.familyName, fontStyle: styleString) } else if tAnnotation is CPDFPolylineAnnotation { let newAnnotation = (tAnnotation as! CPDFPolylineAnnotation) newAnnotation.cFont = CPDFFont(familyName: newAnnotation.cFont.familyName, fontStyle: styleString) } } } else { if annotationType == .line || annotationType == .polyGon || annotationType == .polyLine { if let data = annotationModel.measureFontName() { let font = NSFont(name: data, size: annotationModel.measureFontSize()) ?? 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.setMeasureFontName(newFont.fontName) annotationModel.setMeasureFontSize(newFont.pointSize) } } } } } } updateAnnotation() } @IBAction func lineDashComboBoxAction(_ sender: NSComboBox) { let number = NSNumber(value: lineStyle_DashComBox.floatValue) var lineDashPattern: [Any] = annotationModel.measureDashPattern() let array: [NSNumber] if annotationModel.measureDashPattern() is [NSNumber] { if lineDashPattern.isEmpty { array = [number] } else { lineDashPattern[0] = number array = lineDashPattern as! [NSNumber] } } else { array = [number] } annotationModel.setMeasureDashPattern(array) updateAnnotation() } // MARK: Set & Get var annotations: [Any] { set { _annotations = newValue self.annotation = (newValue.first as? CPDFAnnotation) } get { return _annotations } } var annotationModel: CPDFAnnotationModel { get { return _annotationModel! } set { _annotationModel = newValue if _annotationModel?.annotations != nil { if annotationModel.annotations.count > 0 { annotations = _annotationModel?.annotations as! [CPDFAnnotation] } } } } var annotationType: CAnnotationType { get { if annotations.count > 0 { if let ann = annotation?.isKind(of: CPDFLineAnnotation.self), ann { if (annotation as! CPDFLineAnnotation).isMeasure { return .line } } else if let ann = annotation?.isKind(of: CPDFPolygonAnnotation.self), ann { if pdfView?.annotationType == .square { return .square } return .polyGon } else if let ann = annotation?.isKind(of: CPDFPolylineAnnotation.self), ann { return .polyLine } } else { return annotationModel.annotationType } return .unkown } } }