// // KMHomePopViewController.swift // PDF Reader Pro // // Created by wanjun on 2022/10/17. // import Cocoa typealias popCellViewDownCallback = (_ downEntered: Bool, _ count: String) -> Void typealias popCellViewWillShow = (_ cellView: KMBox, _ index: Int) -> Void @objcMembers class KMHomePopViewController: NSViewController { @IBOutlet weak var customBox: NSBox! @IBOutlet weak var customBoxWidthLayoutConstraint: NSLayoutConstraint! @IBOutlet weak var customBoxHeightLayoutConstraint: NSLayoutConstraint! var downCallback: popCellViewDownCallback? var viewWillShow: popCellViewWillShow? var popCellViewDownString: String? var popCellCount: Int? var dataArr: [String]? var KMHorizontalLine: String = "KMHorizontalLine" var enterFillColor : NSColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.hov") var textColor : NSColor = .black // 背景颜色 var background : NSColor = .white // 背景颜色 var background_hov : NSColor = .clear // 背景颜色 var background_sel : NSColor = .clear // 背景颜色 var background_disabled : NSColor = .clear // 背景颜色 var cornerRadius : Float = 0.0 // 边框圆角 var cornerRadius_hov : Float = 0.0 // 边框圆角 var cornerRadius_sel : Float = 0.0 // 边框圆角 var cornerRadius_disabled : Float = 0.0 // 边框圆角 var lineHeight : CGFloat = 20.0 // 默认 内容行高 var lineHeight_hov : CGFloat = 20.0 // 默认 内容行高 var lineHeight_sel : CGFloat = 20.0 // 默认 内容行高 var lineHeight_disabled : CGFloat = 20.0 // 默认 内容行高 var font : NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体 var font_hov : NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体 var font_sel : NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体 var font_disabled : NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体 var _state: KMDesignTokenState = .Norm var enabled: Bool = true // 是否可点击 var canHover: Bool = true // 是否可悬浮 var disItems: [String] = [] var selectedItems: [String] = [] var showVerticalScroller: Bool = false func initWithPopViewDataArr(_ popViewDataArr: [String]) -> Self { // self.dataArr = popViewDataArr.reverseObjectEnumerator().allObjects as NSArray self.dataArr = popViewDataArr.reversed() return self } override func viewDidLoad() { super.viewDidLoad() customBox.fillColor = background//NSColor.km_init(hex: "#FFFFFF") // self.updateUI() } override func viewDidAppear() { super.viewDidAppear() self.updateUI() } // MARK: Private func updateUI() { customBox.fillColor = background var widthMax: Float = 0; let subViews: [NSView] = self.customBox.contentView!.subviews for subView in subViews { subView.removeFromSuperview() } for string in self.dataArr ?? [] { if !(string as AnyObject).isEqual(to: KMHorizontalLine) { let width = self.cellContentAdaptiveWidth(string) if widthMax < width { widthMax = width } } } var formTopFloat: Float = 4.0 // for i in (0.. Void in // if mouseEntered { // if #available(macOS 10.14, *) { // box.fillColor = NSColor.controlAccentColor // boxLabel.textColor = NSColor.white // } else { // box.fillColor = NSColor.init(red: 71/255.0, green: 126/255.0, blue: 222/255.0, alpha: 1.0) // boxLabel.textColor = NSColor.white // } // } else { // box.fillColor = NSColor.clear // boxLabel.textColor = NSColor.labelColor // } // } // box.downCallback = {(downEntered: Bool, mouseBox: KMBox) -> Void in // if downEntered { // if let callback = self.downCallback { // callback(true, stringValue) // } // } // } // } func createPopViewCellLabelWithFrame(_ mas_top: Float, stringValue: String) { var isDisabled = false if disItems.contains(stringValue) { isDisabled = true } var isSelected = false if (isDisabled == false && self.selectedItems.contains(stringValue)) { isSelected = true } let box: KMBox = KMBox(frame: NSZeroRect) box.boxType = .custom box.borderWidth = 0.0 box.contentViewMargins = NSMakeSize(0, 0) box.cornerRadius = 4.0 customBox.contentView?.addSubview(box) box.mas_makeConstraints { (make) in make?.left.equalTo()(4.0) make?.right.equalTo()(-4.0) make?.height.equalTo()(32.0) make?.top.equalTo()(customBox.mas_top)?.offset()(CGFloat(mas_top)) } // let dropdownVC = KMDesignDropdown.init(nibName: "KMDesignDropdown", bundle: nil) // box.contentView = dropdownVC.view // dropdownVC.dropdown(bg: "dropdown.m.bg.norm", text: "dropdown.m.mac-text.def") // dropdownVC.dropdown(bg: "dropdown.m.bg.hov", text: "dropdown.m.mac-text.def", state: .Hov) // dropdownVC.dropdown(bg: "dropdown.m.bg.sel", text: "dropdown.m.mac-text.sel", state: .Sel) // dropdownVC.dropdown(bg: "dropdown.m.bg.dis", text: "dropdown.m.mac-text.dis", state: .Disabled) // dropdownVC.stringValue = str let boxLabel: NSTextField = NSTextField.init() boxLabel.isEditable = false boxLabel.isBordered = false boxLabel.stringValue = stringValue boxLabel.font = NSFont.systemFont(ofSize: 14.0) boxLabel.translatesAutoresizingMaskIntoConstraints = false boxLabel.backgroundColor = NSColor.clear boxLabel.textColor = textColor//NSColor.km_init(hex: "#252629") box.contentView?.addSubview(boxLabel) boxLabel.mas_makeConstraints { (make) in make?.centerY.equalTo()(0.0) make?.left.equalTo()(8.0) } let textTypography = KMDesignToken.shared.typography(withToken: "dropdown.m.mac-text.def") var fontFamily: String = textTypography.fontFamily let fontWeight: String = textTypography.fontWeight if fontFamily.contains(" ") { fontFamily = fontFamily.replacingOccurrences(of: " ", with: "") } if fontWeight != "" { fontFamily = String(format: "%@-%@", fontFamily, fontWeight) } boxLabel.font = NSFont(name: fontFamily, size: textTypography.fontSize.stringToCGFloat()) ?? NSFont.systemFont(ofSize: textTypography.fontSize.stringToCGFloat()) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = textTypography.lineHeight.stringToCGFloat() boxLabel.attributedStringValue = NSAttributedString(string: stringValue, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) box.moveCallback = {(mouseEntered: Bool, mouseBox: KMBox) -> Void in if !isDisabled { if isSelected { // 选中没有 hover 效果 return } if mouseEntered { mouseBox.fillColor = self.enterFillColor } else { mouseBox.fillColor = NSColor.clear } } } box.downCallback = {(downEntered, mouseBox, event) -> Void in if !isDisabled { if downEntered { mouseBox.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.sel") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.sel") if let callback = self.downCallback { callback(true, stringValue) } } else { mouseBox.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.norm") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.def") } } } if isDisabled { box.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.dis") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.dis") } else if (isSelected) { box.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.sel") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.sel") } let idx = self.dataArr?.index(of: stringValue) ?? 0 self.viewWillShow?(box, idx) } func cellContentAdaptiveWidth(_ content: String) -> Float { if content.isEmpty { return 0 } let attributes = [NSAttributedString.Key.font : NSFont.systemFont(ofSize: 14.0)] let rect : CGRect = content.boundingRect(with: CGSize(width: 0, height: 18),options: .usesLineFragmentOrigin, attributes: attributes,context:nil) return Float(rect.size.width) } func changePopViewCellData(_ count: Int, content: String) { let boxArray: Array = customBox.contentView!.subviews for subView in boxArray { subView.removeFromSuperview() } var dataMutableArr: [String] = Array((dataArr?.reversed())!) dataMutableArr[count] = content dataArr = Array(dataMutableArr.reversed()) self.updateUI() } // MARK: - Init Views fileprivate func initBoxLabel() -> NSTextField { let label = NSTextField.init() label.isEditable = false label.isBordered = false label.font = NSFont.systemFont(ofSize: 14.0) label.translatesAutoresizingMaskIntoConstraints = false label.backgroundColor = NSColor.clear label.textColor = NSColor.km_init(hex: "#252629") return label } } class KMScrollPopViewController: KMHomePopViewController { private var scrollView = NSScrollView() private var contentView = NSView() private var currentItemPosition: NSPoint = .zero convenience init() { self.init(nibName: "KMHomePopViewController", bundle: nil) } override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(self.scrollView) self.scrollView.documentView = self.contentView // self.scrollView.documentView?.backgroundColor(NSColor.km_init(hex: "#FFFFFF")) // customBox.fillColor = NSColor.km_init(hex: "#FFFFFF") self.scrollView.documentView?.backgroundColor(self.background) self.scrollView.hasVerticalScroller = self.showVerticalScroller self.scrollView.borderType = .noBorder self.scrollView.drawsBackground = false } override func viewDidAppear() { super.viewDidAppear() DispatchQueue.main.async { let contentView = self.scrollView.contentView let pageH = NSHeight(self.scrollView.bounds) // KMPrint(NSHeight(self.contentView.bounds)) // KMPrint(pageH) // KMPrint(self.currentItemPosition) var numberPages: Int = 0 var currentPage: Int = 0 var scrollY: CGFloat = 0 if (pageH > 0) { numberPages = Int(NSHeight(self.contentView.bounds) / pageH) + 1 currentPage = Int((self.currentItemPosition.y + 32 + 4 * 2) / pageH) // KMPrint(numberPages) // KMPrint(currentPage) // let _currentPage = numberPages - currentPage - 1 // KMPrint(_currentPage) if (currentPage == (numberPages - 1)) { scrollY = 0 } else { scrollY = NSHeight(self.contentView.bounds) - pageH * CGFloat(currentPage+1) } } // KMPrint(scrollY) contentView.scroll(to: NSPoint(x: 0, y: scrollY)) } } override func viewDidLayout() { super.viewDidLayout() self.scrollView.frame = NSMakeRect(0, 0, NSWidth(self.view.frame), NSHeight(self.view.window!.frame)) self.contentView.frame = NSMakeRect(0, 0, NSWidth(self.customBox.frame), NSHeight(self.customBox.frame)+30) // self.contentView.frame = self.customBox.bounds } override func updateUI() { var widthMax: Float = 0 for subView in self.contentView.subviews { subView.removeFromSuperview() } for string in self.dataArr ?? [] { if ((string as AnyObject).isEqual(to: KMHorizontalLine)) { continue } let width = self.cellContentAdaptiveWidth(string) if (widthMax < width) { widthMax = width } } var formTopFloat: Float = 4.0 for string in dataArr?.reversed() ?? [] { if (string as AnyObject).isEqual(to: KMHorizontalLine) { self.createHonrizontalLineWithFrame(CGRect(x: 12.0, y: CGFloat(formTopFloat), width: CGFloat(widthMax)+23, height: 11)) formTopFloat += 11 } else { self.popCellViewDownString = string self.createPopViewCellLabelWithFrame(formTopFloat, stringValue: string) formTopFloat += 32 } } self.customBoxWidthLayoutConstraint.constant = CGFloat(widthMax+47) self.customBoxHeightLayoutConstraint.constant = CGFloat(formTopFloat+4.0) } override func createHonrizontalLineWithFrame(_ frame: CGRect) { let box: NSBox = NSBox.init(frame: frame) box.boxType = .custom box.borderWidth = 0.0 box.contentViewMargins = NSMakeSize(0, 0) self.contentView.addSubview(box) let lineBox = NSBox.init(frame: CGRect(x: 0, y: 6, width: frame.width, height: 1)) lineBox.boxType = .separator box.addSubview(lineBox) } override func createPopViewCellLabelWithFrame(_ mas_top: Float, stringValue: String) { var isDisabled = false if (self.disItems.contains(stringValue)) { isDisabled = true } var isSelected = false if (isDisabled == false && self.selectedItems.contains(stringValue)) { isSelected = true } if (isSelected && self.selectedItems.first == stringValue) { self.currentItemPosition = NSPoint(x: 0, y: Int(mas_top)) } let box: KMBox = KMBox(frame: NSZeroRect) box.boxType = .custom box.borderWidth = 0.0 box.contentViewMargins = NSMakeSize(0, 0) box.cornerRadius = 4.0 self.contentView.addSubview(box) box.mas_makeConstraints { (make) in make?.left.equalTo()(4.0) make?.right.equalTo()(-4.0) make?.height.equalTo()(32.0) make?.top.equalTo()(self.customBox.mas_top)?.offset()(CGFloat(mas_top)) } let boxLabel = self.initBoxLabel() boxLabel.stringValue = stringValue box.contentView?.addSubview(boxLabel) boxLabel.mas_makeConstraints { (make) in make?.centerY.equalTo()(0.0) make?.left.equalTo()(8.0) make?.right.mas_equalTo()(0) } let textTypography = KMDesignToken.shared.typography(withToken: "dropdown.m.mac-text.def") var fontFamily: String = textTypography.fontFamily let fontWeight: String = textTypography.fontWeight if (fontFamily.contains(" ")) { fontFamily = fontFamily.replacingOccurrences(of: " ", with: "") } if (fontWeight != "") { fontFamily = String(format: "%@-%@", fontFamily, fontWeight) } if NSFont(name: stringValue, size: 12) != nil { fontFamily = stringValue } else { debugPrint("不支持字体" + stringValue) } if stringValue == "Al Tarikh" || stringValue == "Corsiva Hebrew" || stringValue == "DIN Condensed" || stringValue == "Damascus" { boxLabel.font = NSFont.systemFont(ofSize: 14) boxLabel.stringValue = stringValue } else { boxLabel.font = NSFont(name: fontFamily, size: textTypography.fontSize.stringToCGFloat()) ?? NSFont.systemFont(ofSize: textTypography.fontSize.stringToCGFloat()) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = textTypography.lineHeight.stringToCGFloat() boxLabel.attributedStringValue = NSAttributedString(string: stringValue, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle]) } if (isDisabled) { box.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.dis") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.dis") } else if (isSelected) { box.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.sel") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.sel") } else { boxLabel.textColor = self.textColor } box.moveCallback = { mouseEntered, mouseBox in if (isDisabled) { return } if (isSelected) { // 选中没有 hover 效果 return } // if (mouseEntered) { // mouseBox.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.hov") // } else { // mouseBox.fillColor = NSColor.clear // } if mouseEntered { mouseBox.fillColor = self.enterFillColor } else { mouseBox.fillColor = NSColor.clear } } box.downCallback = { [unowned self] downEntered, mouseBox, _ in if (isDisabled) { return } if (downEntered) { mouseBox.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.sel") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.sel") guard let callback = self.downCallback else { return } callback(true, stringValue) } else { mouseBox.fillColor = KMDesignToken.shared.fill(withToken: "dropdown.m.bg.norm") boxLabel.textColor = KMDesignToken.shared.fill(withToken: "dropdown.m.mac-text.def") } } let idx = self.dataArr?.index(of: stringValue) ?? 0 self.viewWillShow?(box, idx) } }