// // KMPDFSecToolbarController.swift // PDF Reader Pro // // Created by Niehaoyu on 2024/10/8. // import Cocoa import KMComponentLibrary @objc protocol KMPDFSecToolbarControllerDelegate: AnyObject { @objc optional func kmPDFSecToolbarControllerDidItemClicked(_ controller: KMPDFSecToolbarController, _ property: Any) @objc optional func kmPDFSecToolbarControllerDidSelectTextDidBeginEditing(_ controller: KMPDFSecToolbarController, _ view: ComponentSelect) @objc optional func kmPDFSecToolbarControllerDidSelectTextDidChange(_ controller: KMPDFSecToolbarController, _ view: ComponentSelect) @objc optional func kmPDFSecToolbarControllerDidSelectTextDidEndEditing(_ controller: KMPDFSecToolbarController, _ view: ComponentSelect) } class KMPDFSecToolbarController: NSViewController { @IBOutlet var contendBox: NSBox! @IBOutlet var infoContendView: NSView! @IBOutlet var rightContendView: NSView! @IBOutlet var moreToolsBGView: NSView! @IBOutlet var moreToolsView: ComponentDropdownTool! @IBOutlet var contendLeftConst: NSLayoutConstraint! @IBOutlet var contendViewWidthConst: NSLayoutConstraint! @IBOutlet var rightContendViewWidthConst: NSLayoutConstraint! private var _propertys: [NSObject] = [] var propertys: [NSObject] { get { return _propertys } } private var propertysWidthValue: CGFloat = 0 private var lastPropertyWidth: CGFloat = 0 private var hidePropertys: [Any] = [] private var rightPropertys: [Any] = [] var viewManager: KMPDFViewManager? weak open var delegate: KMPDFSecToolbarControllerDelegate? override func viewWillLayout() { super.viewWillLayout() let contendXValue = CGRectGetWidth(view.frame)/2 - propertysWidthValue/2 contendLeftConst.constant = max(0, contendXValue) if contendXValue <= 0 { contendViewWidthConst.constant = CGRectGetWidth(view.frame) } else { contendViewWidthConst.constant = propertysWidthValue } hidePropertys.removeAll() moreToolsBGView.isHidden = true let subviews = infoContendView.subviews for view in subviews { if CGRectGetMidX(view.frame) > CGRectGetWidth(self.view.frame) - lastPropertyWidth { moreToolsBGView.isHidden = false view.isHidden = true if view is ComponentButton { hidePropertys.append((view as! ComponentButton).properties) } else if view is ComponentDropdownTool { hidePropertys.append((view as! ComponentDropdownTool).properties) } } else { view.isHidden = false } } NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(setUpHidePropertys), object: nil) self.perform(#selector(setUpHidePropertys), with: nil, afterDelay: 0.35) } override func viewDidLoad() { super.viewDidLoad() // Do view setup here. setUpProperty() } //MARK: - Setup func setUpProperty() { contendBox.fillColor = ComponentLibrary.shared.getComponentColorFromKey("colorBg/layout-middle") moreToolsBGView.wantsLayer = true moreToolsBGView.layer?.backgroundColor = contendBox.fillColor.cgColor moreToolsBGView.isHidden = true moreToolsView.properties = ComponentDropdownToolProperty(state: .normal, leftIcon: NSImage(named: "toolbar_doubleArrow_right")) moreToolsView.delegate = self } @objc func setUpHidePropertys() { var menuItemArr: [ComponentMenuitemProperty] = [] for item in hidePropertys { if item is ComponentButtonProperty { let menuItem = ComponentMenuitemProperty(type: .normal, text: (item as! ComponentButtonProperty).buttonText ?? "", identifier: (item as! ComponentButtonProperty).identifier) menuItemArr.append(menuItem) } else if item is ComponentDropdownToolProperty { let menuItem = ComponentMenuitemProperty(type: .normal, text: (item as! ComponentDropdownToolProperty).text ?? "testtest", identifier: "") if let subItems = (item as! ComponentDropdownToolProperty).menuItemArr { menuItem.subPropertys = subItems } menuItemArr.append(menuItem) } } moreToolsView.properties.menuItemArr = menuItemArr } //MARK: - Getter func returnIDWithSubToolMode(_ subToolMode: KMPDFSubToolMode) -> String { if subToolMode == .Highlight { return KMPDFToolbar_highlight_Identifier } else if subToolMode == .Underline { return KMPDFToolbar_underline_Identifier } else if subToolMode == .Waveline { return KMPDFToolbar_waveline_Identifier } else if subToolMode == .Strikethrough { return KMPDFToolbar_strikethrough_Identifier } else if subToolMode == .Text { return KMPDFToolbar_text_Identifier } else if subToolMode == .Note { return KMPDFToolbar_note_Identifier } else if subToolMode == .Pen { return KMPDFToolbar_pen_Identifier } else if subToolMode == .Eraser { return KMPDFToolbar_eraser_Identifier } else if subToolMode == .Rectangle { return KMPDFToolbar_rectangle_Identifier } else if subToolMode == .Circle { return KMPDFToolbar_circle_Identifier } else if subToolMode == .Arrow { return KMPDFToolbar_arrow_Identifier } else if subToolMode == .Line { return KMPDFToolbar_line_Identifier } else if subToolMode == .Measure { return KMPDFToolbar_measure_Identifier } else if subToolMode == .Stamp { return KMPDFToolbar_stamp_Identifier } else if subToolMode == .Sign { return KMPDFToolbar_sign_Identifier } else if subToolMode == .Edit_text { return KMPDFToolbar_edit_text_Identifier } else if subToolMode == .Edit_Image { return KMPDFToolbar_edit_image_Identifier } else if subToolMode == .Edit_Link { return KMPDFToolbar_edit_link_Identifier } else if subToolMode == .Edit_Crop { return KMPDFToolbar_edit_crop_Identifier } else if subToolMode == .Fill_tick { return KMPDFToolbar_fill_tick_Identifier } else if subToolMode == .fill_fork { return KMPDFToolbar_fill_fork_Identifier } else if subToolMode == .fill_rectangle { return KMPDFToolbar_fill_rectangle_Identifier } else if subToolMode == .fill_line { return KMPDFToolbar_fill_line_Identifier } else if subToolMode == .fill_dot { return KMPDFToolbar_fill_dot_Identifier } else if subToolMode == .fill_date { return KMPDFToolbar_fill_date_Identifier } else if subToolMode == .fill_sign { return KMPDFToolbar_fill_sign_Identifier } else if subToolMode == .Form_text { return KMPDFToolbar_form_text_Identifier } else if subToolMode == .Form_checkbox { return KMPDFToolbar_form_checkbox_Identifier } else if subToolMode == .Form_radio { return KMPDFToolbar_form_radio_Identifier } else if subToolMode == .Form_list { return KMPDFToolbar_form_list_Identifier } else if subToolMode == .Form_dropdown { return KMPDFToolbar_form_dropdown_Identifier } else if subToolMode == .Form_OK { return KMPDFToolbar_form_OK_Identifier } else if subToolMode == .Form_digitalSign { return KMPDFToolbar_form_digitalSign_Identifier } else if subToolMode == .Redact { return KMPDFToolbar_protect_redact_Identifier } else if subToolMode == .Digital_Sign { return KMPDFToolbar_protect_digitalSign_Identifier } else if subToolMode == .Tool_OCR { return KMPDFToolbar_tools_OCR_Identifier } return "" } func returnSubToolModeWithID(_ identifier: String) -> KMPDFSubToolMode { if identifier == KMPDFToolbar_highlight_Identifier { return .Highlight } else if identifier == KMPDFToolbar_underline_Identifier { return .Underline } else if identifier == KMPDFToolbar_waveline_Identifier { return .Waveline } else if identifier == KMPDFToolbar_strikethrough_Identifier { return .Strikethrough } else if identifier == KMPDFToolbar_text_Identifier { return .Text } else if identifier == KMPDFToolbar_note_Identifier { return .Note } else if identifier == KMPDFToolbar_pen_Identifier { return .Pen } else if identifier == KMPDFToolbar_eraser_Identifier { return .Eraser } else if identifier == KMPDFToolbar_rectangle_Identifier { return .Rectangle } else if identifier == KMPDFToolbar_circle_Identifier { return .Circle } else if identifier == KMPDFToolbar_arrow_Identifier { return .Arrow } else if identifier == KMPDFToolbar_line_Identifier { return .Line } else if identifier == KMPDFToolbar_measure_Identifier { return .Measure } else if identifier == KMPDFToolbar_stamp_Identifier { return .Stamp } else if identifier == KMPDFToolbar_sign_Identifier { return .Sign } else if identifier == KMPDFToolbar_edit_text_Identifier { return .Edit_text } else if identifier == KMPDFToolbar_edit_image_Identifier { return .Edit_Image } else if identifier == KMPDFToolbar_edit_link_Identifier { return .Edit_Link } else if identifier == KMPDFToolbar_edit_crop_Identifier { return .Edit_Crop } else if identifier == KMPDFToolbar_fill_tick_Identifier { return .Fill_tick } else if identifier == KMPDFToolbar_fill_fork_Identifier { return .fill_fork } else if identifier == KMPDFToolbar_fill_rectangle_Identifier { return .fill_rectangle } else if identifier == KMPDFToolbar_fill_line_Identifier { return .fill_line } else if identifier == KMPDFToolbar_fill_dot_Identifier { return .fill_dot } else if identifier == KMPDFToolbar_fill_date_Identifier { return .fill_date } else if identifier == KMPDFToolbar_fill_sign_Identifier { return .fill_sign } else if identifier == KMPDFToolbar_form_text_Identifier { return .Form_text } else if identifier == KMPDFToolbar_form_checkbox_Identifier { return .Form_checkbox } else if identifier == KMPDFToolbar_form_radio_Identifier { return .Form_radio } else if identifier == KMPDFToolbar_form_list_Identifier { return .Form_list } else if identifier == KMPDFToolbar_form_dropdown_Identifier { return .Form_dropdown } else if identifier == KMPDFToolbar_form_OK_Identifier { return .Form_OK } else if identifier == KMPDFToolbar_form_digitalSign_Identifier { return .Form_digitalSign } else if identifier == KMPDFToolbar_protect_redact_Identifier { return .Redact } else if identifier == KMPDFToolbar_protect_digitalSign_Identifier { return .Digital_Sign } else if identifier == KMPDFToolbar_tools_OCR_Identifier { return .Tool_OCR } return .None } //MARK: - reload public func reloadMainPropertys(_ arr: [NSObject]) { _propertys.removeAll() for item in arr { _propertys.append(item) } setupMainView() } public func reloadRightPropertys(_ arr: [Any]) { rightPropertys.removeAll() for item in arr { rightPropertys.append(item) } setupRightView() } func setupMainView() { let subviews = infoContendView.subviews for view in subviews { view.removeFromSuperview() } var itemXvalue: CGFloat = 0 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, CGRectGetHeight(infoContendView.frame)/2-14, 28, 28) } else { button.frame = CGRectMake(itemXvalue, CGRectGetHeight(infoContendView.frame)/2-14, button.properties.propertyInfo.viewWidth, 28) } button.setTarget(self, action: #selector(buttonClicked(_:))) infoContendView.addSubview(button) itemXvalue += CGRectGetWidth(button.frame) itemXvalue += 12 lastPropertyWidth = CGRectGetWidth(button.frame) } else if property is ComponentDividerProperty { let divider = ComponentDivider.init() divider.frame = CGRectMake(itemXvalue, CGRectGetHeight(infoContendView.frame)/2-8, 1, 16) divider.properties = (property as! ComponentDividerProperty) infoContendView.addSubview(divider) itemXvalue += 1 itemXvalue += 12 lastPropertyWidth = CGRectGetWidth(divider.frame) } else if property is ComponentDropdownToolProperty { let dropdownTool = ComponentDropdownTool.init() dropdownTool.properties = property as! ComponentDropdownToolProperty dropdownTool.frame = CGRectMake(itemXvalue, CGRectGetHeight(infoContendView.frame)/2-14, dropdownTool.properties.propertyInfo.viewWidth, 28) dropdownTool.delegate = self infoContendView.addSubview(dropdownTool) itemXvalue += CGRectGetWidth(dropdownTool.frame) itemXvalue += 12 lastPropertyWidth = CGRectGetWidth(dropdownTool.frame) } else if property is ComponentSelectProperties { let selectView = ComponentSelect.init() selectView.properties = property as! ComponentSelectProperties selectView.frame = CGRectMake(itemXvalue, CGRectGetHeight(infoContendView.frame)/2-14, 144, 28) if let items = selectView.properties.menuItemArr { selectView.updateMenuItemsArr(items) } selectView.delegate = self infoContendView.addSubview(selectView) itemXvalue += CGRectGetWidth(selectView.frame) itemXvalue += 12 lastPropertyWidth = CGRectGetWidth(selectView.frame) } } itemXvalue -= 12 propertysWidthValue = itemXvalue contendViewWidthConst.constant = propertysWidthValue contendLeftConst.constant = CGRectGetWidth(view.frame)/2 - propertysWidthValue/2 } func setupRightView() { let subviews = rightContendView.subviews for view in subviews { view.removeFromSuperview() } var itemXvalue: CGFloat = 0 for property in rightPropertys { 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(_:))) rightContendView.addSubview(button) itemXvalue += CGRectGetWidth(button.frame) itemXvalue += 12 } else if property is ComponentDividerProperty { let divider = ComponentDivider.init() divider.frame = CGRectMake(itemXvalue, CGRectGetHeight(infoContendView.frame)/2-8, 1, 16) divider.properties = (property as! ComponentDividerProperty) rightContendView.addSubview(divider) itemXvalue += 1 itemXvalue += 12 } } itemXvalue -= 12 rightContendViewWidthConst.constant = itemXvalue } func reloadMainview() { let subviews = infoContendView.subviews for view in subviews { if view is ComponentButton { (view as! ComponentButton).reloadData() } else if view is ComponentDropdownTool { (view as! ComponentDropdownTool).reloadData() } else if view is ComponentSelect { (view as! ComponentSelect).reloadData() } } } func reloadRightview() { let subviews = rightContendView.subviews for view in subviews { if view is ComponentButton { (view as! ComponentButton).reloadData() } } } func refreshToolbarModeInfo() { guard let viewManager = self.viewManager else { return } let subviews = infoContendView.subviews for view in subviews { if view is ComponentButton { let item = (view as! ComponentButton) let resultID = self.returnIDWithSubToolMode(viewManager.subToolMode) if item.properties.identifier != resultID { if item.properties.state == .pressed { item.properties.state = .normal item.reloadData() } } else { if item.properties.state != .pressed { item.properties.state = .pressed item.reloadData() } } } } } //MARK: - @objc func buttonClicked(_ sender: ComponentButton) { let subToolMode = returnSubToolModeWithID(sender.properties.identifier) if subToolMode != .None { if viewManager?.subToolMode == subToolMode { viewManager?.subToolMode = .None } else { viewManager?.subToolMode = subToolMode } } else { viewManager?.subToolMode = .None } refreshToolbarModeInfo() delegate?.kmPDFSecToolbarControllerDidItemClicked?(self, sender.properties) } //MARK: - Mouse override func mouseDown(with event: NSEvent) { super.mouseDown(with: event) view.window?.makeFirstResponder(self) } } //MARK: - ComponentDropdownToolDelegate extension KMPDFSecToolbarController: ComponentDropdownToolDelegate { func componentDropdownToolDidShowPopupView(_ view: ComponentDropdownTool) { delegate?.kmPDFSecToolbarControllerDidItemClicked?(self, view.properties) } func componentDropdownToolDidClicked(_ view: ComponentDropdownTool, menuItem: ComponentMenuitemProperty?) { if let property = menuItem { property.itemSelected = false property.state = .normal delegate?.kmPDFSecToolbarControllerDidItemClicked?(self, property) } } } //MARK: - ComponentSelectDelegate extension KMPDFSecToolbarController: ComponentSelectDelegate { func componentSelectDidSelect(view: ComponentSelect?, menuItemProperty: ComponentMenuitemProperty?) { if let property = menuItemProperty { property.itemSelected = false property.state = .normal delegate?.kmPDFSecToolbarControllerDidItemClicked?(self, property) } } func componentSelectTextDidBeginEditing(_ view: ComponentSelect) { delegate?.kmPDFSecToolbarControllerDidSelectTextDidBeginEditing?(self, view) } func componentSelectTextDidChange(_ view: ComponentSelect) { delegate?.kmPDFSecToolbarControllerDidSelectTextDidChange?(self, view) } func componentSelectTextDidEndEditing(_ view: ComponentSelect) { delegate?.kmPDFSecToolbarControllerDidSelectTextDidEndEditing?(self, view) } }