// // KMPDFToolbarController.swift // PDF Reader Pro // // Created by Niehaoyu on 2024/10/8. // import Cocoa import KMComponentLibrary @objc protocol KMPDFToolbarControllerDelegate: AnyObject { @objc optional func kmPDFToolbarControllerDidToolbarItemClicked(_ controller: KMPDFToolbarController, _ itemIdentifier: String) } class KMPDFToolbarController: NSViewController { @IBOutlet var contendBox: NSBox! @IBOutlet var leftViewButton: ComponentButton! @IBOutlet var pageButton: ComponentButton! @IBOutlet var toolsView: ComponentDropdownTool! @IBOutlet var dividerView: ComponentDivider! @IBOutlet var selectZoom: ComponentSelectZoom! @IBOutlet var tabsView: ComponentTabs! @IBOutlet var rightToolsView: NSView! @IBOutlet var secondContendView: NSView! @IBOutlet var rightViewWidthConst: NSLayoutConstraint! private var customRightGroupView: ComponentGroup! private var undoRedo_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("Undo / Redo"), identifier: "undoRedo_Menuitem_PropertyKey") private var save_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("Save"), identifier: "save_Menuitem_PropertyKey") private var aiTools_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("AI Tools"), identifier: "aiTools_Menuitem_PropertyKey") private var batch_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("Batch"), identifier: "batch_Menuitem_PropertyKey") private var tts_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("TTS"), identifier: "tts_Menuitem_PropertyKey") private var ppt_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("Slide Show"), identifier: "ppt_Menuitem_PropertyKey") private var print_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("Print"), identifier: "print_Menuitem_PropertyKey") private var share_Menuitem_Property = ComponentMenuitemProperty(type: .normal, multipleSelect: true, itemSelected: false, text: KMLocalizedString("Share"), identifier: "share_Menuitem_PropertyKey") var pdfView: CPDFListView? var secondToolBar: KMPDFSecToolbarController = KMPDFSecToolbarController.init() weak open var delegate: KMPDFToolbarControllerDelegate? override func viewDidLoad() { super.viewDidLoad() // Do view setup here. contendBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle") setUpProperty() setUpRightViews() setupSecondToolbar() } func setUpProperty() { leftViewButton.properties = KMPDFToolbarManager.manager.viewProperty leftViewButton.setTarget(self, action: #selector(buttonClicked(_:))) pageButton.properties = KMPDFToolbarManager.manager.pageProperty pageButton.setTarget(self, action: #selector(buttonClicked(_:))) dividerView.properties = ComponentDividerProperty(type: .vertical, dash: false) toolsView.properties = KMPDFToolbarManager.manager.toolsProperty toolsView.delegate = self selectZoom.properties = KMPDFToolbarManager.manager.selectZoomProperty selectZoom.delegate = self tabsView.updateItemProperty([KMPDFToolbarManager.manager.markupMode_Property, KMPDFToolbarManager.manager.editMode_Property, KMPDFToolbarManager.manager.formMode_Property, KMPDFToolbarManager.manager.fillMode_Property, KMPDFToolbarManager.manager.convertMode_Property, KMPDFToolbarManager.manager.protectMode_Property, KMPDFToolbarManager.manager.toolsMode_Property]) tabsView.delegate = self } //MARK: - 刷新一级工具栏 func reloadToolbarTabsView() { KMPDFToolbarManager.manager.markupMode_Property.state = KMPDFManager.manager.toolMode == .Markup ? .pressed : .normal KMPDFToolbarManager.manager.editMode_Property.state = KMPDFManager.manager.toolMode == .Edit ? .pressed : .normal KMPDFToolbarManager.manager.formMode_Property.state = KMPDFManager.manager.toolMode == .Form ? .pressed : .normal KMPDFToolbarManager.manager.fillMode_Property.state = KMPDFManager.manager.toolMode == .Fill ? .pressed : .normal KMPDFToolbarManager.manager.convertMode_Property.state = KMPDFManager.manager.toolMode == .Convert ? .pressed : .normal KMPDFToolbarManager.manager.protectMode_Property.state = KMPDFManager.manager.toolMode == .Protect ? .pressed : .normal KMPDFToolbarManager.manager.toolsMode_Property.state = KMPDFManager.manager.toolMode == .Tools ? .pressed : .normal tabsView.refreshItems() } func reloadLeftIconView() { KMPDFToolbarManager.manager.viewProperty.state = KMPDFManager.manager.showView ? .pressed : .normal KMPDFToolbarManager.manager.viewProperty.isDisabled = false if KMPDFManager.manager.isPageEditMode { KMPDFToolbarManager.manager.viewProperty.isDisabled = true } leftViewButton.reloadData() } func reloadPageEditView() { KMPDFToolbarManager.manager.pageProperty.state = KMPDFManager.manager.isPageEditMode ? .pressed : .normal pageButton.reloadData() } func reloadSelectZoomView() { KMPDFToolbarManager.manager.selectZoomProperty.isDisabled = false if KMPDFManager.manager.isPageEditMode { KMPDFToolbarManager.manager.selectZoomProperty.isDisabled = true } if let pdfview = self.pdfView { KMPDFToolbarManager.manager.selectZoomProperty.text = (NSString(format: "%.0f", pdfview.scaleFactor * 100) as String) + "%" } selectZoom.reloadData() } //MARK: -右侧工具模块 func setUpRightViews() { let subviews = rightToolsView.subviews for view in subviews { view.removeFromSuperview() } var itemXvalue: CGFloat = 4 let _manager = KMPDFToolbarManager.manager var propertys: [Any] = [] var adddividerA: Bool = false var adddividerB: Bool = false for property in _manager.validRightPropertys { if property == _manager.undoProperty || property == _manager.redoProperty || property == _manager.saveProperty { adddividerA = true } else if property == _manager.aiToolsProperty || property == _manager.batchProperty || property == _manager.ttsProperty || property == _manager.pptProperty || property == _manager.printProperty || property == _manager.shareProperty { adddividerB = true } } for property in _manager.validRightPropertys { if adddividerA == true { if property == _manager.aiToolsProperty || property == _manager.batchProperty || property == _manager.ttsProperty || property == _manager.pptProperty || property == _manager.printProperty || property == _manager.shareProperty { propertys.append(ComponentDividerProperty(type: .vertical, dash: false)) adddividerA = false } } propertys.append(property) } if adddividerB == true { if propertys.last is ComponentDividerProperty { } else { propertys.append(ComponentDividerProperty(type: .vertical, dash: false)) } } propertys.append(_manager.rightViewProperty) for property in propertys { if property is ComponentButtonProperty { let buttonProperty = (property as! ComponentButtonProperty) let button = ComponentButton.init() button.properties = buttonProperty if buttonProperty.onlyIcon { button.frame = CGRectMake(itemXvalue, 0, 28, 28) } else { button.frame = CGRectMake(itemXvalue, 0, button.properties.propertyInfo.viewWidth, 28) } button.setTarget(self, action: #selector(buttonClicked(_:))) rightToolsView.addSubview(button) itemXvalue += CGRectGetWidth(button.frame) itemXvalue += 12 } else if property is ComponentDividerProperty { let divider = ComponentDivider.init() divider.frame = CGRectMake(itemXvalue, CGRectGetHeight(rightToolsView.frame)/2-8, 1, 16) divider.properties = (property as! ComponentDividerProperty) rightToolsView.addSubview(divider) itemXvalue += 1 itemXvalue += 12 } else if property is ComponentDropdownToolProperty { let dropdownTool = ComponentDropdownTool.init() dropdownTool.properties = property as! ComponentDropdownToolProperty dropdownTool.frame = CGRectMake(itemXvalue, 0, 28, 28) dropdownTool.delegate = self rightToolsView.addSubview(dropdownTool) itemXvalue += CGRectGetWidth(dropdownTool.frame) itemXvalue += 12 } } itemXvalue -= 12 rightViewWidthConst.constant = itemXvalue } //MARK: - 二级工具栏 func setupSecondToolbar() { secondToolBar.view.frame = secondContendView.bounds secondToolBar.delegate = self secondToolBar.view.autoresizingMask = [.width, .height] secondContendView.addSubview(secondToolBar.view) } func reloadSecondToolbar() { let _manager = KMPDFToolbarManager.manager if KMPDFManager.manager.isPageEditMode { secondToolBar.reloadMainPropertys(_manager.getSubToolbarItems(isPageEditMode: true)) secondToolBar.reloadRightPropertys([_manager.page_Reduce_Property, _manager.page_Increase_Property]) } else { secondToolBar.reloadMainPropertys(_manager.getSubToolbarItems(KMPDFManager.manager.toolMode)) secondToolBar.reloadRightPropertys([]) } } //只刷新Item状态 func refreshSecondToolbarItemsState() { secondToolBar.refreshMainview() secondToolBar.refreshRightview() } //MARK: - reloadData func reloadData() { reloadLeftIconView() reloadPageEditView() reloadToolsView() reloadSelectZoomView() reloadToolbarTabsView() reloadSecondToolbar() } //MARK: - 刷新tools工具 func reloadToolsView() { KMPDFToolbarManager.manager.reloadToolsData() toolsView.reloadData() } //MARK: - Action @objc func buttonClicked(_ sender: ComponentButton) { if sender.properties == KMPDFToolbarManager.manager.viewProperty { KMPDFManager.manager.showView = !KMPDFManager.manager.showView sender.properties.state = KMPDFManager.manager.showView ? .pressed : .normal sender.reloadData() } else if sender.properties == KMPDFToolbarManager.manager.pageProperty { KMPDFManager.manager.isPageEditMode = !KMPDFManager.manager.isPageEditMode sender.properties.state = KMPDFManager.manager.isPageEditMode ? .pressed : .normal sender.reloadData() KMPDFManager.manager.toolMode = .None } delegate?.kmPDFToolbarControllerDidToolbarItemClicked?(self, sender.properties.identifier) reloadData() } //MARK: - 自定义工具栏 func showPageTurnMenuWithPoint(_ point: CGPoint) { if (customRightGroupView?.superview) != nil { return } undoRedo_Menuitem_Property.itemSelected = false save_Menuitem_Property.itemSelected = false aiTools_Menuitem_Property.itemSelected = false batch_Menuitem_Property.itemSelected = false tts_Menuitem_Property.itemSelected = false ppt_Menuitem_Property.itemSelected = false print_Menuitem_Property.itemSelected = false share_Menuitem_Property.itemSelected = false let _manager = KMPDFToolbarManager.manager for property in _manager.validRightPropertys { if property == _manager.undoProperty || property == _manager.redoProperty { undoRedo_Menuitem_Property.itemSelected = true } else if property == _manager.saveProperty { save_Menuitem_Property.itemSelected = true } else if property == _manager.aiToolsProperty { aiTools_Menuitem_Property.itemSelected = true } else if property == _manager.batchProperty { batch_Menuitem_Property.itemSelected = true } else if property == _manager.ttsProperty { tts_Menuitem_Property.itemSelected = true } else if property == _manager.pptProperty { ppt_Menuitem_Property.itemSelected = true } else if property == _manager.printProperty { print_Menuitem_Property.itemSelected = true } else if property == _manager.shareProperty { share_Menuitem_Property.itemSelected = true } } var items: [ComponentMenuitemProperty] = [ComponentMenuitemProperty.header(KMLocalizedString("Show Right Tools")), undoRedo_Menuitem_Property, save_Menuitem_Property, ComponentMenuitemProperty.divider(), aiTools_Menuitem_Property, batch_Menuitem_Property, tts_Menuitem_Property, ppt_Menuitem_Property, print_Menuitem_Property, share_Menuitem_Property] var viewHeight: CGFloat = 8.0 for item in items { item.state = .normal if item.type == .normal { viewHeight += 36 } else if item.type == .divider { viewHeight += 8 } else if item.type == .header { viewHeight += 36 } } if customRightGroupView == nil { customRightGroupView = ComponentGroup.createFromNib(in: ComponentLibrary.shared.componentBundle()) } customRightGroupView.clickedAutoHide = false customRightGroupView?.frame = CGRectMake(0, 0, 160, viewHeight) customRightGroupView?.reloadData() customRightGroupView.groupDelegate = self customRightGroupView.showWithPoint(CGPoint(x: point.x, y: point.y-viewHeight), relativeTo: self.contendBox) customRightGroupView?.updateGroupInfo(items) refreshRightMenuState() } func hideGroupView() { customRightGroupView?.removeGroupView() } func refreshRightMenuState() { let totalItems: [ComponentMenuitemProperty] = [undoRedo_Menuitem_Property, save_Menuitem_Property, aiTools_Menuitem_Property, batch_Menuitem_Property, tts_Menuitem_Property, ppt_Menuitem_Property, print_Menuitem_Property, share_Menuitem_Property] var selectedCount = 0 for item in totalItems { if item.itemSelected == true { selectedCount += 1 } } var maxCount = 6 if undoRedo_Menuitem_Property.itemSelected == true { maxCount = 5 } if selectedCount == maxCount { for item in totalItems { if item.itemSelected == false { item.isDisabled = true } } } else { for item in totalItems { item.isDisabled = false } } if selectedCount == 5 && undoRedo_Menuitem_Property.itemSelected == false { //特殊情况,UndoRedo占两个空位 undoRedo_Menuitem_Property.isDisabled = true } for item in totalItems { NotificationCenter.default.post(name: Notification.Name(rawValue: ComponentMenuItemUpdatedKey), object: item.identifier) } } //MARK: - MouseEvent override func rightMouseUp(with event: NSEvent) { super.rightMouseUp(with: event) let point = event.locationInWindow showPageTurnMenuWithPoint(point) } } //MARK: - ComponentDropdownToolDelegate:工具模式 extension KMPDFToolbarController: ComponentDropdownToolDelegate { func componentDropdownToolDidClicked(_ view: ComponentDropdownTool, menuItem: ComponentMenuitemProperty?) { for item in KMPDFToolbarManager.manager.toolsProperty.menuItemArr ?? [] { item.itemSelected = false item.state = .normal } menuItem?.itemSelected = true if menuItem == KMPDFToolbarManager.manager.tools_selectProperty { KMPDFManager.manager.viewToolsType = .Select } else if menuItem == KMPDFToolbarManager.manager.tools_scrollProperty { KMPDFManager.manager.viewToolsType = .Scroll } else if menuItem == KMPDFToolbarManager.manager.tools_contentProperty { KMPDFManager.manager.viewToolsType = .Content_Selection } else if menuItem == KMPDFToolbarManager.manager.tools_magnifyProperty { KMPDFManager.manager.viewToolsType = .Magnify } else if menuItem == KMPDFToolbarManager.manager.tools_areaProperty { KMPDFManager.manager.viewToolsType = .AreaZoom } reloadToolsView() } } //MARK: - ComponentSelectZoomDelegate:缩放比例 extension KMPDFToolbarController: ComponentSelectZoomDelegate { func componentSelectZoomDidReduce(view: ComponentSelectZoom) { let zoomSting = view.properties.text var scale = CGFloat((NSString(string: zoomSting)).floatValue / 100.0) switch scale { case 0...0.25: scale = 0 case 0.25...3: scale -= 0.25 case 3.1...10: scale -= 0.4 case 10.1...100: scale -= 1 default: scale -= 1 } pdfView?.scaleFactor = scale } func componentSelectZoomDidSelect(view: ComponentSelectZoom?, menuItemProperty: ComponentMenuitemProperty?) { if menuItemProperty?.identifier == KMPDFToolbar_Zoom_AdapWidth_Identifier { if pdfView?.scaleFactor != 1.0 { pdfView?.scaleFactor = 1.0 pdfView?.autoScales = false } } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_AdapPage_Identifier { let pageHeight = pdfView?.currentPage()!.size.height let pdfviewHeight = pdfView?.bounds.size.height pdfView?.scaleFactor = pdfviewHeight!/pageHeight! pdfView?.autoScales = false } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_ActualSize_Identifier { pdfView?.autoScales = true } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_10_Identifier { pdfView?.scaleFactor = 0.1 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_25_Identifier { pdfView?.scaleFactor = 0.25 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_50_Identifier { pdfView?.scaleFactor = 0.5 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_75_Identifier { pdfView?.scaleFactor = 0.75 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_100_Identifier { pdfView?.scaleFactor = 1.0 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_150_Identifier { pdfView?.scaleFactor = 1.5 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_200_Identifier { pdfView?.scaleFactor = 2.0 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_400_Identifier { pdfView?.scaleFactor = 4.0 } else if menuItemProperty?.identifier == KMPDFToolbar_Zoom_800_Identifier { pdfView?.scaleFactor = 8.0 } } func componentSelectZoomDidAdd(view: ComponentSelectZoom) { let zoomSting = view.properties.text var scale = CGFloat((NSString(string: zoomSting)).floatValue / 100.0) switch scale { case 0...0.25: scale += 0.25 case 0.25...3: scale += 0.25 case 3.1...10: scale += 0.4 case 10.1...100: scale += 1 default: scale += 1 } pdfView?.scaleFactor = scale } } //MARK: - ComponentTabsDelegate extension KMPDFToolbarController: ComponentTabsDelegate { func componentTabsDidSelected(_ view: ComponentTabs, _ property: ComponentTabsProperty) { let _manager = KMPDFManager.manager _manager.viewToolsType = .Select _manager.isPageEditMode = false if property == KMPDFToolbarManager.manager.markupMode_Property { if _manager.toolMode == .Markup { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Markup } } else if property == KMPDFToolbarManager.manager.editMode_Property { if _manager.toolMode == .Edit { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Edit } } else if property == KMPDFToolbarManager.manager.formMode_Property { if _manager.toolMode == .Form { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Form } } else if property == KMPDFToolbarManager.manager.fillMode_Property { if _manager.toolMode == .Fill { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Fill } } else if property == KMPDFToolbarManager.manager.convertMode_Property { if _manager.toolMode == .Convert { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Convert } } else if property == KMPDFToolbarManager.manager.protectMode_Property { if _manager.toolMode == .Protect { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Protect } } else if property == KMPDFToolbarManager.manager.toolsMode_Property { if _manager.toolMode == .Tools { _manager.toolMode = .None property.state = .normal view.refreshItems() } else { _manager.toolMode = .Tools } } delegate?.kmPDFToolbarControllerDidToolbarItemClicked?(self, property.identifier) reloadData() } } //MARK: - KMPDFSecToolbarControllerDelegate:二级工具栏 extension KMPDFToolbarController: KMPDFSecToolbarControllerDelegate { func kmPDFSecToolbarControllerDidItemClicked(_ controller: KMPDFSecToolbarController, _ property: Any) { if let value = property as? ComponentButtonProperty { delegate?.kmPDFToolbarControllerDidToolbarItemClicked?(self, value.identifier) } else if let value = property as? ComponentMenuitemProperty { delegate?.kmPDFToolbarControllerDidToolbarItemClicked?(self, value.identifier) } } } //MARK: - ComponentGroupDelegate:右侧工具栏 extension KMPDFToolbarController: ComponentGroupDelegate { func componentGroupDidSelect(group: ComponentGroup?, menuItemProperty: ComponentMenuitemProperty?) { let _manager = KMPDFToolbarManager.manager var validItems:[NSObject] = [] if undoRedo_Menuitem_Property.itemSelected { validItems.append(_manager.undoProperty) validItems.append(_manager.redoProperty) } if save_Menuitem_Property.itemSelected { validItems.append(_manager.saveProperty) } if aiTools_Menuitem_Property.itemSelected { validItems.append(_manager.aiToolsProperty) } if batch_Menuitem_Property.itemSelected { validItems.append(_manager.batchProperty) } if tts_Menuitem_Property.itemSelected { validItems.append(_manager.ttsProperty) } if ppt_Menuitem_Property.itemSelected { validItems.append(_manager.pptProperty) } if print_Menuitem_Property.itemSelected { validItems.append(_manager.printProperty) } if share_Menuitem_Property.itemSelected { validItems.append(_manager.shareProperty) } let sortArray = _manager.totalRightPropertys let sortedArray = validItems.sorted { guard let indexA = sortArray.firstIndex(of: $0 as NSObject), let indexB = sortArray.firstIndex(of: $1 as NSObject) else { return false } return indexA < indexB } _manager.validRightPropertys = sortedArray setUpRightViews() refreshRightMenuState() } }