// // KMEditPDFPopToolBarController.swift // PDF Reader Pro // // Created by tangchao on 2024/6/18. // import Cocoa @objc enum KMEditPDFToolbarItemKey: Int { case color case fontStyle case fontAdd case fontReduce case fontBold case fontItalic case textAlignment case leftRotate case rightRotate case reverseX // 左右翻转 case reverseY // 上下翻转 case crop case replace case export case alignmentLeft case alignmentRight case alignmentCenterX case alignmentjustifiedX // 左右两端对齐 case alignmentTop case alignmentBottom case alignmentCenterY case alignmentjustifiedY // 上下两端对齐 case separator // 分割线 } class KMSeparatorLineView: NSView { var strokeColor: NSColor = .black { didSet { self.needsDisplay = true } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) let rect = self.bounds let ctx = NSGraphicsContext.current?.cgContext ctx?.saveGState() ctx?.setLineWidth(1) ctx?.setStrokeColor(self.strokeColor.cgColor) let startP = NSPoint(x: rect.size.width*0.5, y: 6+2) ctx?.move(to: startP) let endP = NSPoint(x: rect.size.width*0.5, y: rect.size.height-8) ctx?.addLine(to: endP) ctx?.strokePath() ctx?.restoreGState() } } struct KMEditPDFToolbarStyle: OptionSet { let rawValue: Int static var text = KMEditPDFToolbarStyle(rawValue: 1 << 0) static var image = KMEditPDFToolbarStyle(rawValue: 1 << 1) } class KMEditPDFToolbarItemView: NSView { private lazy var contentBox_: NSBox = { let view = NSBox() view.boxType = .custom view.titlePosition = .noTitle view.contentViewMargins = .zero view.borderWidth = 0 return view }() var view: NSView? { didSet { if let data = self.view { self.contentBox_.contentView = data } self.needsLayout = true } } var obj: AnyObject? convenience init() { self.init(frame: .zero) self.addSubview(self.contentBox_) } override func layout() { super.layout() let height = NSHeight(self.bounds) let width = NSWidth(self.bounds) // let boxFrame = self.contentBox_.contentView?.frame ?? .zero // let boxX = (width - boxFrame.size.width) * 0.5 // let boxY = (height - boxFrame.size.height) * 0.5 // self.contentBox_.frame = NSMakeRect(boxX, boxY, boxFrame.size.width, boxFrame.size.height) self.contentBox_.frame = self.bounds // KMPrint("-------- \(boxFrame)") } } class KMEditPDFColorView: NSView { lazy var box: NSBox = { let view = NSBox() view.boxType = .custom view.titlePosition = .noTitle view.contentViewMargins = .zero view.borderWidth = 1 view.cornerRadius = 4 view.borderColor = NSColor(hex: "#DFE1E5") return view }() lazy var colorBtn: NSButton = { let view = NSButton() view.isBordered = false view.title = "" view.wantsLayer = true view.layer?.cornerRadius = 10 view.layer?.backgroundColor = .black view.target = self view.action = #selector(buttonClick) return view }() lazy var plateBtn: NSButton = { let view = NSButton() view.isBordered = false view.title = "" view.wantsLayer = true view.layer?.cornerRadius = 10 view.layer?.masksToBounds = true view.image = NSImage(named: "view_color") return view }() override init(frame frameRect: NSRect) { super.init(frame: frameRect) self.initSubView() } required init?(coder: NSCoder) { super.init(coder: coder) self.initSubView() } convenience init() { self.init(frame: .init(x: 0, y: 0, width: 56, height: 32)) } func initSubView() { self.addSubview(self.box) self.box.contentView?.addSubview(self.colorBtn) self.box.contentView?.addSubview(self.plateBtn) } override func layout() { super.layout() let height = NSHeight(self.bounds) self.box.frame = self.bounds let btnWH: CGFloat = 20 let btnY: CGFloat = (height - btnWH) * 0.5 let colorX: CGFloat = 4 self.colorBtn.frame = NSMakeRect(colorX, btnY, btnWH, btnWH) let plateX: CGFloat = NSMaxX(self.colorBtn.frame) + 8 self.plateBtn.frame = NSMakeRect(plateX, btnY, btnWH, btnWH) } @objc func buttonClick(_ sender: NSButton) { } } @objc protocol KMEditPDFToolbarViewDelegate: NSObjectProtocol { @objc optional func numberOfItems(in toolbarView: KMEditPDFToolbarView) -> Int @objc optional func toolbarView(_ toolbarView: KMEditPDFToolbarView, viewFor index: Int) -> NSView? @objc optional func toolbarView(_ toolbarView: KMEditPDFToolbarView, sizeForItemAt index: Int) -> NSSize // @objc optional func toolbarView(_ toolbarView: KMEditPDFToolbarView, insetForSectionAt section: Int) -> NSEdgeInsets // @objc optional func toolbarView(_ toolbarView: KMEditPDFToolbarView, minimumLineSpacingForSectionAt section: Int) -> CGFloat // @objc optional func toolbarView(_ toolbarView: KMEditPDFToolbarView, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat } class KMEditPDFToolbarView: NSView { weak var delegate: KMEditPDFToolbarViewDelegate? convenience init() { self.init(frame: .zero) } var inset: NSEdgeInsets = NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) { didSet { self.needsLayout = true } } func reloadData() { for sv in self.subviews { sv.removeFromSuperview() } guard let num = self.delegate?.numberOfItems?(in: self) else { return } for i in 0 ..< num { if let view = self.delegate?.toolbarView?(self, viewFor: i) { self.addSubview(view) } } self.needsLayout = true } override func layout() { super.layout() let height = NSHeight(self.bounds) let leftMargin = self.inset.left let topMargin = self.inset.top var x = leftMargin let vSpace: CGFloat = 2 for (i, sv) in self.subviews.enumerated() { if let size = self.delegate?.toolbarView?(self, sizeForItemAt: i) { let y = topMargin var frame = NSRect(x: x, y: y, width: size.width, height: size.height) x += (size.width + vSpace) sv.frame = frame } } } } @objcMembers class KMEditPDFPopToolBarWindow: NSWindow { static let shared = KMEditPDFPopToolBarWindow() var style: KMEditPDFToolbarStyle = .text var isMultiple: Bool = false var itemClick: ((KMEditPDFToolbarItemKey, Any?)->Void)? convenience init() { let rect = NSRect(x: 0, y: 0, width: 400, height: 44) let styleMask: NSWindow.StyleMask = [.fullSizeContentView] self.init(contentRect: rect, styleMask: styleMask, backing: .buffered, defer: false) } override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) { super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag) let contentViewC = KMEditPDFPopToolBarController() self.contentViewController = contentViewC self.titlebarAppearsTransparent = true self.titleVisibility = .hidden // self.level = .popUpMenu // self.isMovableByWindowBackground = false self.isMovable = false self.contentView?.wantsLayer = true self.contentView?.layer?.cornerRadius = 4 self.contentView?.layer?.masksToBounds = true self.backgroundColor = .clear contentViewC.itemClick = { [weak self] itemKey, obj in self?.itemClick?(itemKey, obj) } } func show(relativeTo positioningRect: NSRect, of positioningView: NSView, preferredEdge: NSRectEdge) { let contentViewC = (self.contentViewController as? KMEditPDFPopToolBarController) var width: CGFloat = 392 if self.style.contains(.text) { if self.style.contains(.image) { // text + image contentViewC?.itemKeys = [.alignmentLeft, .alignmentCenterX, .alignmentRight, .alignmentjustifiedX, .alignmentTop, .alignmentCenterY, .alignmentBottom, .alignmentjustifiedY] width = 320 } else { // text if self.isMultiple { width = 478 contentViewC?.itemKeys = [.color, .fontStyle, .fontAdd, .fontReduce, .fontBold, .fontItalic, .textAlignment, .separator, .alignmentLeft, .alignmentTop] } else { width = 392 contentViewC?.itemKeys = [.color, .fontStyle, .fontAdd, .fontReduce, .fontBold, .fontItalic, .textAlignment] } } } else { if self.style.contains(.image) { // image if self.isMultiple { width = 396 contentViewC?.itemKeys = [.leftRotate, .rightRotate, .separator, .reverseX, .reverseY, .separator, .crop, .replace, .export, .separator, .alignmentLeft, .alignmentTop] } else { width = 304 contentViewC?.itemKeys = [.leftRotate, .rightRotate, .separator, .reverseX, .reverseY, .separator, .crop, .replace, .export] } } else { // none } } // var position = positioningView.convert(positioningRect.origin, to: nil) var position = NSEvent.mouseLocation position.y += 20 position.x -= 60 // self.setFrameOrigin(position) let frame = NSMakeRect(position.x, position.y, width, 44) self.setFrame(frame, display: true) self.contentViewController?.view.frame = NSMakeRect(0, 0, width, 44) self.orderFront(nil) // self.makeKeyAndOrderFront(nil) } override var isMainWindow: Bool { return true } override var isKeyWindow: Bool { return true } } class KMEditPDFPopToolBarController: NSViewController { deinit { KMPrint("KMEditPDFPopToolBarController deinit.") } convenience init() { self.init(nibName: "KMEditPDFPopToolBarController", bundle: nil) } var toolbarView: KMEditPDFToolbarView? var itemKeys: [KMEditPDFToolbarItemKey] = [] { didSet { self.toolbarView?.reloadData() } } var itemClick: ((KMEditPDFToolbarItemKey, Any?)->Void)? override func viewDidLoad() { super.viewDidLoad() // Do view setup here. self.view.wantsLayer = true self.view.layer?.backgroundColor = .white let toolbarView = KMEditPDFToolbarView() self.toolbarView = toolbarView toolbarView.frame = self.view.bounds toolbarView.autoresizingMask = [.width, .height] self.view.addSubview(toolbarView) toolbarView.delegate = self toolbarView.inset = .init(top: 6, left: 4, bottom: 0, right: 0) toolbarView.reloadData() } @objc func _buttonClick(_ sender: NSButton) { let idx = sender.tag if idx >= 0 && idx < self.itemKeys.count { self.itemClick?(self.itemKeys[idx], nil) } } } extension KMEditPDFPopToolBarController: KMEditPDFToolbarViewDelegate { func numberOfItems(in toolbarView: KMEditPDFToolbarView) -> Int { return self.itemKeys.count } func toolbarView(_ toolbarView: KMEditPDFToolbarView, viewFor index: Int) -> NSView? { let itemKey = self.itemKeys[index] if itemKey == .color { let colorView = KMEditPDFToolbarItemView() let view = KMEditPDFColorView() colorView.view = view return colorView } else if itemKey == .fontStyle { let fontStyleView = KMEditPDFToolbarItemView() let viewC = KMDesignSelect.init(withType: .Combox) viewC.isScrollPop = true fontStyleView.view = viewC.view fontStyleView.obj = viewC let familyNames = CPDFFont.familyNames viewC.removeAllItems() viewC.addItems(withObjectValues: familyNames) viewC.selectItem(at: 0) viewC.delete = self return fontStyleView } else if itemKey == .separator { let colorView = KMEditPDFToolbarItemView() let view = KMSeparatorLineView() view.strokeColor = NSColor(hex: "#DADBDE") colorView.view = view return colorView } let colorView = KMEditPDFToolbarItemView() let viewC = KMDesignButton(withType: .Image) colorView.view = viewC.view colorView.obj = viewC viewC.pagination() viewC.tag = index viewC.target = self viewC.action = #selector(_buttonClick) if itemKey == .fontAdd { viewC.image = NSImage(named: "KMImageNameEditPDFFontAdd")! } else if itemKey == .fontReduce { viewC.image = NSImage(named: "KMImageNameEditPDFFontReduce")! } else if itemKey == .fontBold { viewC.image = NSImage(named: "KMImageNameEditPDFFontBold")! } else if itemKey == .fontItalic { viewC.image = NSImage(named: "KMImageNameEditPDFFontItalic")! } else if itemKey == .textAlignment { viewC.image = NSImage(named: "KMImageNameEditPDFAlignCenterSelect")! } // 图片 else if itemKey == .leftRotate { viewC.image = NSImage(named: "KMImageNameEditPDFRotationLeft")! } else if itemKey == .rightRotate { viewC.image = NSImage(named: "KMImageNameEditPDFRotationRight")! } else if itemKey == .reverseX { viewC.image = NSImage(named: "KMImageNameEditPDFReverseX")! } else if itemKey == .reverseY { viewC.image = NSImage(named: "KMImageNameEditPDFReverseY")! } else if itemKey == .crop { viewC.image = NSImage(named: "KMImageNameEditPDFCrop")! } else if itemKey == .replace { viewC.image = NSImage(named: "KMImageNameEditPDFReplace")! } else if itemKey == .export { viewC.image = NSImage(named: "KMImageNameEditPDFExport")! } // 对齐 else if itemKey == .alignmentLeft { viewC.image = NSImage(named: "KMImageNameEditPDFImage45_1")! } else if itemKey == .alignmentCenterX { viewC.image = NSImage(named: "KMImageNameEditPDFImage46_1")! } else if itemKey == .alignmentRight { viewC.image = NSImage(named: "KMImageNameEditPDFImage47_1")! } else if itemKey == .alignmentjustifiedX { viewC.image = NSImage(named: "KMImageNameEditPDFImage21_1")! } else if itemKey == .alignmentTop { viewC.image = NSImage(named: "KMImageNameEditPDFImage48_1")! } else if itemKey == .alignmentCenterY { viewC.image = NSImage(named: "KMImageNameEditPDFImage49_1")! } else if itemKey == .alignmentBottom { viewC.image = NSImage(named: "KMImageNameEditPDFImage50_1")! } else if itemKey == .alignmentjustifiedY { viewC.image = NSImage(named: "KMImageNameEditPDFImage20_1")! } return colorView } func toolbarView(_ toolbarView: KMEditPDFToolbarView, sizeForItemAt index: Int) -> NSSize { let itemKey = self.itemKeys[index] if itemKey == .color { return NSMakeSize(56, 32) } else if itemKey == .fontStyle { return NSMakeSize(148, 32) } else if itemKey == .separator { return NSMakeSize(16, 32) } return NSMakeSize(32, 32) } } extension KMEditPDFPopToolBarController: KMSelectPopButtonDelegate { func km_comboBoxSelectionDidChange(_ obj: KMDesignSelect) { // if (self.lineWidthVC == obj) { // let index = self.lineWidthVC.indexOfSelectedItem // if index < 0 { // return // } // // let width = self.lineWidthVC.stringValue.replacingOccurrences(of: "pt", with: "") // if annotationModel.stampAnnotationType() == .signDot { // annotationModel.setNoteWidth(CGFloat(width.stringToCGFloat())*5) // annotationModel.setNoteHeight(CGFloat(width.stringToCGFloat())*5) // } else { // annotationModel.setLineWidth(width.stringToCGFloat()) // } // } else if (self.opacityVC == obj) { // let index = self.opacityVC.indexOfSelectedItem // if index < 0 { // return // } // // let opacity = self.opacityVC.stringValue.replacingOccurrences(of: "%", with: "") // self.opacitySlider.floatValue = Float(opacity.stringToCGFloat()/100) // annotationModel.setOpacity(opacity.stringToCGFloat()/100) // } // // refreshUI() // updateAnnotation() } func km_controlTextDidEndEditing(_ obj: KMDesignSelect) { } }