// // KMReadModelView.swift // PDF Reader Pro // // Created by lizhe on 2023/3/23. // import Cocoa enum KMReadModelViewScaleType: String, CaseIterable { case fitWidth = "Fit" case actualSize = "Actual Size" case autoSize = "Auto" case _10 = "10%" case _25 = "25%" case _50 = "50%" case _100 = "100%" case _150 = "150%" case _200 = "200%" case _400 = "400%" case _800 = "800%" static func allValues() -> [String] { var array: [String] = [] for key in KMReadModelViewScaleType.allCases { array.append(NSLocalizedString(key.rawValue, comment: "")) } return array } static func typeOfRawValue(value: String) -> KMReadModelViewScaleType { var type: KMReadModelViewScaleType switch value { case NSLocalizedString(KMReadModelViewScaleType.fitWidth.rawValue, comment: ""): type = .fitWidth case NSLocalizedString(KMReadModelViewScaleType.actualSize.rawValue, comment: ""): type = .actualSize case NSLocalizedString(KMReadModelViewScaleType.autoSize.rawValue, comment: ""): type = .autoSize case KMReadModelViewScaleType._10.rawValue: type = ._10 case KMReadModelViewScaleType._25.rawValue: type = ._25 case KMReadModelViewScaleType._50.rawValue: type = ._50 case KMReadModelViewScaleType._100.rawValue: type = ._100 case KMReadModelViewScaleType._150.rawValue: type = ._150 case KMReadModelViewScaleType._200.rawValue: type = ._200 case KMReadModelViewScaleType._400.rawValue: type = ._400 case KMReadModelViewScaleType._800.rawValue: type = ._800 default: type = .autoSize } return type } } protocol KMReadModelViewDelegate: NSObject { func firstPageButtonDidChange(view: KMReadModelView, sender: Any) func beforePageButtonDidChange(view: KMReadModelView, sender: Any) func afterPageButtonDidChange(view: KMReadModelView, sender: Any) func lastPageButtonDidChange(view: KMReadModelView, sender: Any) func currentPageButtonDidChange(view: KMReadModelView, sender: Any, pageIndex: Int) func scaleDidChange(view: KMReadModelView, sender: Any, type: KMReadModelViewScaleType) func cancelReadModel(view: KMReadModelView, sender: Any) func readModelViewWidthChange(view: KMReadModelView, width: CGFloat) } class KMReadModelView: KMBaseXibView { @IBOutlet weak var firstPageView: NSView! @IBOutlet weak var beforePageView: NSView! @IBOutlet weak var currentPageView: NSView! @IBOutlet weak var totalPageView: NSTextField! @IBOutlet weak var afterPageView: NSView! @IBOutlet weak var lastPageView: NSView! @IBOutlet weak var totalLable: NSTextField! @IBOutlet weak var zoomView: NSView! @IBOutlet weak var backgroundContentView: NSView! @IBOutlet weak var currentPageTextField: NSTextField! @IBOutlet weak var currentPageBackgroundView: NSView! @IBOutlet weak var contentBox: KMBox! @IBOutlet weak var contentViewWidthConstraint: NSLayoutConstraint! @IBOutlet weak var currentContentViewWidthConstraint: NSLayoutConstraint! @IBOutlet weak var totalPageCountWidthConstraint: NSLayoutConstraint! @IBOutlet weak var scaleWidthConstraint: NSLayoutConstraint! var firstPageButton: KMDesignButton! var beforePageButton: KMDesignButton! var afterPageButton: KMDesignButton! var lastPageButton: KMDesignButton! var zoomButton: KMDesignSelect! var timer: Timer? weak var delegate: KMReadModelViewDelegate? var currentPageIndex: Int? { didSet { self.currentPageTextField.stringValue = (currentPageIndex! + 1).description self.updateButtonState() self.updateUI() } } var totalPagesCount: Int? { didSet { self.totalLable.stringValue = totalPagesCount?.description ?? "1" self.updateButtonState() self.updateUI() } } var scaleType: KMReadModelViewScaleType? { didSet { self.zoomButton.selectItem(at: KMReadModelViewScaleType.allValues().firstIndex(of: scaleType!.rawValue)!) } } deinit { self.endTimer() } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Drawing code here. } override func setup() { self.backgroundColor(NSColor.km_init(hex: "#FFFFFF")) self.shadow = NSShadow() self.wantsLayer = true self.layer?.shadowColor = NSColor.km_init(hex: "#000000", alpha: 0.16).cgColor self.layer?.shadowOffset = CGSize(width: 0, height: -2) self.layer?.shadowRadius = 8 self.layer?.shadowOpacity = 1 self.layer?.cornerRadius = 4 firstPageButton = KMDesignButton(withType: .Image) self.firstPageView.addSubview(firstPageButton.view) firstPageButton.view.frame = CGRect(x: 0, y: 0, width: 24, height: 24) firstPageButton.target = self firstPageButton.image = NSImage(named: "icon_btn_readModel_first")! firstPageButton.image_disabled = NSImage(named: "icon_btn_readModel_first_dis")! firstPageButton.action = #selector(firstPageButtonAction) firstPageButton.pagination() firstPageButton.borderWidth = 1 firstPageButton.borderColor = NSColor.km_init(hex: "#DFE1E5") firstPageButton.updateUI() beforePageButton = KMDesignButton(withType: .Image) self.beforePageView.addSubview(beforePageButton.view) beforePageButton.view.frame = CGRect(x: 0, y: 0, width: 24, height: 24) beforePageButton.target = self beforePageButton.image = NSImage(named: "icon_btn_readModel_before")! beforePageButton.image_disabled = NSImage(named: "icon_btn_readModel_before_dis")! beforePageButton.action = #selector(beforePageButtonAction) beforePageButton.pagination() beforePageButton.borderWidth = 1 beforePageButton.borderColor = NSColor.km_init(hex: "#DFE1E5") beforePageButton.updateUI() afterPageButton = KMDesignButton(withType: .Image) self.afterPageView.addSubview(afterPageButton.view) afterPageButton.view.frame = CGRect(x: 0, y: 0, width: 24, height: 24) afterPageButton.target = self afterPageButton.image = NSImage(named: "icon_btn_readModel_after")! afterPageButton.image_disabled = NSImage(named: "icon_btn_readModel_after_dis")! afterPageButton.action = #selector(afterPageButtonAction) afterPageButton.pagination() afterPageButton.borderWidth = 1 afterPageButton.borderColor = NSColor.km_init(hex: "#DFE1E5") afterPageButton.updateUI() lastPageButton = KMDesignButton(withType: .Image) self.lastPageView.addSubview(lastPageButton.view) lastPageButton.view.frame = CGRect(x: 0, y: 0, width: 24, height: 24) lastPageButton.target = self lastPageButton.image = NSImage(named: "icon_btn_readModel_last")! lastPageButton.image_disabled = NSImage(named: "icon_btn_readModel_last_dis")! lastPageButton.action = #selector(lastPageButtonAction) lastPageButton.pagination() lastPageButton.borderWidth = 1 lastPageButton.borderColor = NSColor.km_init(hex: "#DFE1E5") lastPageButton.updateUI() zoomButton = KMDesignSelect(withType: .PopButton) self.zoomView.addSubview(zoomButton.view) zoomButton.view.frame = CGRect(x: 0, y: 0, width: 65, height: 24) zoomButton.selectItem(at: 0) zoomButton.delete = self zoomButton.font = NSFont.SFProTextRegularFont(12.0) zoomButton.font_hov = NSFont.SFProTextRegularFont(12.0) zoomButton.font_focus = NSFont.SFProTextRegularFont(12.0) zoomButton.font_disabled = NSFont.SFProTextRegularFont(12.0) zoomButton.borderWidth = 0 zoomButton.updateUI() currentPageBackgroundView.border(NSColor.km_init(hex: "#DFE1E5"), 1, 4) currentPageTextField.textColor = NSColor.km_init(hex: "#252629") currentPageTextField.font = NSFont.SFProTextRegularFont(12.0) currentPageTextField.delegate = self totalLable.textColor = NSColor.km_init(hex: "#252629") totalLable.font = NSFont.SFProTextRegularFont(12.0) contentBox.moveCallback = { [unowned self] (enter, box) in if enter { self.inReadModelView() } else { self.beginTimer() } } } //刷新界面UI 和 数据 override func reloadData() { } override func updateLanguage() { zoomButton.removeAllItems() zoomButton.addItems(withObjectValues: KMReadModelViewScaleType.allValues()) } override func updateUI() { let width = self.fetchWidth() // if self.contentViewWidthConstraint.constant != width { self.delegate?.readModelViewWidthChange(view: self, width: width) // } self.contentViewWidthConstraint.constant = width self.currentContentViewWidthConstraint.constant = self.fetchCurrentPageIndexWidth(string: self.currentPageTextField.stringValue as NSString) self.totalPageCountWidthConstraint.constant = self.fetchTotalPageIndexWidth(string: self.totalPageView.stringValue as NSString) self.scaleWidthConstraint.constant = self.fetchScaleWidth(string: self.zoomButton.stringValue as NSString) zoomButton.view.frame = self.zoomView.bounds } override func resetData() { } override func addNotification() { } override func removeNotification() { } } //MARK: data extension KMReadModelView { func fetchWidth() -> CGFloat { var width = 16.0 width += self.firstPageView.frame.size.width width += 8.0 width += self.beforePageView.frame.size.width width += 8.0 width += self.fetchCurrentPageIndexWidth(string: self.currentPageTextField.stringValue as NSString) width += 8.0 width += 4.0 width += 8.0 width += self.fetchTotalPageIndexWidth(string: self.totalLable.stringValue as NSString) width += 8.0 width += self.afterPageView.frame.size.width width += 8.0 width += self.lastPageView.frame.size.width width += 16.0 width += self.fetchScaleWidth(string: self.zoomButton.stringValue as NSString) width += 16.0 return width } func fetchCurrentPageIndexWidth(string: NSString) -> CGFloat { var width = 28.0 let attributes = [NSAttributedString.Key.font : NSFont.SFProTextRegularFont(12.0)] width += string.boundingRect(with: CGSize(width: 100, height: 24), attributes: attributes).size.width width = max(width, 48) return width } func fetchTotalPageIndexWidth(string: NSString) -> CGFloat { var width = 0.0 let attributes = [NSAttributedString.Key.font : NSFont.SFProTextRegularFont(12.0)] width += string.boundingRect(with: CGSize(width: 100, height: 24), attributes: attributes).size.width width = max(width, 30) return width } func fetchScaleWidth(string: NSString) -> CGFloat { var width = 40.0 let attributes = [NSAttributedString.Key.font : NSFont.SFProTextRegularFont(12.0)] width += string.boundingRect(with: CGSize(width: 100, height: 24), attributes: attributes).size.width width = max(width, 80) return width } } //MARK: Mouse extension KMReadModelView { override func mouseDown(with event: NSEvent) { KMPrint("mouseDown") } override func mouseUp(with event: NSEvent) { KMPrint("mouseUp") } override func mouseMoved(with event: NSEvent) { KMPrint("mouseMoved") } override func mouseEntered(with event: NSEvent) { KMPrint("mouseEntered") } override func mouseExited(with event: NSEvent) { KMPrint("mouseExited") } } //MARK: PopButton extension KMReadModelView: KMSelectPopButtonDelegate { func km_comboBoxSelectionDidChange(_ obj: KMDesignSelect) { KMPrint("km_comboBoxSelectionDidChange") self.updateUI() self.delegate?.scaleDidChange(view: self, sender: obj, type: KMReadModelViewScaleType(rawValue: KMReadModelViewScaleType.allValues()[obj.indexOfSelectedItem]) ?? .autoSize) } } //MARK: extension KMReadModelView: NSTextFieldDelegate { func controlTextDidEndEditing(_ obj: Notification) { let string = Int(self.currentPageTextField.stringValue)?.description ?? "1" currentPageTextField.stringValue = string self.delegate?.currentPageButtonDidChange(view: self, sender: obj, pageIndex: Int(string) ?? 1) } } //MARK: In out extension KMReadModelView { @objc fileprivate func inReadModelView() { self.endTimer() self.updateUI() NSAnimationContext.runAnimationGroup { NSAnimationContext in self.animator().alphaValue = 1 } } @objc fileprivate func outReadModelView() { NSAnimationContext.runAnimationGroup { NSAnimationContext in self.animator().alphaValue = 0 self.endTimer() } } func resetTimer() { self.endTimer() self.beginTimer() } func beginTimer() { if self.timer != nil { self.endTimer() } self.inReadModelView() self.timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(outReadModelView), userInfo: nil, repeats: true) } func endTimer() { self.timer?.invalidate() self.timer = nil } } //MARK: Action extension KMReadModelView { @IBAction func escButtonAction(_ sender: Any) { KMPrint("read model escButtonAction") self.delegate?.cancelReadModel(view: self, sender: sender) } @objc func firstPageButtonAction(sender: Any) { KMPrint("firstPageButtonAction") if self.canFirstPageButtonAction() { self.delegate?.firstPageButtonDidChange(view: self, sender: sender) } self.updateButtonState() } @objc func beforePageButtonAction(sender: Any) { KMPrint("beforePageButtonAction") if self.canBeforePageButtonAction() { self.delegate?.beforePageButtonDidChange(view: self, sender: sender) } self.updateButtonState() } @objc func afterPageButtonAction(sender: Any) { KMPrint("afterPageButtonAction") if self.canAfterPageButtonAction() { self.delegate?.afterPageButtonDidChange(view: self, sender: sender) } self.updateButtonState() } @objc func lastPageButtonAction(sender: Any) { KMPrint("lastPageButtonAction") if self.canLastPageButtonAction() { self.delegate?.lastPageButtonDidChange(view: self, sender: sender) } self.updateButtonState() } func canFirstPageButtonAction() -> Bool { guard let pageIndex = self.currentPageIndex else { return false } if pageIndex != 0 { return true } else { return false } } func canBeforePageButtonAction() -> Bool { guard let pageIndex = self.currentPageIndex else { return false } if pageIndex != 0 { return true } else { return false } } func canAfterPageButtonAction() -> Bool { guard let totalCount = self.totalPagesCount else { return false } guard let pageIndex = self.currentPageIndex else { return false } if pageIndex < totalCount - 1 { return true } else { return false } } func canLastPageButtonAction() -> Bool { guard let totalCount = self.totalPagesCount else { return false } guard let pageIndex = self.currentPageIndex else { return false } if pageIndex != totalCount - 1 { return true } else { return false } } func updateButtonState() { self.firstPageButton.enabled = self.canFirstPageButtonAction() self.beforePageButton.enabled = self.canBeforePageButtonAction() self.afterPageButton.enabled = self.canAfterPageButtonAction() self.lastPageButton.enabled = self.canLastPageButtonAction() } }