123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- //
- // KMDesignSelect.swift
- // PDF Reader Pro
- //
- // Created by wanjun on 2023/2/22.
- //
- import Cocoa
- @objc protocol KMSelectPopButtonDelegate: NSObjectProtocol {
- @objc optional func km_controlTextDidEndEditing(_ obj: KMDesignSelect)
- @objc optional func km_controlTextDidChange(_ obj: KMDesignSelect)
- @objc optional func km_SelectPopoverWillShow(_ obj: KMDesignSelect)
- func km_comboBoxSelectionDidChange(_ obj: KMDesignSelect)
- }
- @objc enum SelectType : Int {
- case PopButton = 0
- case Combox
- }
- class KMSelectCell: NSTextFieldCell {
- var borderThickness: CGFloat = 1
- var offset: CGFloat = 0.0
- override func drawingRect(forBounds theRect: NSRect) -> NSRect {
- var newRect:NSRect = super.drawingRect(forBounds: theRect)
- let textSize:NSSize = self.cellSize(forBounds: theRect)
- // let heightDelta:CGFloat = newRect.size.height - textSize.height
- // if heightDelta > 0 {
- // newRect.size.height = textSize.height
- // newRect.origin.y += heightDelta * 0.5
- // } else {
- // newRect.size.height = textSize.height
- // newRect.origin.y += heightDelta
- // }
- let originY = ((self.controlView?.bounds.size.height)! - textSize.height) / 2
- newRect.size.height = textSize.height
- newRect.origin.y += originY
- newRect.origin.x += offset
- newRect.size.width = theRect.width - offset*2
- // newRect.fill()
- return newRect
- }
-
- override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
- // Area that covers the NSTextField itself. That is the total height minus our custom border size.
- let interiorFrame = NSRect(x: 0, y: 0, width: cellFrame.width, height: cellFrame.height - borderThickness)
- let path = NSBezierPath()
- path.lineWidth = borderThickness
- // Line width is at the center of the line.
- path.move(to: NSPoint(x: 0, y: cellFrame.height))
- path.line(to: NSPoint(x: cellFrame.width, y: cellFrame.height))
- path.line(to: NSPoint(x: cellFrame.width, y: 0))
- path.line(to: NSPoint(x: 0, y: 0))
- NSColor.clear.setStroke()
- path.stroke()
- // Pass in area minus the border thickness in the height
- drawInterior(withFrame: interiorFrame, in: controlView)
- }
- }
- @objcMembers class KMDesignSelect: NSViewController {
-
- @IBOutlet weak var mainBox: KMBox!
-
- @IBOutlet weak var selectBox: NSBox!
- @IBOutlet weak var textField: NSTextField!
- @IBOutlet weak var imageView: NSImageView!
- @IBOutlet weak var horizontalPadding_spacing: NSLayoutConstraint!
- @IBOutlet weak var itemSpacing_spacing: NSLayoutConstraint!
- @IBOutlet weak var imageViewWidth_spacing: NSLayoutConstraint!
- @IBOutlet weak var imageViewHeight_spacing: NSLayoutConstraint!
- var imageWidth: Float = 12.0 // 图片宽度
- var imageHeight: Float = 12.0 // 图片高度
- var horizontalPadding: Float = 8.0
- var itemSpacing: Float = 8.0
- var borderColor: NSColor = .clear// 边框颜色
- var borderColor_hov: NSColor = .clear// 边框颜色
- var borderColor_focus: NSColor = .clear// 边框颜色
- var borderColor_disabled: NSColor = .clear// 边框颜色
- var borderColor_errordef: NSColor = .clear// 边框颜色
- var borderColor_errorfocus: NSColor = .clear// 边框颜色
- var cornerRadius: Float = 0.0// 边框圆角
- var cornerRadius_hov: Float = 0.0// 边框圆角
- var cornerRadius_focus: Float = 0.0// 边框圆角
- var cornerRadius_disabled: Float = 0.0// 边框圆角
- var cornerRadius_errordef: Float = 0.0// 边框圆角
- var cornerRadius_errorfocus: Float = 0.0// 边框圆角
- var borderWidth: Float = 1.0// 边框宽度
- var borderWidth_hov: Float = 1.0// 边框宽度
- var borderWidth_focus: Float = 1.0// 边框宽度
- var borderWidth_disabled: Float = 1.0// 边框宽度
- var borderWidth_errordef: Float = 1.0// 边框宽度
- var borderWidth_errorfocus: Float = 1.0// 边框宽度
- var background: NSColor = .clear// 背景颜色
- var background_hov: NSColor = .clear// 背景颜色
- var background_focus: NSColor = .clear// 背景颜色
- var background_disabled: NSColor = .clear// 背景颜色
- var background_errordef: NSColor = .clear// 背景颜色
- var background_errorfocus: NSColor = .clear// 背景颜色
- var textColor: NSColor = .black // 内容颜色
- var textColor_hov: NSColor = .black // 内容颜色
- var textColor_focus: NSColor = .black // 内容颜色
- var textColor_disabled: NSColor = .black // 内容颜色
- var textColor_errordef: NSColor = .black // 内容颜色
- var textColor_errorfocus: NSColor = .black // 内容颜色
- var lineHeight: CGFloat = 20.0 // 默认 内容行高
- var lineHeight_hov: CGFloat = 20.0 // 默认 内容行高
- var lineHeight_focus: CGFloat = 20.0 // 默认 内容行高
- var lineHeight_disabled: CGFloat = 20.0 // 默认 内容行高
- var lineHeight_errordef: CGFloat = 20.0 // 默认 内容行高
- var lineHeight_errorfocus: CGFloat = 20.0 // 默认 内容行高
- var font: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
- var font_hov: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
- var font_focus: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
- var font_disabled: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
- var font_errordef: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
- var font_errorfocus: NSFont = NSFont.systemFont(ofSize: 14.0) // 内容字体
-
- var textbg_errorfocus: NSColor = .clear // 正在输入高亮
- var _image: NSImage = NSImage(named: "icon_btn_arrow_gray_down_s_norm_false")!
- var _stringValue: String = ""// 内容
- var _toolTip: String = "" // 提示文字
- // button 通用属性
- var action: Selector? // 点击事件
- var target: AnyObject? // 对象目标
- var _enabled: Bool = true // 是否可点击
- var _state: KMDesignTokenState = .Norm
- var canHover: Bool = true // 是否可悬浮
- var _isHidden: Bool = false // 是否隐藏
- var _editable: Bool = false // 是否允许编辑
- var _alignment: NSTextAlignment = .left //对齐
- var placeholderString: String = "" { // 预设文字
- didSet {
- self.textField.placeholderString = self.placeholderString
- }
- }
- var lineBreakMode: NSLineBreakMode = .byTruncatingTail //文字超出显示
-
- var buttonType: SelectType = .PopButton
- var items: [String] = []
- open weak var delete: KMSelectPopButtonDelegate?
- var _indexOfSelectedItem: Int = 0
- var _numberOfItems: Int = 0
- var disItems: [String] = []
- var isScrollPop = false
- var createFilePopover: NSPopover = NSPopover.init()
- var popoverBehavior: NSPopover.Behavior = .semitransient
- var popViewController: KMHomePopViewController?
- var popViewControllerBackground: NSColor?
- var popViewControllerTextColor: NSColor?
- var popViewControllerEnterFillColor: NSColor?
-
- init(withType type: SelectType) {
- super.init(nibName: "KMDesignSelect", bundle: nil)
- self.buttonType = type
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do view setup here.
-
- textField.isSelectable = false
-
- if (buttonType == .PopButton) {
- self.mainBox.contentView = selectBox
- textField.delegate = self
- self.select(bg: "select.m.bg.norm", text: "select.m.mac-text.act")
- self.select(bg: "select.m.bg.hov", text: "select.m.mac-text.act", state: .Hov)
- self.select(bg: "select.m.bg.focus", text: "select.m.mac-text.act", state: .Focus)
- self.select(bg: "select.m.bg.dis", text: "select.m.mac-text.dis", state: .Disabled)
- self.select(bg: "select.m.bg.error-def", text: "select.m.mac-text.act", state: .Error_def)
- self.select(bg: "select.m.bg.error-focus", text: "select.m.mac-text.act", textbg: "select.m.bg-text", state: .Error_focus)
- } else if (buttonType == .Combox) {
- self.mainBox.contentView = selectBox
- textField.delegate = self
-
- self.select(bg: "select.m.bg.norm", text: "select.m.mac-text.act")
- self.select(bg: "select.m.bg.hov", text: "select.m.mac-text.act", state: .Hov)
- self.select(bg: "select.m.bg.focus", text: "select.m.mac-text.act", state: .Focus)
- self.select(bg: "select.m.bg.dis", text: "select.m.mac-text.dis", state: .Disabled)
- self.select(bg: "select.m.bg.error-def", text: "select.m.mac-text.act", state: .Error_def)
- self.select(bg: "select.m.bg.error-focus", text: "select.m.mac-text.act", textbg: "select.m.bg-text", state: .Error_focus)
- }
-
- self.mainBox.canHover = true
- self.mainBox.canClick = true
- self.mainBox.downCallback = { [unowned self](downEntered, mouseBox, event) -> Void in
- if self.enabled {
- if downEntered {
- self.canHover = false
- self.mainBoxAction(mouseBox)
- }
- }
- }
- self.mainBox.moveCallback = { [unowned self](mouseEntered: Bool, mouseBox: KMBox) -> Void in
- if !self.createFilePopover.isShown && self.canHover && (self.state != .Disabled) {
- self.canHover = true
- if mouseEntered {
- self.state = .Hov
- } else {
- self.state = .Norm
- }
- self.updateUI()
- }
- }
-
- createFilePopover.delegate = self
- }
-
- // MARK: Get、Set
-
- var stringValue: String {
- get {
- return _stringValue
- }
- set {
- _stringValue = newValue
-
- let paragraphStyle = NSMutableParagraphStyle()
- if (state == .Norm) {
- paragraphStyle.lineSpacing = lineHeight
- } else if (state == .Hov) {
- paragraphStyle.lineSpacing = lineHeight_hov
- } else if (state == .Focus) {
- paragraphStyle.lineSpacing = lineHeight_focus
- } else if (state == .Disabled) {
- paragraphStyle.lineSpacing = lineHeight_disabled
- } else if (state == .Error_def) {
- paragraphStyle.lineSpacing = lineHeight_errordef
- } else if (state == .Error_focus) {
- paragraphStyle.lineSpacing = lineHeight_errorfocus
- }
- paragraphStyle.lineBreakMode = .byTruncatingTail
- paragraphStyle.alignment = alignment
- textField.attributedStringValue = NSAttributedString(string: _stringValue, attributes: [NSAttributedString.Key.paragraphStyle: paragraphStyle])
- }
- }
-
- var alert: Bool = false {
- didSet {
- updateUI()
- }
- }
-
- var enabled: Bool {
- get {
- return _enabled
- }
- set {
- _enabled = newValue
- if _enabled {
- _state = .Norm
- } else {
- _state = .Disabled
- }
- updateUI()
- }
- }
- var state: KMDesignTokenState {
- get {
- return _state
- }
- set {
- _state = newValue
- updateUI()
- }
- }
- var isHidden: Bool {
- get {
- return _isHidden
- }
- set {
- _isHidden = newValue
-
- self.view.isHidden = _isHidden
- }
- }
- var editable: Bool {
- get {
- return _editable
- }
- set {
- _editable = newValue
-
- textField.isEditable = _editable
- }
- }
-
- var indexOfSelectedItem: Int {
- get {
- return _indexOfSelectedItem
- }
- set {
- _indexOfSelectedItem = newValue
- }
- }
-
- var numberOfItems: Int {
- get {
- return items.count
- }
- }
- var image: NSImage {
- get {
- return _image
- }
- set {
- _image = newValue
-
- imageView.image = _image
- }
- }
-
- var toolTip: String {
- get {
- return _toolTip
- }
- set {
- _toolTip = newValue
- if _toolTip != "" {
- mainBox.toolTip = _toolTip
- }
- }
- }
-
- var alignment: NSTextAlignment {
- get {
- return _alignment
- }
- set {
- _alignment = newValue
-
- textField.alignment = alignment
- }
- }
-
- // MARK: Private Methods
- func updateUI() -> Void {
- if (state == .Norm) {
- selectBox.fillColor = background
- selectBox.borderWidth = CGFloat(borderWidth)
- selectBox.cornerRadius = CGFloat(cornerRadius)
- selectBox.borderColor = borderColor
- textField.textColor = textColor
- textField.font = font
- imageView.image = NSImage(named: "KMImageNameSelectNormal")
- } else if (state == .Hov) {
- selectBox.fillColor = background_hov
- selectBox.borderWidth = CGFloat(borderWidth_hov)
- selectBox.cornerRadius = CGFloat(cornerRadius_hov)
- selectBox.borderColor = borderColor_hov
- textField.textColor = textColor_hov
- textField.font = font_hov
- imageView.image = NSImage(named: "KMImageNameSelectHover")
- } else if (state == .Focus) {
- selectBox.fillColor = background_focus
- selectBox.borderWidth = CGFloat(borderWidth_focus)
- selectBox.cornerRadius = CGFloat(cornerRadius_focus)
- selectBox.borderColor = borderColor_focus
- textField.textColor = textColor_focus
- textField.font = font_focus
- imageView.image = NSImage(named: "KMImageNameSelectFocus")
- } else if (state == .Disabled) {
- selectBox.fillColor = background_disabled
- selectBox.borderWidth = CGFloat(borderWidth_disabled)
- selectBox.cornerRadius = CGFloat(cornerRadius_disabled)
- selectBox.borderColor = borderColor_disabled
- textField.textColor = textColor_disabled
- textField.font = font_disabled
- imageView.image = NSImage(named: "KMImageNameSelectDisable")
- } else if (state == .Error_def) {
- selectBox.fillColor = background_errordef
- selectBox.borderWidth = CGFloat(borderWidth_errordef)
- selectBox.cornerRadius = CGFloat(cornerRadius_errordef)
- selectBox.borderColor = borderColor_errordef
- textField.textColor = textColor_errordef
- textField.font = font_errordef
- imageView.image = NSImage(named: "KMImageNameSelectNormal")
- } else if (state == .Error_focus) {
- selectBox.fillColor = background_errorfocus
- selectBox.borderWidth = CGFloat(borderWidth_errorfocus)
- selectBox.cornerRadius = CGFloat(cornerRadius_errorfocus)
- selectBox.borderColor = borderColor_errorfocus
- textField.textColor = textColor_errorfocus
- textField.font = font_errorfocus
- imageView.image = NSImage(named: "KMImageNameSelectNormal")
- }
-
- if alert == true {
- selectBox.borderColor = NSColor.km_init(hex: "#F3465B")
- } else {
- selectBox.borderColor = selectBox.borderColor
- }
-
- imageViewWidth_spacing.constant = CGFloat(imageWidth)
- imageViewHeight_spacing.constant = CGFloat(imageHeight)
- horizontalPadding_spacing.constant = CGFloat(horizontalPadding)
- itemSpacing_spacing.constant = CGFloat(itemSpacing)
- textField.isEditable = editable
- // textField.placeholderString = placeholderString
- textField.lineBreakMode = lineBreakMode
-
- popViewController?.updateUI()
- }
-
- func removeAllItems() {
- items = []
- }
-
- func addItems(withObjectValues objects: [String]) {
- items = objects
- }
-
- func selectItem(at index: Int) {
- if items.count > 0 && index < items.count {
- stringValue = items[index]
- self.indexOfSelectedItem = index
- }
- }
-
- // MARK: Action
-
- func mainBoxAction(_ sender: Any) -> Void {
- self.delete?.km_SelectPopoverWillShow?(self)
-
- if createFilePopover.isShown {
- createFilePopover.close()
- } else {
- var vc: KMHomePopViewController?
- if (self.isScrollPop) {
- vc = KMScrollPopViewController()
- } else {
- vc = KMHomePopViewController()
- }
-
- if (self.popViewControllerBackground != nil) {
- vc?.background = self.popViewControllerBackground!
- }
-
- if self.popViewControllerBackground != nil {
- vc?.textColor = self.popViewControllerTextColor!
- }
-
- if self.popViewControllerBackground != nil {
- vc?.enterFillColor = self.popViewControllerEnterFillColor!
- }
-
- let _ = vc?.initWithPopViewDataArr(items)
- self.popViewController = vc
-
- createFilePopover.contentViewController = vc
- if (self.stringValue.isEmpty == false) {
- vc?.selectedItems = [self.stringValue]
- }
- createFilePopover.animates = true
- createFilePopover.behavior = self.popoverBehavior
- createFilePopover.setValue(true, forKey: "shouldHideAnchor")
- createFilePopover.show(relativeTo: CGRect(x: view.bounds.origin.x, y: 10, width: view.bounds.size.width, height: view.bounds.size.height), of: view, preferredEdge: .minY)
- var width = mainBox.frame.width
- for i in items {
- let w = i.getTextRectSize(font: .systemFont(ofSize: 14.0), size: CGSize(width: CGFloat(MAXFLOAT), height: 32.0)).width+12*2
- if width < w {
- width = w
- }
- }
-
- vc?.customBoxWidthLayoutConstraint.constant = width
- vc?.downCallback = { [unowned self] (downEntered: Bool, count: String) -> Void in
- if downEntered {
- self.stringValue = count
-
- let current = self.items.firstIndex(of: count) ?? 0
- self.indexOfSelectedItem = current
- self.delete?.km_comboBoxSelectionDidChange(self)
-
- self.updateUI()
-
- self.createFilePopover.close()
- }
- }
- }
- }
- }
- extension KMDesignSelect: NSTextFieldDelegate {
- func controlTextDidChange(_ obj: Notification) {
- let textfield = obj.object as! NSTextField
- self.stringValue = textfield.stringValue
- self.delete?.km_controlTextDidChange?(self)
- }
-
- func controlTextDidEndEditing(_ obj: Notification) {
- let textfield = obj.object as! NSTextField
-
- self.stringValue = textfield.stringValue
-
- self.delete?.km_controlTextDidEndEditing?(self)
- }
- }
- extension KMDesignSelect: NSPopoverDelegate {
- func popoverWillShow(_ notification: Notification) {
- let popover = notification.object as! NSPopover
- if (createFilePopover == popover) {
- self.state = .Focus
- self.canHover = false
-
- let vc = createFilePopover.contentViewController! as! KMHomePopViewController
- vc.disItems = disItems
- }
- }
-
- func popoverWillClose(_ notification: Notification) {
- let popover = notification.object as! NSPopover
- if (createFilePopover == popover) {
- self.state = .Norm
- self.canHover = true
- }
- }
- }
|