// // KMCropPropertyController.swift // PDF Reader Pro // // Created by Niehaoyu on 2024/11/20. // import Cocoa import KMComponentLibrary @objc protocol KMCropPropertyControllerDelegate: AnyObject { @objc optional func kmCropControllerDidCrop(_ controller: KMCropPropertyController, _ cropRect: CGRect, _ view: KMPageRangeSelectView) @objc optional func kmCropControllerDidCropSeparate(_ controller: KMCropPropertyController, _ view: KMPageRangeSelectView) @objc optional func kmCropControllerDidCropAuto(_ controller: KMCropPropertyController, _ view: KMPageRangeSelectView) } class KMCropPropertyController: NSViewController { @IBOutlet var contendView: NSView! //White Margin @IBOutlet var whiteMarginBGView: NSView! @IBOutlet var whiteMarginLabel: NSTextField! @IBOutlet var separateLabel: NSTextField! @IBOutlet var separateTip: ComponentToolTipsHelp! @IBOutlet var separateSwitch: ComponentSwitch! @IBOutlet var autoLabel: NSTextField! @IBOutlet var autoTipsView: ComponentToolTipsHelp! @IBOutlet var autoSwitch: ComponentSwitch! //PageSize @IBOutlet var pageSizeBGView: NSView! @IBOutlet var pageSizeLabel: NSTextField! @IBOutlet var sizeSyncButton: ComponentButton! @IBOutlet var sizeWidthInput: ComponentInputNumber! @IBOutlet var sizeHeightInput: ComponentInputNumber! //PageMargin @IBOutlet var pageMarginBGView: NSView! @IBOutlet var pageMarginLabel: NSTextField! @IBOutlet var pageLeftInput: ComponentInputNumber! @IBOutlet var pageTopInput: ComponentInputNumber! @IBOutlet var pageRightInput: ComponentInputNumber! @IBOutlet var pageBottomInput: ComponentInputNumber! //PageRange @IBOutlet var pageRangeBGView: NSView! @IBOutlet var pageRangeLabel: NSTextField! @IBOutlet var pangeRangeSelectView: KMPageRangeSelectView! @IBOutlet var cropButton: ComponentButton! private var _cropSeparateOn: Bool = false private var _cropAutoOn: Bool = false private var _syncChangeBounds: Bool = false //同步修改宽高 weak open var delegate: KMCropPropertyControllerDelegate? public var pdfView: CPDFListView? override func viewDidLoad() { super.viewDidLoad() // Do view setup here. cropSeparateOn = UserDefaults.standard.bool(forKey: "CropSeparateOnKey") cropAutoOn = UserDefaults.standard.bool(forKey: "CropAutoOnKey") if UserDefaults.standard.object(forKey: "CropSyncChangeBoundsKey") == nil { UserDefaults.standard.setValue(true, forKey: "CropSyncChangeBoundsKey") } syncChangeBounds = UserDefaults.standard.bool(forKey: "CropSyncChangeBoundsKey") setupProperty() reloadData() } //MARK: - Setter and Getter public var cropSeparateOn : Bool { get { return _cropSeparateOn } set { _cropSeparateOn = newValue UserDefaults.standard.setValue(_cropSeparateOn, forKey: "CropSeparateOnKey") } } public var cropAutoOn : Bool { get { return _cropAutoOn } set { _cropAutoOn = newValue UserDefaults.standard.setValue(_cropAutoOn, forKey: "CropAutoOnKey") } } public var syncChangeBounds : Bool { get { return _syncChangeBounds } set { _syncChangeBounds = newValue UserDefaults.standard.setValue(_syncChangeBounds, forKey: "CropSyncChangeBoundsKey") } } func setupProperty() { //White Margin whiteMarginLabel.stringValue = KMLocalizedString("Crop White Margins") whiteMarginLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") whiteMarginLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") separateLabel.stringValue = KMLocalizedString("Separate") separateLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-form/colorText-label") separateLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-regular") separateSwitch.properties = ComponentSwitchProperty(size: .s, open: false, isDisabled: false) separateSwitch.setTarget(self, action: #selector(switchAction(_:))) autoLabel.stringValue = KMLocalizedString("Auto") autoLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("comp-form/colorText-label") autoLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-m-regular") separateTip.toolTip = KMLocalizedString("separateTip tooltips") autoTipsView.toolTip = KMLocalizedString("autoTipsView tooltips") autoSwitch.properties = ComponentSwitchProperty(size: .s, open: false, isDisabled: false) autoSwitch.setTarget(self, action: #selector(switchAction(_:))) //PageSize whiteMarginLabel.stringValue = KMLocalizedString("Crop Page Size") whiteMarginLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") whiteMarginLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") sizeSyncButton.properties = ComponentButtonProperty(type: .text_gray, size: .xxs, onlyIcon: true, icon: NSImage(named: "sync_Change_unlock"), keepPressState: true) sizeSyncButton.properties.propertyInfo.leftIcon_press = NSImage(named: "sync_Change_lock") sizeSyncButton.setTarget(self, action: #selector(sizeSyncButtonClicked(_:))) sizeSyncButton.reloadData() sizeWidthInput.properties = ComponentInputNumberProperty(alignment: .center, size: .s, state: .normal, showPrefix: true, leftIcon: NSImage(named: "w_icon"), minSize: 0, maxSize: 1000, text:"100") sizeWidthInput.delegate = self sizeHeightInput.properties = ComponentInputNumberProperty(alignment: .center, size: .s, state: .normal, showPrefix: true, leftIcon: NSImage(named: "h_icon"), minSize: 0, maxSize: 1000, text:"100") sizeHeightInput.delegate = self //PageMargin whiteMarginLabel.stringValue = KMLocalizedString("Crop Page Margins") whiteMarginLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") whiteMarginLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") pageLeftInput.properties = ComponentInputNumberProperty(size: .s, state: .normal, minSize: 0, maxSize: 1000, text:"0") pageTopInput.properties = ComponentInputNumberProperty(size: .s, state: .normal, minSize: 0, maxSize: 1000, text:"0") pageRightInput.properties = ComponentInputNumberProperty(size: .s, state: .normal, minSize: 0, maxSize: 1000, text:"0") pageBottomInput.properties = ComponentInputNumberProperty(size: .s, state: .normal, minSize: 0, maxSize: 1000, text:"0") pageLeftInput.delegate = self pageTopInput.delegate = self pageRightInput.delegate = self pageBottomInput.delegate = self //PageRange pageRangeLabel.stringValue = KMLocalizedString("Page Range") pageRangeLabel.textColor = ComponentLibrary.shared.getComponentColorFromKey("colorText/2") pageRangeLabel.font = ComponentLibrary.shared.getFontFromKey("mac/body-s-medium") cropButton.properties = ComponentButtonProperty(type: .primary, size: .m, buttonText: KMLocalizedString("Apply"), keepPressState: false) cropButton.setTarget(self, action: #selector(cropButtonClicked(_:))) } func reloadData() { guard let pdfView = self.pdfView else { return } guard let page = pdfView.currentSelectionPage() else { return } let pageBounds = page.bounds let selectionRect = pdfView.selectionRect //White Margin separateSwitch.properties.open = cropSeparateOn separateSwitch.reloadData() autoSwitch.properties.open = cropAutoOn autoSwitch.reloadData() //PageSize sizeWidthInput.properties.maxSize = Int(pageBounds.size.width) sizeWidthInput.properties.text = String(format: "%.0f", selectionRect.size.width) sizeWidthInput.reloadData() sizeHeightInput.properties.maxSize = Int(pageBounds.size.height) sizeHeightInput.properties.text = String(format: "%.0f", selectionRect.size.height) sizeHeightInput.reloadData() if syncChangeBounds { sizeSyncButton.properties.state = .pressed } else { sizeSyncButton.properties.state = .normal } sizeSyncButton.reloadData() //PageMargin pageLeftInput.properties.maxSize = Int(pageBounds.size.width) pageLeftInput.properties.text = String(format: "%.0f", selectionRect.origin.x) pageLeftInput.reloadData() pageRightInput.properties.maxSize = Int(pageBounds.size.width) pageRightInput.properties.text = String(format: "%.0f", pageBounds.size.width - CGRectGetMaxX(selectionRect)) pageRightInput.reloadData() pageTopInput.properties.maxSize = Int(pageBounds.size.height) pageTopInput.properties.text = String(format: "%.0f", pageBounds.size.height - CGRectGetMaxY(selectionRect)) pageTopInput.reloadData() pageBottomInput.properties.maxSize = Int(pageBounds.size.height) pageBottomInput.properties.text = String(format: "%.0f", selectionRect.origin.y) pageBottomInput.reloadData() //PageRange if CGRectEqualToRect(pageBounds, selectionRect) { cropButton.properties.isDisabled = true } else { cropButton.properties.isDisabled = false } cropButton.reloadData() } //MARK: - Action @objc func sizeSyncButtonClicked(_ sender: ComponentButton) { syncChangeBounds = !syncChangeBounds reloadData() } @objc func cropButtonClicked(_ sender: ComponentButton) { if cropSeparateOn { delegate?.kmCropControllerDidCropSeparate?(self, pangeRangeSelectView) } else if cropAutoOn { delegate?.kmCropControllerDidCropAuto?(self, pangeRangeSelectView) } else { delegate?.kmCropControllerDidCrop?(self, pdfView?.selectionRect ?? CGRectZero, pangeRangeSelectView) } } @objc func switchAction(_ sender: ComponentSwitch) { guard let pdfView = self.pdfView else { return } guard let page = pdfView.document.page(at: 0) else { return } if sender == separateSwitch { cropSeparateOn = sender.properties.open cropAutoOn = false let rect = KMCropTools.getPageForegroundBox(page) pdfView.selectionRect = rect pdfView.setNeedsDisplayForVisiblePages() } else if sender == autoSwitch { cropAutoOn = sender.properties.open cropSeparateOn = false let rect = KMCropTools.getPageForegroundBox(page) pdfView.selectionRect = rect pdfView.setNeedsDisplayForVisiblePages() } reloadData() } } //MARK: - ComponentInputNumberDelegate extension KMCropPropertyController: ComponentInputNumberDelegate { func componentInputNumberDidValueChanged(inputNumber: ComponentInputNumber?) { guard let pdfView = self.pdfView else { return } guard let page = pdfView.currentSelectionPage() else { return } let pageBounds = page.bounds var value: CGFloat = 0 if let text = inputNumber?.properties.text { value = text.stringToCGFloat() } var rect = pdfView.selectionRect if inputNumber == sizeWidthInput { if syncChangeBounds { var scale: CGFloat = 0 if rect.size.width != 0 { scale = value / rect.size.width } rect.size.height *= scale } rect.size.width = value } else if inputNumber == sizeHeightInput { if syncChangeBounds { var scale: CGFloat = 0 if rect.size.height != 0 { scale = value / rect.size.height } rect.size.width *= scale } rect.size.height = value } else if inputNumber == pageLeftInput { rect.origin.x = value } else if inputNumber == pageRightInput { rect.size.width = pageBounds.size.width - rect.origin.x - value } else if inputNumber == pageTopInput { rect.size.height = pageBounds.size.height - rect.origin.y - value } else if inputNumber == pageBottomInput { rect.origin.y = value } pdfView.selectionRect = rect pdfView.setNeedsDisplayForVisiblePages() cropAutoOn = false cropSeparateOn = false reloadData() } }